pax_global_header00006660000000000000000000000064135744240030014514gustar00rootroot0000000000000052 comment=300fa3fb49b52c751af24a6cc06fc9f7d84b4049 nemo-4.4.2/000077500000000000000000000000001357442400300124615ustar00rootroot00000000000000nemo-4.4.2/.circleci/000077500000000000000000000000001357442400300143145ustar00rootroot00000000000000nemo-4.4.2/.circleci/config.yml000066400000000000000000000043001357442400300163010ustar00rootroot00000000000000version: 2.0 shared: &shared steps: - checkout - run: name: Prepare environment command: apt-get update - run: name: Install dependencies command: | wget https://github.com/linuxmint/xapps/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O xapps.tar.gz wget https://github.com/linuxmint/cinnamon-desktop/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O cinnamon-desktop.tar.gz wget https://github.com/linuxmint/cinnamon-translations/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O cinnamon-translations.tar.gz ls *.tar.gz | xargs -i tar zxvf {} apt install --yes --allow-downgrades ./packages/*.deb rm -rf packages - run: name: Build project command: mint-build -i - run: name: Prepare packages command: | if [ -z $CI_PULL_REQUEST ]; then mkdir /packages mv /root/*.deb /packages/ git log > /packages/git.log cd / tar zcvf packages.tar.gz packages fi - run: name: Deploy packages to Github command: | if [ -z $CI_PULL_REQUEST ]; then wget https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_amd64.zip apt-get install --yes unzip unzip ghr_v0.5.4_linux_amd64.zip TAG="master".$CIRCLE_JOB ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -replace $TAG /packages.tar.gz ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -recreate -b "Latest unstable packages" $TAG /packages.tar.gz fi jobs: "mint19": <<: *shared docker: - image: linuxmintd/mint19-amd64 "lmde3": <<: *shared docker: - image: linuxmintd/lmde3-amd64 workflows: version: 2 build: jobs: - "mint19" - "lmde3" nemo-4.4.2/.github/000077500000000000000000000000001357442400300140215ustar00rootroot00000000000000nemo-4.4.2/.github/ISSUE_TEMPLATE.md000066400000000000000000000004341357442400300165270ustar00rootroot00000000000000 ``` * Nemo version (nemo --version) * Is issue with desktop or windowed nemo? * Distribution - (Mint 17.2, Arch, Fedora 25, etc...) * Graphics hardware *and* driver used * 32 or 64 bit ``` **Issue** **Steps to reproduce** **Expected behaviour** **Other information** nemo-4.4.2/.gitignore000066400000000000000000000012641357442400300144540ustar00rootroot00000000000000########################### # Default .gitignore file for Nemo. # By default this ignores the lint from the Eclipse IDE. ################## # Eclipse Output # ################## *.pydevproject .project .metadata bin/** tmp/** tmp/**/* *.tmp *.bak *.swp *~.nib local.properties .classpath .settings/ .loadpath # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # PDT-specific .buildpath debian/tmp/* debian/nemo/* debian/nemo-dbg/* debian/nemo-data/* debian/libnemo-extension*/* debian/gir1.2*/* debian/*.log debian/.debhelper debian/debhelper-build-stamp debian/files *.substvars *.debhelper debian/buildnemo-4.4.2/AUTHORS000066400000000000000000000000661357442400300135330ustar00rootroot00000000000000https://github.com/linuxmint/nemo/graphs/contributors nemo-4.4.2/COPYING000066400000000000000000000431161357442400300135210ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 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 Library 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. Copyright (C) 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, Suite 500, Boston, MA 02110-1335 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. , 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 Library General Public License instead of this License. nemo-4.4.2/COPYING-DOCS000066400000000000000000000433001357442400300142420ustar00rootroot00000000000000 GNU Free Documentation License Version 1.1, March 2000 Copyright (C) 2000 Free Software Foundation, Inc. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five). C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. In any section entitled "Acknowledgements" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections entitled "History" in the various original documents, forming one section entitled "History"; likewise combine any sections entitled "Acknowledgements", and any sections entitled "Dedications". You must delete all sections entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document, on account of their being thus compiled, if they are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document 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. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have no Invariant Sections, write "with no Invariant Sections" instead of saying which ones are invariant. If you have no Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for Back-Cover Texts. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. nemo-4.4.2/COPYING.EXTENSIONS000066400000000000000000000011271357442400300152130ustar00rootroot00000000000000Nemo extensions link against the libnemo-extenstions library which is is under the LGPL license. However, they also get loaded into the main nemo program which is licensed under the GPL. So, extensions should not be incompatible with the LGPL or GPL. Some extensions are GPL but use some IPC mechanism like dbus to talk to a potentially non-GPL application. This is actually not such a bad design in general if your extension is doing a lot of work, as running as a nemo extension with all its issues (no synchronous i/o, can't control of the context your code runs in, etc) can be kind of a pain. nemo-4.4.2/COPYING.LIB000066400000000000000000000613111357442400300141230ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street - Suite 500, Boston, MA 02110-1335, 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 Appendix: 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. Copyright (C) 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 - Suite 500, Boston, MA 02110-1335, 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. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! nemo-4.4.2/ChangeLog000066400000000000000000035455261357442400300142570ustar00rootroot00000000000000commit 16763a8b828387930641d69c04451e02d67cadd6 Author: Cosimo Cecchi Date: 2012-05-14 release: prepare for 3.4.2 M NEWS M configure.in commit 0e08c9938a4e3557f9519aa52f2f488a99e28e97 Author: Praveen Illa Date: 2012-05-14 Updated Telugu Translations M po/te.po commit 10a15760f0ba7d1b0a65693caf47a9b080742ed3 Author: Cosimo Cecchi Date: 2012-05-08 window-manage-views: don't call methods on a NULL NemoFile In got_file_info_for_view_selection_callback(), we unconditionally try to fetch information for the parent directory in case the selection is a regular file, but we should avoid doing that when the file has no parent, such as when it's the root of a web server. https://bugzilla.gnome.org/show_bug.cgi?id=675259 M src/nemo-window-manage-views.c commit c92532c8808815a776e377bf208bc194f077b169 Author: Cosimo Cecchi Date: 2012-05-07 x-content-bar: pack the media label in the content area Instead of just packing it into the GtkInfoBar's box, since that will put it after the buttons of the action area. https://bugzilla.gnome.org/show_bug.cgi?id=670129 M src/nemo-x-content-bar.c commit 7e90dabb2f38539173970fb715a53b355fb44e1c Author: Cosimo Cecchi Date: 2012-05-07 places-sidebar: disallow context menus for sidebar headings We already make them non-selectable - there's no point in having a menu for headings here. https://bugzilla.redhat.com/show_bug.cgi?id=819404 M src/nemo-places-sidebar.c commit 4e59e4cfc7bc68534664d9f72d0c7ea680b79db3 Author: Cosimo Cecchi Date: 2012-05-04 places-sidebar: don't double unref GMount objects Fixes a lot of reported crashers with NFS/Samba volumes. https://bugzilla.gnome.org/show_bug.cgi?id=674659 M src/nemo-places-sidebar.c commit c5b336f62e4d5efb330306cf9a905e70e7553171 Author: Kjartan Maraas Date: 2012-04-30 Added Norwegian bokmÃ¥l translation M po/nb.po commit fd7f5be8da08bf18d5d60314940491ff4f7fd99c Author: Ã…smund Skjæveland Date: 2012-04-29 Updated Norwegian Nynorsk translation M po/nn.po commit dad5031da0fc176ec27dcbb3a7057cc41aee399b Author: Sebastien Bacher Date: 2012-04-27 update ZERO_OR_THREE_DIGITS define to work as intended https://bugzilla.gnome.org/show_bug.cgi?id=674924 M libnemo-private/nemo-icon-canvas-item.c commit f5b824abf3f3b9304d7a63fd52d3f96036dc91ff Author: Cosimo Cecchi Date: 2012-04-24 editable-label: fix selection color in backdrop state Don't set the ACTIVE flag if we don't have focus, it just doesn't make sense. M eel/eel-editable-label.c commit dd0223773a818de92c71f119e1b42bae5157bdad Author: Djavan Fagundes Date: 2012-04-23 Fixed a string in Brazilian Portuguese translation M po/pt_BR.po commit 6b692bcaa4577aa811a18ba38ecce0d925e7613d Author: Yuri Myasoedov Date: 2012-04-23 Updated Russian translation M po/ru.po commit 9684ae22e4b4e02d8dc0b944d956ac7f7b8863f4 Author: Charles Kerr Date: 2012-04-18 link: plug a memory leak https://bugzilla.gnome.org/show_bug.cgi?id=674087 M libnemo-private/nemo-link.c commit c016565b17b2a94a1e2c7bbab9b5ae284110e578 Author: Charles Kerr Date: 2012-04-18 desktop-metadata: plug some memory leaks https://bugzilla.gnome.org/show_bug.cgi?id=674086 M libnemo-private/nemo-desktop-metadata.c commit 8118406d63b317c18cf52313a55c0f4b17093af3 Author: Cosimo Cecchi Date: 2012-04-18 list-view: don't treat clicks as on an empty area if the row is selected When the row is selected, and we right click on it, make sure we popup its context menu and not its parent's, since the selection is a stronger indication of intent. https://bugzilla.gnome.org/show_bug.cgi?id=674245 M src/nemo-list-view.c commit 2f2180c7a1e6203b3dfd9d926795aac180869fb3 Author: Christian Kirbach Date: 2012-04-18 Updated German translation (Bug #674093) M po/de.po commit ae6beb8030e3045b8bea3330e7b0507904a22e74 Author: Cosimo Cecchi Date: 2012-04-16 release: prepare for 3.4.1 M NEWS M configure.in commit bc3f1d8ffff2b3ca6336cef2bd5304c3f12b7418 Author: Cosimo Cecchi Date: 2012-04-13 undo: use g_file_info_get_attribute_byte_string for trash::orig-path Since that's what GVfs sets. https://bugzilla.gnome.org/show_bug.cgi?id=673776 M libnemo-private/nemo-file-undo-operations.c commit 17d765a598e85eaeb785938e896d1fd44abc481a Author: Milo Casagrande Date: 2012-04-06 [l10n] Updated Italian translation M po/it.po commit 0531db12b0a929fca139a3fde0846d31b602d922 Author: Abderrahim Kitouni Date: 2012-03-24 file-operations: don't mix character and byte lengths Otherwise untitled files end up with a (possibly) corrupt part of the name appended. https://bugzilla.gnome.org/show_bug.cgi?id=672761 M libnemo-private/nemo-file-operations.c commit ba04ec0e7435b21d492a39e0bafc167ba24e0f49 Author: Ryan Lortie Date: 2012-04-05 NemoFile: keep free space information directly There were previously some tricks in nemo to this effect: - when you call nemo_file_get_volume_free_space() on a NemoFile, the return result is NULL at first and later you get a "changed" signal on the file after the value is filled in - the value is being stored inside the NemoDirectory equivalent for the file that is created when the call is first performed and kept around until after the change signal fires (so that the person receiving the change signal can still get the data). This is done to save space by not expanding NemoFile. The NemoDirectory is then dropped after the change signal is done firing. - the nemo properties window has a 200ms timeout after changes to files being reported before it re-queries the properties The end result is that the NemoDirectory (which holds the information about the free space) is already freed by the time the properties window tries to update the free space display. This results in the directory being recreated and the process starting over again. The end result is that we never get the free space shown in the dialog and instead we have an infinite loop of CPU usage (fortunately repeating only every 200ms, so you get ~5% CPU usage instead of 100%). We can solve the problem by just storing the free space information directly in the NemoFile details structure and dropping the dance with NemoDirectory; nothing in NemoDirectory is actually using that information anyway. https://bugzilla.gnome.org/show_bug.cgi?id=673550 M libnemo-private/nemo-directory-private.h M libnemo-private/nemo-directory.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c commit 07f22b823cb75fc0da5dc9bc8c3805766d8baa15 Author: Praveen Illa Date: 2012-04-05 Updated Telugu Translation M po/te.po commit ae375b34c28c157950069e8bae8e033f5c12a556 Author: Nelson Benitez Leon Date: 2012-04-03 list-view: don't handle extra mouse buttons events Don't handle extra mouse button events so they can bubble up through GtkTreeview till NemoWindow where they are handled to navigate the view forward and backward. Part of bug 660006 Signed-off-by: Nelson Benitez Leon M src/nemo-list-view.c commit 3deb33d449f293b8e2597ccd7cc3bacec7b40ca2 Author: Nelson Benitez Leon Date: 2012-03-29 eel-canvas: ignore extra mouse button events Ignore button press/release events for mouse buttons greater than 5 so allowing forward and backward mouse buttons to work over icons. Part of bug 660006 Signed-off-by: Nelson Benitez Leon M eel/eel-canvas.c commit 49c753b1e2adaf7803b2fd4f1685f859d979ff74 Author: Cosimo Cecchi Date: 2012-04-02 file-operations: fix off-by-one error in copied files count TransferInfo->num_files counts from zero, so we have to increment it by one when formatting it into a string. https://bugzilla.gnome.org/show_bug.cgi?id=673345 M libnemo-private/nemo-file-operations.c commit 9b762008cf6417f1691bd94dd99c583d4e7a2c26 Author: Cosimo Cecchi Date: 2012-04-01 link: remove unused code nemo_link_local_get_additional_text() is now unused. M libnemo-private/nemo-link.c M libnemo-private/nemo-link.h commit afc9a8196ce9a94b900f532c3b7d433ef9641569 Author: Cosimo Cecchi Date: 2012-04-01 icon-container: don't show comment field for desktop files This fixes a regression introduced in commit 5a47a484e45218e83202c508b421b1a2707af270 https://bugzilla.gnome.org/show_bug.cgi?id=673316 M src/nemo-icon-view-container.c commit 3525ec8ec6b382a04affa0d02bf8ba1a1929f89b Author: Alexander Shopov Date: 2012-04-01 Updated Bulgarian translation M po/bg.po commit c2ab193ea26c67d6031fce7fe389b3832c37cc80 Author: Piotr DrÄ…g Date: 2012-03-31 Updated Polish translation M po/pl.po commit ce15200eb252536bf95c0a37939b883320f851c7 Author: Piotr DrÄ…g Date: 2012-03-29 Added Tibetan translation to LINGUAS M po/LINGUAS commit a08f87e8fe5522dbd58573a73d3e7aac70d80cff Author: tennom YK Date: 2012-03-29 Added Tibetan translation A po/bo.po commit 963ee1bd9ba64d88272bd264d76eff6846e24c7c Author: Daniel Mustieles Date: 2012-03-27 Updated Spanish translation M po/es.po commit 67b2499fc0ea6ba08063adea535a1d3529ff3053 Author: Mantas KriauÄiÅ«nas Date: 2012-03-26 Updated Lithuanian translation M po/lt.po commit b6972a97ab14dc86c2e5130feda39d3bc5c7a355 Author: Cosimo Cecchi Date: 2012-03-26 release: prepare for 3.4.0 M NEWS M configure.in commit c1551dfcfa9c92bf43c57b219535f63a9fecdad4 Author: Cosimo Cecchi Date: 2012-03-26 view: ensure we show "Open with..." entries for folders This is a regression from commit b9c51fd4eb84a9f52ee4be1bf183fc516984130b https://bugzilla.gnome.org/show_bug.cgi?id=672809 M src/nemo-view.c commit d64698322ea64fed050bd82de545e678d557f85c Author: ReÅŸat SABIQ Date: 2012-03-26 Updated Crimean Tatar (Crimean Turkish) translation M po/crh.po commit 440d5bb1693d32a7d4fb8ef16002c130b600eb80 Author: Jiro Matsuzawa Date: 2012-03-25 Updated Japanese translation. M po/ja.po commit 70b70e316cf4930036759581a935ab19475835e3 Author: Praveen Arimbrathodiyil Date: 2012-03-24 Malayalam translation updated by Aslam M po/ml.po commit afe92aa3ea0fdd988dd3bfe5851032843e6d808b Author: Sasi Bhushan Date: 2012-03-24 Updated Telugu translation M po/te.po commit 0d165b3e0b874263e6f52127194b6e9f47ea4a1b Author: Rajesh Ranjan Date: 2012-03-23 hindi translation by Chandan Kumar M po/hi.po commit adb6a12a7b0b08cfd441e4a75857797dc9875a43 Author: Timo Jyrinki Date: 2012-03-23 Updated Finnish translation by Jiri Grönroos M po/fi.po commit 982ce96d810795dd30d50cb2ff8e622fcb9ff4d6 Author: Praveen Illa Date: 2012-03-23 Updated Telugu Translation M po/te.po commit a6cb9e4697d904390cf54fdd19aa556b78bf98c0 Author: Kristjan SCHMIDT Date: 2012-03-22 Updated Esperanto translation M po/eo.po commit a5914993f533ceeef84d2d7000c64160b68d2cfb Author: Ibrahim Saed Date: 2012-03-21 Updated Arabic translation M po/ar.po commit 8d0c374a46fd90f82dea80c7d19fd8800fa67154 Author: Duarte Loreto Date: 2012-03-21 Updated Portuguese translation M po/pt.po commit 040ee44c68efb7120e9a86f56c6e325052d42a8f Author: Automatic Mirroring Date: 2012-03-21 Update Simplified Chinese translation. M po/zh_CN.po commit ef3a663a6e25040e1e96d3225654a0c774b1a823 Author: YunQiang Su Date: 2012-03-21 update Simplified Chinese (zh_CN) translation M po/zh_CN.po commit 4229689853639bce00b4a8dab7f7312aafb7da32 Author: Cosimo Cecchi Date: 2012-03-19 release: prepare for 3.3.92 M NEWS M configure.in commit a60e9887eebb8973c48c0151981a26cce7cc8793 Author: Cosimo Cecchi Date: 2012-03-19 places-sidebar: add support for the "network" volume class identifier If a GVolume has a class identifier of "network", put it (and its mount) in the Network section. This fixes e.g. NFS mounts showing in the wrong section. M src/nemo-places-sidebar.c commit a06988aefdf6cf147936737e48005170410046b2 Author: Cosimo Cecchi Date: 2012-03-19 places-sidebar: focus the first non-heading row on focus-in Instead of giving the focus to the heading, which would end up in getting stuck there, since headings are not supposed to be actionable. https://bugzilla.gnome.org/show_bug.cgi?id=672002 M src/nemo-places-sidebar.c commit 003b8773399de836e11c725f24c8a1f668a29adf Author: Cosimo Cecchi Date: 2012-03-19 places-sidebar: use gtk_tree_view_set_cursor() to move selection This will also move the scrolled window up/down when we navigate the places sidebar with keyboard. M src/nemo-places-sidebar.c commit 429d3548b72b5a29e8c0e31304db3cd51e25fcbf Author: Cosimo Cecchi Date: 2012-03-19 places-sidebar: make find_prev_or_next_row() start from the passed iter This will be useful for the next commits. M src/nemo-places-sidebar.c commit 5d2471aff8033fc319957273cf20d33420c5a6f7 Author: Carles Ferrando Date: 2012-03-19 [l10n]Updated Catalan (Valencian) translation M po/ca@valencia.po commit 3ea1074b29d7d25c7c087eeeece215a057ab3fbd Author: Joan Duran Date: 2012-03-19 [l10n] Updated Catalan translation M po/ca.po commit 63b59332d15139bd43504e0192a169cd5f924bf5 Author: Mario Blättermann Date: 2012-03-18 [l10n] Updated German translation M po/de.po commit f8f4f5a241dd99c04be8f327aed3316c9d87f1b2 Author: Cosimo Cecchi Date: 2012-03-16 icon-container: set a range base selection icon on _set_selection() If the selection we set if just one item (as it is in the case when we're going back/forward in the history), set that item as a base for range selection too, instead of just selecting it. https://bugzilla.gnome.org/show_bug.cgi?id=672127 M libnemo-private/nemo-icon-container.c commit ba281e27b804b1c61c715f4371f352b04e9d76ad Author: Cosimo Cecchi Date: 2012-03-16 eel: delete unused code We don't use EelDPoint/EelIPoint anymore; other functions here are just unused. M eel/eel-art-extensions.c M eel/eel-art-extensions.h M eel/eel-self-checks.c M eel/eel-self-checks.h commit 8e43d841355b6cd82af730bc2357f9ac1ed7c638 Author: Cosimo Cecchi Date: 2012-03-16 icon-container: avoid using EelDPoint It's going away. M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-canvas-item.h M libnemo-private/nemo-icon-container.c commit 0832acdb4371fc7de957303e220e899c8fdcdf5c Author: Cosimo Cecchi Date: 2012-03-16 icon-view: fix wheel scrolling for compact view If the smooth scroll event we get is an emulated scroll wheel, we have to emulate a right/left scroll, like we do for regular UP/DOWN events. https://bugzilla.gnome.org/show_bug.cgi?id=672185 M src/nemo-icon-view.c commit 8dcf1625bb5e38c865ebe01f53275b579093663c Author: Reinout van Schouwen Date: 2012-03-16 2012-03-16 Reinout van Schouwen - nl.po: Fixed typo M po/nl.po commit 136a20daeef2568776a1c239bac9cb66a1f66efc Author: Reinout van Schouwen Date: 2012-03-16 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ 2012-03-16 Reinout van Schouwen - nl.po: Use ‘Standaard instellen’ instead of ‘Standaard gebruiken’ M po/nl.po commit 9f6d1414dac34fef51616d7642fe52a2353d3c2b Author: Krishnababu Krothapalli Date: 2012-03-16 Translations Updated with FUEL M po/te.po commit 4273aa66a8e73e11cf3ad388bb53350c12b30e83 Author: Krishnababu Krothapalli Date: 2012-03-16 Translations Updated with FUEL M po/te.po commit 258628dbf02a540179488c94d0a6c1100ad12eab Author: Anita Reitere Date: 2012-03-14 Updated Latvian translation. M po/lv.po commit 3d275a971132a41809a3b1e5b8ac683d264d6c35 Author: Stefano Facchini Date: 2012-03-13 view: improve scroll-zooming for smooth scrolling devices Try to emulate a normal scroll event by adding deltas until the total delta reaches +1 or -1. M src/nemo-view.c commit d865bc50459fb1349a761c3c7029bad7f13fc67c Author: Cosimo Cecchi Date: 2012-03-13 pathbar: make dragging from toolbar work again This was a regression from the recent refactorings in NemoPathbar. Since we now have an event window, if we want button events to reach the parent toolbar, we have to select for such events when we realize the event window. M src/nemo-pathbar.c commit f7b54cdba55a0856b201e62818059ac5007fac35 Author: Cosimo Cecchi Date: 2012-03-13 view: threshold the delta information when scroll-zooming We don't want to zoom for every single event, since in case the device supports smooth scrolling, we will get a lot of small events. Pointed out by Stefano Facchini. M src/nemo-view.c commit 45cb82857c9cef34952da4c0488780fd8b19a61b Author: Jonh Wendell Date: 2012-03-13 Updated Brazilian Portuguese translation M po/pt_BR.po commit df6a0a0a1e721142b1be5338fcad2cc0248fdf1e Author: Cosimo Cecchi Date: 2012-03-12 build: remove unused --enable-profiler build option It's unused. https://bugzilla.gnome.org/show_bug.cgi?id=661632 M configure.in commit d9c23d83fdb5e1178f2c2f97a57b937cdab1b251 Author: Cosimo Cecchi Date: 2012-03-12 properties-window: ellipsize the Type field Or the properties window won't shrink when the file type string is long (e.g. with Archive types). https://bugzilla.gnome.org/show_bug.cgi?id=671809 M src/nemo-properties-window.c commit 73588247787b408ec43dba4156cadac97fe2d6d6 Author: Cosimo Cecchi Date: 2012-03-12 pathbar: refresh label size request every time it changes Or we might end up with buttons having the wrong size if a folder on the pathbar changes name. https://bugzilla.gnome.org/show_bug.cgi?id=671865 M src/nemo-pathbar.c commit 389845f1f6e175212554aba7645ce728f0a8f7ec Author: Cosimo Cecchi Date: 2012-03-12 pathbar: don't set use-markup before resetting the label If the label contains markup text, setting use_markup before resetting the text can spawn a warning (and we're resetting the label text right afterwards anyway). M src/nemo-pathbar.c commit 799514c57003d174b466c1fbf262f1229cf9d9df Author: Nilamdyuti Goswami Date: 2012-03-12 Assamese translation completed M po/as.po commit e6a47735728f2e9e40b7c036d94b8c7e7c996ef6 Author: Timo Jyrinki Date: 2012-03-12 Finnish translation update from http://l10n.laxstrom.name/wiki/Gnome_3.4 translation sprint M po/fi.po commit 269abde49580fe4ffa3ec0f31a4efa494860a1d5 Author: Piotr DrÄ…g Date: 2012-03-10 Updated Polish translation M po/pl.po commit 6449cbff18611f8583f98a6ce4e97b66c9667d52 Author: Seong-ho Cho Date: 2012-03-10 Updated Korean translation M po/ko.po commit 376678e92a107703ba19dd34fc4012ef4f04cf8c Author: Kristjan SCHMIDT Date: 2012-03-10 Updated Esperanto translation M po/eo.po commit 878e2a4f7ada26bb7c106e5bbdbd8434acf86c77 Author: Cosimo Cecchi Date: 2012-03-08 view: fix zoom direction for smooth scrolling case M src/nemo-view.c commit 1a76e044a2c9b834d00c4ea30f1e3af3321d8cdd Author: Cosimo Cecchi Date: 2012-03-08 view: handle smooth scroll events for zooming Instead of reaching the g_assert_not_reached() and crash. https://bugzilla.gnome.org/show_bug.cgi?id=671650 M src/nemo-view.c commit 0d46b0620b3b120cde310cb2319c309d8f3e3b82 Author: Cosimo Cecchi Date: 2012-03-07 all: remove eel_g_hash_table_new_free_at_exit() Especially when references can be owned by non-resident modules, this is just too dangerous. https://bugzilla.gnome.org/show_bug.cgi?id=670989 M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h M eel/eel-stock-dialogs.c M eel/eel-string.c M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M libnemo-private/nemo-signaller.c M libnemo-private/nemo-thumbnails.c M src/nemo-properties-window.c commit b9c51fd4eb84a9f52ee4be1bf183fc516984130b Author: Cosimo Cecchi Date: 2012-03-07 view: show applications for non launcher desktop files https://bugzilla.gnome.org/show_bug.cgi?id=319981 M src/nemo-mime-actions.c M src/nemo-view.c commit 5a47a484e45218e83202c508b421b1a2707af270 Author: Cosimo Cecchi Date: 2012-03-07 link: fix code to parse additional description for links For some reason, this was ifdeffed out. M libnemo-private/nemo-link.c M src/nemo-icon-view-container.c commit 9ff4e9194215cd955b952b1a82bd6a9d80e666cd Author: Cosimo Cecchi Date: 2012-03-07 link: remove obsolete check for application/x-gnome-app-info We stopped supporting this everywhere else ages ago. M libnemo-private/nemo-link.c commit 0ffe4ea4e0df9e5a186b3096bf1712011230a75b Author: Cosimo Cecchi Date: 2012-03-07 file-dnd: only accept launchers as DnD targets Not random desktop files. M libnemo-private/nemo-file-dnd.c commit b241fd28913e87fe01419e4922259949a11c973f Author: Cosimo Cecchi Date: 2012-03-07 file: don't consider all desktop files nemo links Only those which match application/x-desktop directly. M libnemo-private/nemo-file.c commit 1ef720295bc14630522f2496d194c7c43ccc016a Author: Cosimo Cecchi Date: 2012-03-07 directory-async: remove code that was never executed The ifdef is never defined, so we should just remove this code. M libnemo-private/nemo-directory-async.c commit b4877e5bb19d99936987dc9507fba273a55c3a5a Author: Cosimo Cecchi Date: 2012-03-07 properties-window: fix packing for desktop file properties box Fallout from GtkTable->GtkGrid migration. M src/nemo-properties-window.c commit cc05cdd37fa4e34164081222740c266ae5761508 Author: Bruce Cowan Date: 2012-03-07 Updated British English translation M po/en_GB.po commit aed94bad3ea8eaa6c603f8d85cbfb8cd1fd824fd Author: Arash Mousavi Date: 2012-03-06 Updated Persian Translation M po/fa.po commit 36b1557baf6ecc923e821d417531895640195c4f Author: Bruno Brouard Date: 2012-03-06 Updated French translation M po/fr.po commit 34e74c768d5f39a65056716429a84306c3901992 Author: Matej UrbanÄiÄ Date: 2012-03-06 Updated Slovenian translation M po/sl.po commit b1c3776dd91c29e4e9c1f020c24bb039ef730962 Author: Inaki Larranaga Murgoitio Date: 2012-03-06 Updated Basque language M po/eu.po commit 7fdd100f259046f86500da3eb64cf10bceaba2bd Author: Cosimo Cecchi Date: 2012-03-05 build: bump required GTK version to 3.3.17 I.e. the current git master. M configure.in commit df2cf158aa93e2d395b57ce2a1bf4b89bac20709 Author: Cosimo Cecchi Date: 2012-03-05 release: prepare for 3.3.91 M NEWS M configure.in commit ab5077e0bce77af4cad87a20fec8099e3db0bcc0 Author: Michael Terry Date: 2012-03-05 slot: don't ref the NemoWindowSlot when setting floating bar timeout We cancel the timeout on destruction already, and if a destroy event happens in between the timeout, this would break the assumption in NemoWindowPane that all its slots were removed during its destruction. https://bugzilla.gnome.org/show_bug.cgi?id=670591 M src/nemo-window-slot.c commit 819a5d14a33d95ba5ef25a3becec4ebccb93807b Author: Michael Terry Date: 2012-03-05 file-operations: use the right prototype for empty trash callback When unmounting, we might first prompt whether the trash should be emptied or not on the target volume. If we do so, make sure the callback from the empty trash job has the right prototype, to avoid crashing later trying to interpret a gboolean as a pointer to a data structure. https://bugzilla.gnome.org/show_bug.cgi?id=670595 M libnemo-private/nemo-file-operations.c commit 503443418709c9fb42af52c90c035b3957b0686e Author: Cosimo Cecchi Date: 2012-03-05 pathbar: copy implementation of an event window from the GTK copy In order to listen for scroll events on the whole pathbar area, we need to create an event window in realize(), created with GDK_SCROLL_MASK. Copy the code from GtkPathBar that implements this. M src/nemo-pathbar.c M src/nemo-pathbar.h commit 04116ab2876412445c788091be07d7f7321a4a94 Author: Cosimo Cecchi Date: 2012-03-05 pathbar: sync with GTK master to make scrolling work again M src/nemo-pathbar.c commit 4c83328a0ba2d511fea8cefe1464269fbaa1b35f Author: Cosimo Cecchi Date: 2012-03-05 Revert "Revert "Fix up accidental error in last commit"" Having people randomly commit unapproved controversial changes to the UI during UI freeze is so awesome... This reverts commit 50a174cfbf288f07d2f9bf44f31af41dc1535df8. M src/nemo-view.c commit 29a050d986bd5fd86ef522617966768c8c40beb7 Author: Cosimo Cecchi Date: 2012-03-05 Revert "Revert "Use ctrl-delete as the keyboard shortcut to trash files"" Having people randomly commit unapproved controversial changes to the UI during UI freeze is so awesome... This reverts commit 6c21b39cd9d22de4c92ab214e647e65fbfdfe9ac. M src/nemo-view.c commit 6c66de56871a7201c6b0c13d216a237a2e4a4af3 Author: Hannie Dumoleyn Date: 2012-03-04 Updated Dutch translation M po/nl.po commit 24bbb0d39a285546538961d917a070f1ead27bed Author: Arash Mousavi Date: 2012-03-04 Updated Persian Translations M po/fa.po commit 4a0dcfa280ebf9ade975fbefc470f9d3334b1175 Author: Nguyá»…n Thái Ngá»c Duy Date: 2012-03-04 Updated Vietnamese translation M po/vi.po commit 46ba80571e73335fa2fde48529e73b6f2b3f0453 Author: Nguyá»…n Thái Ngá»c Duy Date: 2012-03-03 po/vi: import from Damned Lies M po/vi.po commit 55660df03074e3759a88fd5cf4a45d0a0ce8830a Author: Gabor Kelemen Date: 2012-03-04 Updated Hungarian translation M po/hu.po commit 2c289a073bd0ff4b779f70885566b0783534a1da Author: Daniel Korostil Date: 2012-03-02 Uploaded Ukranian M po/uk.po commit 202b772a7b6fcd7ac758011935cc0eb4eca8454e Author: Mario Blättermann Date: 2012-02-29 [l10n] Updated German translation M po/de.po commit 6c21b39cd9d22de4c92ab214e647e65fbfdfe9ac Author: Xavier Claessens Date: 2012-02-27 Revert "Use ctrl-delete as the keyboard shortcut to trash files" This reverts commit cce40272e35b20b4aaf5f93109a05b7bb89704d5. M src/nemo-view.c commit 50a174cfbf288f07d2f9bf44f31af41dc1535df8 Author: Xavier Claessens Date: 2012-02-27 Revert "Fix up accidental error in last commit" This reverts commit c6279ac229545d7f64b64212383df2753482e233. M src/nemo-view.c commit f8f2aa2c1caa6c3eb2ad801f9b1644b505ec1e3f Author: Dr.T.Vasudevan Date: 2012-02-26 updated Tamil translation M po/ta.po commit b1de3f789a3271d459815ec6d04ece342ebf8d1c Author: Dr.T.Vasudevan Date: 2012-02-26 updated Tamil translation M po/ta.po commit b4272502dbdb48656502679e364c25ea945e1945 Author: Dr.T.Vasudevan Date: 2012-02-26 updated Tamil translation M po/ta.po commit 9c0bf9befaa286a96b4300d462954de003708340 Author: A S Alam Date: 2012-02-26 update Punjabi Translation M po/pa.po commit 94463615ff55a9217470054084f4af8e819ee9c8 Author: Abderrahim Kitouni Date: 2012-02-23 Updated Arabic translation by Ibrahim Saed and Abderrahim Kitouni M po/ar.po commit 73929f70316bd2b120a67725fdd43bc5a996149b Author: Mattias Põldaru Date: 2012-02-22 [l10n] Updated Estonian translation M po/et.po commit ab0af563ecfd50632cbb8491e634282a0f15ea07 Author: Mattias Põldaru Date: 2012-02-22 [l10n] Updated Estonian translation M po/et.po commit fa8997416110581ed48979fdf873f8fe28fcf87b Author: Ask H. Larsen Date: 2012-02-20 Updated Danish translation M po/da.po commit b05d9fd27463054916f84626f4d1a8daf9543d18 Author: МироÑлав Ðиколић Date: 2012-02-20 Updated Serbian translation M po/sr.po M po/sr@latin.po commit 30f1d93169661d1493ffca3baace20577bed4a3a Author: Cosimo Cecchi Date: 2012-02-20 release: prepare for 3.3.90 M NEWS M configure.in commit 3da42acd7a4da971294708e683394a2292c54c12 Author: Cosimo Cecchi Date: 2012-02-20 build: link eel and libnemo-private to libm M eel/Makefile.am M libnemo-private/Makefile.am commit 6fecf4844d5ae749c83a943af950ee594fc2e73d Author: Cosimo Cecchi Date: 2012-02-20 file: add a default empty implementation of set_metadata methods Otherwise we will segfault for subclasses of NemoFile that don't override the method. https://bugzilla.gnome.org/show_bug.cgi?id=669735 https://bugzilla.gnome.org/show_bug.cgi?id=669711 M libnemo-private/nemo-file.c commit 9fda64f91fdbd470e8a84991427dd1e9cb0b8ebf Author: Ihar Hrachyshka Date: 2012-02-20 Updated Belarusian translation. M po/be.po commit 67c5ba88c073c0a6620f22d7223d2bd3b450f499 Author: Ihar Hrachyshka Date: 2012-02-20 Updated Belarusian translation. M po/be.po commit f6f651bff8f5961ea4577c7aaa81ada8263a74da Author: Kjartan Maraas Date: 2012-02-20 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 448c7991f3c2fb7c2434cd7a2dab8dfae399f609 Author: Adam MatouÅ¡ek Date: 2012-02-20 Updated Czech translation M po/cs.po commit c3f5c2afdd1f740576029544d21e732759e54ba0 Author: Daniel Nylander Date: 2012-02-19 Updated Swedish translation M po/sv.po commit 720b994d93d62f346e0cde181bdfc1817916f13c Author: Yaron Shahrabani Date: 2012-02-18 Updated Hebrew translation. M po/he.po commit 0d4de6246689ab67b40dad1d206114915589d18f Author: Chao-Hsiung Liao Date: 2012-02-18 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit ea10e1a45f11ea3771b92f411a0817fd9049fc88 Author: Jiro Matsuzawa Date: 2012-02-17 [l10n] Update Japanese translation M po/ja.po commit d5cc4631ee4366bcf7f33c78bf193eb0e1cbb8b0 Author: Luca Ferretti Date: 2012-02-16 l10n: Updated Italian translation M po/it.po commit 41106223c6124fb8b427810a3e9a5b9d270777fa Author: Fábio Nogueira Date: 2012-02-16 Updated Translator Credits in Brazilian Portuguese Translation M po/pt_BR.po commit 8b21dc1de851f4e49a791cb2d878570e26985975 Author: Alexander Shopov Date: 2012-02-16 Updated Bulgarian translation M po/bg.po commit 570266ce8c0ccd0e2382cd6cf5fdd59339b9a7c1 Author: Yuri Myasoedov Date: 2012-02-15 Updated Russian translation M po/ru.po commit a7843cb0d1bff3deafed93d9c9e2c7d8d6ebf458 Author: Daniel Mustieles Date: 2012-02-15 Updated Spanish translation M po/es.po commit 4421b79de801efd5fbd7d6ef6666e2b0e3b813f9 Author: Fran Diéguez Date: 2012-02-14 Updated Galician translations M po/gl.po commit 2c7b82f2d3712f08dc940828b7a4b4de55164621 Author: Cosimo Cecchi Date: 2012-02-14 undo: add ngettext plural forms for undo operation strings Even if we don't use those strings for singular cases, this is still needed, since some languages might need to use the singular form for e.g. the x1st item. See: https://live.gnome.org/TranslationProject/DevGuidelines/Plurals https://bugzilla.gnome.org/show_bug.cgi?id=669889 M libnemo-private/nemo-file-undo-operations.c commit 01382c267728e2dd00cc8b48cd6024dbae183345 Author: Cosimo Cecchi Date: 2012-02-13 pane: don't make the toolbar for inactive pane insensitive At the same time, we have to listen for events on the toolbar items to set the active pane. M src/nemo-search-bar.c M src/nemo-search-bar.h M src/nemo-window-menus.c M src/nemo-window-pane.c commit 3787143f2bcf576a9b75600b40a324454b25beca Author: Cosimo Cecchi Date: 2012-02-13 pane: set a style class on the inactive window pane to style it Set a "nemo-inactive-pane" style class on the inactive NemoWindowPane; this allows us to theme the inactive pane state way more easily and removes a bunch of setup code. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M libnemo-private/nemo-icon-private.h M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-view.c M src/nemo-view.h M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 31dad6f9fa05dc64fc1ead54bdad9bbae4bfa713 Author: Cosimo Cecchi Date: 2012-02-13 icon-canvas-item: don't override parent container style flags When drawing the canvas item elements, don't override the parent container style flags, so we don't lose e.g. backdrop information. M libnemo-private/nemo-icon-canvas-item.c commit 457c9ccaf17e34366ea4bacb7d3a1a72094fb8d7 Author: Baurzhan Muftakhidinov Date: 2012-02-12 [l10n] Updated Kazakh translation M po/kk.po commit 47778be25cf65fbcd0151093fc7e2b3aa14b229c Author: Cosimo Cecchi Date: 2012-02-11 floating-bar: add "floating-bar" style class M src/nemo-floating-bar.c commit ef34e92b4c685c25e36d67b8b266ac6bff1489f0 Author: Yuri Myasoedov Date: 2012-02-11 Updated Russian translation M po/ru.po commit 8d064c5e5782e98bb63836b92847ff1260f4b77f Author: Tiffany Antopolski Date: 2012-02-10 po: updated en_CA.po M po/en_CA.po commit cd497dd43fabc6b9aa679fd326bb0f16334dbd59 Author: Cosimo Cecchi Date: 2012-02-08 undo: fix a double free in the Create operation strings func https://bugzilla.gnome.org/show_bug.cgi?id=669691 M libnemo-private/nemo-file-undo-operations.c commit 071f40683bda36eb47df8a2c536da282b9fb04e6 Author: Cosimo Cecchi Date: 2012-02-06 release: prepare for 3.3.5 M NEWS M configure.in commit b7a3fddf60aaeac95f85259b2d83fc3cde81959f Author: Cosimo Cecchi Date: 2012-02-06 places-sidebar: change the way we restore selection on update Instead of checking whether the URI of every item we add is a candidate for selection, cycle through all the added items after inserting. This also fixes a bug where the GtkTreeIter we used for keeping track of the last added item was not up-to-date with the actual cell, since the sort function we apply to the items will modify the position of the item in the tree itself, making the iter invalid. https://bugzilla.gnome.org/show_bug.cgi?id=668212 M src/nemo-places-sidebar.c commit 7e7a21daf15055aab8639ba684ce34a6683073fa Author: Cosimo Cecchi Date: 2012-02-06 places-sidebar: don't use an additional GtkTreeModelFilter We were using it just for GtkTreeDragSourceIface, which we can implement ourselves. M src/nemo-places-sidebar.c commit 7c5ebdbbd3c7778af230fc830b5bc6bd706f1d61 Author: Cosimo Cecchi Date: 2012-02-06 window-manage-views: fix a crash when middle-clicking desktop icons We were hitting an assertion when middle clicking a desktop icon, since we were trying to open it in a tab (same window), and we don't really want to do that on the desktop. https://bugzilla.gnome.org/show_bug.cgi?id=655576 M src/nemo-window-manage-views.c commit 4abf11d07e8d8bc86523e105db9c6c76f29e9643 Author: Cosimo Cecchi Date: 2012-02-06 window: simplify code a bit Don't export nemo_window_update_split_view_actions_sensitivity(), but alwauys call it from nemo_window_update_show_hide_menu_items(), since that's what the code always does. https://bugzilla.gnome.org/show_bug.cgi?id=669189 M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window.c commit 2626eacbd9883161d7d3b14f4e1c56a02e3eb7ce Author: Cosimo Cecchi Date: 2012-02-06 pane: don't forget to update the split view actions when closing a slot In case a slot close is requested, we should still update the split view actions sensitivity/state. https://bugzilla.gnome.org/show_bug.cgi?id=669189 M src/nemo-window-pane.c commit e8c4685f033b11034fa24007c558b8fc347024d3 Author: Cosimo Cecchi Date: 2012-02-06 desktop-background: stop any pending crossfades on widget destruction Internally, GnomeBGCrossfade depends on the GdkWindow we pass on to gnome_bg_crossfade_start() to be available during the whole crossfade. If our widget is destroyed, we have to immediately stop the crossfade, without waiting our finalization step, which happens after the widget is already gone. M libnemo-private/nemo-desktop-background.c commit 91fc1674ae71d356b06b8b549e91782a2b06758a Author: Cosimo Cecchi Date: 2012-02-06 desktop-background: unref the GnomeBG on finalize This also prevents signals being emitted from it after our destruction, as in https://bugzilla.gnome.org/show_bug.cgi?id=665796 M libnemo-private/nemo-desktop-background.c commit 9d0f892656282519059d65f10db7504ad4910b22 Author: Cosimo Cecchi Date: 2012-02-06 pane: don't access invalid memory slot->pane is already cleared in nemo_window_slot_dispose(), which will get called while the slot is destroyed; setting it here can cause an invalid memory access. M src/nemo-window-pane.c commit 1bfe1dd449bdfb80e58f6f149d87c153f13962f2 Author: Piotr DrÄ…g Date: 2012-02-04 Updated Polish translation M po/pl.po commit 6b2e19cb9957f0685eb561a6e22c1be6730e6fee Author: Cosimo Cecchi Date: 2012-01-31 undo: fix logic in the file operation callback This caused some actions not to be scheduled for redo. M libnemo-private/nemo-file-undo-operations.c commit c4099c1a20c0502dd7a12e0d1ffbfe70d4bf527a Author: Cosimo Cecchi Date: 2012-01-30 application: fix an unfortunate typo We were allocating the wrong size for the NemoApplication private structure. M src/nemo-application.c commit d60b724d5ee183b1074a137d9cc24c22b3a2259d Author: Cosimo Cecchi Date: 2012-01-30 undo: fix Redo Trash not updating the trashed mtime When we redo a trash operation, we should make sure our trashed files hash table stores the updated timestamp when we trashed the file again, or we won't be able to trash them again. M libnemo-private/nemo-file-undo-operations.c commit 2a02b02328e20ac66b8cb71140681fdd0ac384ff Author: Cosimo Cecchi Date: 2012-01-30 undo: make sure to correctly clear the undo state on operation finish Don't stack allocate the struct for the file operations return value, and make sure we don't return success for a failed operation. M libnemo-private/nemo-file-undo-operations.c commit 2944be953ef54717bb24968b0eebe468c9705db4 Author: Chao-Hsiung Liao Date: 2012-01-29 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 56a0b14e55239bf5076f1c73b30f534af1dd1a86 Author: Matej UrbanÄiÄ Date: 2012-01-28 Updated Slovenian translation M po/sl.po commit f34c331ca81e4bafd6db4c6c36c7b3625c674278 Author: Matej UrbanÄiÄ Date: 2012-01-28 Updated Slovenian translation M po/sl.po commit 3738ee50a11a2d3997c470cb19a23521c60c256e Author: Yaron Shahrabani Date: 2012-01-28 Updated Hebrew translation. M po/he.po commit 247a27a94b28304dbb0b4aaf2ff783d0d909a73c Author: Timo Jyrinki Date: 2012-01-24 Updated Finnish translation. M po/fi.po commit 9736b263c7830dad6c9de6b42f131395201b993b Author: Cosimo Cecchi Date: 2012-01-23 undo: remove some URI->GFile roundtrips in the trash undo operations We can just store GFiles directly in the hash table and use g_file_hash() and g_file_equal() instead of parsing the URIs ourselves. M libnemo-private/nemo-file-undo-operations.c commit 211d4429171e6d3e307cb175513077f61c86b640 Author: Cosimo Cecchi Date: 2012-01-23 undo: don't provide any free function for trashed hashtable values No need to call g_free() anymore. M libnemo-private/nemo-file-undo-operations.c commit 3c3096371bb8fda0766c59c9467eb8ed24ed67cf Author: Arthur Taylor Date: 2012-01-22 Make rubberband fade obey gtk animation setting. The rubberband fade-out effect should observe the gtk animation setting, intened to make life easier for people running resource contrained setups (like X11 over a network.) Signed-off-by: Arthur Taylor M libnemo-private/nemo-icon-container.c commit 125cc4026585b760071db630ffd6edcce1ad8c93 Author: Kjartan Maraas Date: 2012-01-23 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 7b74cfc6fd6279599753f777620e2537d1f23e61 Author: Daniel Mustieles Date: 2012-01-23 Updated Spanish translation M po/es.po commit 45a2f47e35002b316cb8ccb94073deaa6bb75850 Author: Fran Diéguez Date: 2012-01-22 Updated Galician translations M po/gl.po commit 362fb6464b62d6fed896d1bc53f6fc763f8fa6fb Author: Cosimo Cecchi Date: 2012-01-21 undo: rework undo for the trash operation to be asynchronous Also, make the mtime checks actually useful; we need to check the trash::deletion-date attribute and match it with the time we trashed the file (which we can easily know using g_get_current_time()). M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-undo-operations.c M libnemo-private/nemo-file-undo-operations.h commit c063418e66ed0fdc40b4fd48bc5bd29c0cbefa09 Author: Cosimo Cecchi Date: 2012-01-21 undo: fix undo move to trash We were querying the mtime of the trashed file after it was already trashed, and we were also overflowing the guint64 assigning -1 to it. M libnemo-private/nemo-file-operations.c commit bf38d260d1011c08f5e36f3d7d78e10244627e16 Author: Cosimo Cecchi Date: 2012-01-21 undo: always complete the apply action in idle The action might be synchronous. M libnemo-private/nemo-file-undo-operations.c commit 89cc154cee3e64a771499d21f410854ecc5cd8ad Author: Piotr DrÄ…g Date: 2012-01-21 Updated POTFILES.in M po/POTFILES.in commit f8e8507dcfa98e21a1454cb5290b071abec680e4 Author: Daniel Mustieles Date: 2012-01-21 Updated Spanish translation M po/es.po commit 5f338fc07e288dcc2ff6e141edc42aade01da284 Author: Cosimo Cecchi Date: 2012-01-20 undo: remove NemoFileUndoTypes M libnemo-private/Makefile.am D libnemo-private/nemo-file-undo-types.h commit 3f45de05a6a87c8d432e94375f714c3da1f8fc34 Author: Cosimo Cecchi Date: 2012-01-20 view: use NemoFileUndoInfo directly Get the info object from the manager and use that to build menus. M src/nemo-view.c commit aac633c6d66d7dd9753b645e88657a7f6257e8eb Author: Cosimo Cecchi Date: 2012-01-20 file/file-operations: adapt to changes in file undo manager And fix some typos. M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c commit 1f758301ee89b5f96bcb650f039696a7049fac44 Author: Cosimo Cecchi Date: 2012-01-20 file-undo-manager: use NemoFileUndoInfo Rework NemoFileUndoManager to use the new NemoFileUndoInfo objects. At the same time, make it use a single item instead of a queue, turning it into a state machine. This has various reasons; from a code perspective, if we keep a stack of operations, we should also keep track and invalidate items in there when something changes on the filesystem, but this can be very expensive. On the other hand in the UI we probably don't want to expose more than one item anyway. M libnemo-private/nemo-file-undo-manager.c M libnemo-private/nemo-file-undo-manager.h commit 69e79e2f9d3c8c2bbae4a0a32e58f42385c662b4 Author: Cosimo Cecchi Date: 2012-01-20 undo: turn NemoFileUndoData into NemoFileUndoInfo Make it a GObject with subclasses for each type of operations. This allows for easy sharing of the base class object with the view as well, for menu information, and provides an async API to the undo manager for the file operation. M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file-undo-operations.c M libnemo-private/nemo-file-undo-operations.h M libnemo-private/nemo-file-undo-types.h M libnemo-private/nemo-file.c commit 44b695b9af6a26fbf2979a19fd638cc3682c89bb Author: Cosimo Cecchi Date: 2012-01-18 file-operations: first pass at passing on success information We want to know if a file operation failed for some reason, so that we don't add it in the redo queue. M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-operations.h M libnemo-private/nemo-file-undo-manager.c M libnemo-private/nemo-file-undo-manager.h M libnemo-private/nemo-file-undo-operations.c M libnemo-private/nemo-file-undo-operations.h M libnemo-private/nemo-file-undo-types.h M src/nemo-places-sidebar.c M src/nemo-properties-window.c M src/nemo-tree-sidebar.c M src/nemo-view.c M test/test-copy.c commit f76844a3208033a97532222ce531bd9a04205871 Author: Cosimo Cecchi Date: 2012-01-16 undo: pass in a GtkWindow for undo operations So that dialogs triggered by the file operations can correctly be parented. M libnemo-private/nemo-file-undo-manager.c M libnemo-private/nemo-file-undo-manager.h M libnemo-private/nemo-file-undo-operations.c M libnemo-private/nemo-file-undo-types.h M src/nemo-view.c commit dcf5d6796b5adc13a4b03d36f30d9f15025e9df9 Author: Amos Brocco Date: 2012-01-16 undo: introduce undo support M libnemo-private/Makefile.am M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-private.h A libnemo-private/nemo-file-undo-manager.c A libnemo-private/nemo-file-undo-manager.h A libnemo-private/nemo-file-undo-operations.c A libnemo-private/nemo-file-undo-operations.h A libnemo-private/nemo-file-undo-types.h M libnemo-private/nemo-file.c M src/nemo-directory-view-ui.xml M src/nemo-shell-ui.xml M src/nemo-view.c M src/nemo-window-menus.c commit 88f18618ba15b952a739e410b910508f244b1fc3 Author: Vincent Untz Date: 2012-01-19 build: Support build against tracker 0.13/0.14 https://bugzilla.gnome.org/show_bug.cgi?id=667853 M configure.in commit b65b13f59e0bb20497751a5c13ea85ccb7ebb2ba Author: Daniel Mustieles Date: 2012-01-17 Updated Spanish translation M po/es.po commit 01a2c0affada3157cf5b7b8147e27d6a0a0151dc Author: Fran Diéguez Date: 2012-01-17 Updated Galician translations M po/gl.po commit 3795ec8883676e367be1d7f9d6314a1a7e781fd7 Author: Cosimo Cecchi Date: 2012-01-16 notebook: use a symbolic icon for the tab close image M src/nemo-notebook.c commit 1a5cc61ae329d3776e8d75fd46b0e9326f0e7654 Author: Kjartan Maraas Date: 2012-01-16 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 8ff0ae7d645b4c076977ab889b46a20392d3da25 Author: Cosimo Cecchi Date: 2012-01-16 release: prepare for 3.3.4 M NEWS M configure.in commit 8c778211e5c826998890d2034b828928c693e4d9 Author: Carlos Garnacho Date: 2012-01-12 eel: Queue resizes on the canvas as elements change visibility Not queueing resizes may play oddly with the size request caches in GTK+, resulting in gtk_widget_get_preferred_width/height returning 0 even after the canvas was populated. https://bugzilla.gnome.org/show_bug.cgi?id=667831 M eel/eel-canvas.c commit f1bb90717ba78533905d3f532940a390371a979c Author: Cosimo Cecchi Date: 2012-01-16 build: add nemo.gresource.xml to EXTRA_DIST Fix distcheck. M src/Makefile.am commit 132bf6802d9e36354e89469f3ef0b5daa1082299 Author: Cosimo Cecchi Date: 2012-01-16 extension: doc cleanups M docs/reference/libnemo-extension/Makefile.am M docs/reference/libnemo-extension/libnemo-extension-docs.xml M docs/reference/libnemo-extension/libnemo-extension-sections.txt commit e79c28b48008ed5e94763417b4a68b86ffcfd919 Author: Cosimo Cecchi Date: 2012-01-16 extension: add some more missing gir annotations M libnemo-extension/nemo-column-provider.c M libnemo-extension/nemo-menu-provider.c M libnemo-extension/nemo-menu.c M libnemo-extension/nemo-property-page-provider.c commit f04f79a424a03127c4d3ab44bd1363ff00ade212 Author: Cosimo Cecchi Date: 2012-01-16 build: update gitignore M data/.gitignore M src/.gitignore commit 607c8a11f41d7f1a49f67421d4b98a6edbcbcee5 Author: Cosimo Cecchi Date: 2012-01-16 module: don't access the GModule if none was returned Before checking if the GModule pulls in ORBit, we should make sure g_module_open() returned a non-NULL GModule. M libnemo-private/nemo-module.c commit 024381aac07aeb7ed161913e601fcefbf4e3f990 Author: Marcus Carlson Date: 2012-01-16 file-operations: show current file counter and total files Change the file operation strings so that both the current file counter and the total number of files are shown in the UI. https://bugzilla.gnome.org/show_bug.cgi?id=606955 M libnemo-private/nemo-file-operations.c commit e0b3e63b6fedb8bd056c80647c43f4f388c3b1ed Author: Cosimo Cecchi Date: 2012-01-16 build: require latest GLib and GTK+ This is needed for the new resources API. M configure.in commit 733c890a5d7e4615b754accc0c7906545b9a0b59 Author: Alexander Larsson Date: 2012-01-12 Move all ui files and icons into resources M icons/Makefile.am M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file-utilities.h M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-thumbnails.c M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h M src/Makefile.am M src/nemo-bookmarks-window.c M src/nemo-desktop-icon-view.c M src/nemo-file-management-properties.c M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-toolbar.c M src/nemo-view.c M src/nemo-window-menus.c A src/nemo.gresource.xml commit d6291d9ae62de65deaafd72cf9f5a5e22e627cf3 Author: Yaron Shahrabani Date: 2012-01-14 Updated Hebrew translation. M po/he.po commit 1df7de8a1ab643ebefe3d8df7ab0343f36687299 Author: Martin Pitt Date: 2012-01-05 Lazily initialize notification service Avoid spawning the notification daemon at startup through querying server caps. Instead, cache the result in server_has_persistence() and initialize it lazily. https://bugzilla.gnome.org/show_bug.cgi?id=667342 M src/nemo-progress-ui-handler.c commit 6010f04793f926d2cc3c3533ce2f8de3f24eccc6 Author: Og B. Maciel Date: 2012-01-12 Fixes wrong translation on warning about long filename. BGO #667495. M po/pt_BR.po commit 69cb7b536c0df4331b7c36aca9f71e67c8b19009 Author: Timo Jyrinki Date: 2012-01-12 Updated Finnish translation. M po/fi.po commit 6003b063ee2af39644d4138e52ae93bd5b513ac1 Author: Cosimo Cecchi Date: 2012-01-09 extension: add some annotations M libnemo-extension/nemo-file-info.c M libnemo-extension/nemo-location-widget-provider.c commit 0d0eb9b50e5fd24a09bc2b9c141950fb75d86db3 Author: Cosimo Cecchi Date: 2012-01-09 window: make nemo_window_prompt_for_location() private M src/nemo-window-menus.c M src/nemo-window.c M src/nemo-window.h commit d01abc43d6bf016b573cbd0d6b6d0dc1bd127873 Author: Cosimo Cecchi Date: 2012-01-09 window: remove unused view-as-changed signal M src/nemo-window.c commit 006e8207d13da318aa912a860930dd79f04fb085 Author: Cosimo Cecchi Date: 2012-01-09 window: remove unused zoom-changed signal M src/nemo-window.c commit d48669776205bf7732601d73d2fddec5b44a53ef Author: Cosimo Cecchi Date: 2012-01-09 pane: remove useless assertion Now that the slots are direct pages of the GtkNotebook, there's no need to ensure the slot is in the pane's list, since we already assert on gtk_notebook_page_num(slot) >= 0. M src/nemo-window-pane.c commit ec391bf3de51ab4ee7f510ab6570fc240a7754c0 Author: Cosimo Cecchi Date: 2012-01-09 slot: make NemoWindowSlot a GtkBox Simplifies management of the slot quite a bit. M src/nemo-notebook.c M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-slot.c M src/nemo-window-slot.h commit 283c4903139dc08b7b69afa117870e143cc64137 Author: Cosimo Cecchi Date: 2012-01-09 notebook: remove unused defines M src/nemo-notebook.c commit 115c960e939a1c1fa6db97a105fe92d0b70ecde8 Author: Cosimo Cecchi Date: 2012-01-09 slot: remove unused cases for NemoLocationChangeType M src/nemo-window-manage-views.c M src/nemo-window-slot.h commit 1cb66dfb4c3750a142dfd3130613b52b1d386eff Author: Cosimo Cecchi Date: 2012-01-07 search-bar: remove unused focus-in signal M src/nemo-search-bar.c M src/nemo-search-bar.h commit f49a5b864058cc5bb4b1534ab03e89d1e9fdbc34 Author: Cosimo Cecchi Date: 2012-01-07 window: move nemo_window_update_up_button() to NemoWindow M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window.c commit 2705e8019c6f6b3714b679788827c5c297798cf9 Author: Cosimo Cecchi Date: 2012-01-07 pane: cleanup M src/nemo-properties-window.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window-types.h M src/nemo-window.c M src/nemo-window.h commit 1af49b5dd84e9127785f2c507940574d6f62ecbf Author: Cosimo Cecchi Date: 2012-01-07 window: use g_clear_object M src/nemo-window-manage-views.c M src/nemo-window-menus.c commit 4d22ba9b6100556bf6f81f827b38dc9ad0626ac3 Author: Cosimo Cecchi Date: 2012-01-06 window: nuke unused functions M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h commit ed97a6ec6db1a618bc65705618e5b73748e4cd7e Author: Cosimo Cecchi Date: 2012-01-06 all: use nemo_window_slot_get_window() M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window.c commit f1f7bf476b3c932d13927e55292e8bd8b77b29d8 Author: Cosimo Cecchi Date: 2012-01-06 application: remove useless assignment M src/nemo-application.c commit e83f6e0990971ea22275bd9cf877541b7824ab14 Author: Cosimo Cecchi Date: 2012-01-06 pane: refactor to make NemoWindow a GObject property M src/nemo-window-pane.c commit 93923f66225434e42ef6bb8588e7d3fbdb3409a4 Author: Cosimo Cecchi Date: 2012-01-06 window: fold nemo_window_allow_up() into its only caller M src/nemo-window-manage-views.c M src/nemo-window.c M src/nemo-window.h commit f5db1b3062a42a649fbc11e4272399cfa70dc772 Author: Cosimo Cecchi Date: 2012-01-06 window: remove unused nemo_window_allow_back/forward M src/nemo-window.c M src/nemo-window.h commit f784b5b57503e58c49a1d55b0c664096951c9018 Author: Cosimo Cecchi Date: 2012-01-06 pane: use nemo_navigation_state_set_boolean() M src/nemo-window-pane.c commit f3eff82082f4ebd88e01d3efbe2631a15989cfa9 Author: Cosimo Cecchi Date: 2012-01-06 navigation-state: add API to sync a boolean value on a tracked action M src/nemo-navigation-state.c M src/nemo-navigation-state.h commit 9384542c1821420c01962237d23e9716bc5a8404 Author: Cosimo Cecchi Date: 2012-01-06 window: add nemo_window_get_navigation_state() M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window.c M src/nemo-window.h commit f876211d2e318580d1f28c57e7f0182f7c5bfb3a Author: Cosimo Cecchi Date: 2012-01-06 window: add nemo_window_get_main_action_group() M src/nemo-desktop-window.c M src/nemo-window-menus.c M src/nemo-window.c M src/nemo-window.h commit 419d49de7dd714095fbd63dd7093fec5c07a52fb Author: Cosimo Cecchi Date: 2012-01-06 slot: fold function into the only caller Also simplify its code a bit. M src/nemo-window-slot.c commit 7289cc044cfaa3eee69396805d4e6dd8644a9483 Author: Cosimo Cecchi Date: 2012-01-06 slot: cleanup NemoWindowSlot creation M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit b09427273f525753b4b792bfdfb333e28c2e0ea9 Author: Cosimo Cecchi Date: 2012-01-06 window: misc cleanups M src/nemo-window-bookmarks.c M src/nemo-window-private.h M src/nemo-window.c commit 33a79d4ca73be9b45b19ff28cd702103a40333c5 Author: Cosimo Cecchi Date: 2012-01-06 window: move nemo_window_open_slot to NemoWindowPane Where it should really belong. M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window.c commit 0d83fdffed7b3c8987e19f6e5ef6f304f5efdb9d Author: Cosimo Cecchi Date: 2012-01-06 slot: don't include gi18n.h in the header M src/nemo-bookmarks-window.c M src/nemo-progress-ui-handler.c M src/nemo-view-dnd.c M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit ac606bd25e13914c28702a5099905ead4e1c1510 Author: Cosimo Cecchi Date: 2012-01-06 all: use nemo_window_get_active_pane() M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window.c commit 455c8da5981db559d7d47d9f9fcb8dac8297d4ac Author: Cosimo Cecchi Date: 2012-01-06 all: use nemo_window_get_active_slot() M src/nemo-location-bar.c M src/nemo-window-bookmarks.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window-slot.c M src/nemo-window.c commit cc151a40cebda4ba7d4adc40c702f0210614105f Author: Cosimo Cecchi Date: 2012-01-02 window: remove bookmark menu placeholder path from NemoWindowClass It's not used by the only subclass we have now. M src/nemo-window-bookmarks.c M src/nemo-window.c M src/nemo-window.h commit 6c8896cfc1a52b0eec31bec3090ee5661af1931e Author: Cosimo Cecchi Date: 2012-01-02 window: remove nemo_window_get_window_type() It's unused now. M src/nemo-desktop-window.c M src/nemo-window.c M src/nemo-window.h commit f167ba4f3f3d571169c07584528e748391c5a833 Author: Cosimo Cecchi Date: 2012-01-02 view: don't use nemo_window_get_window_type() Just check if the view is a NemoDesktopIconView instead. M src/nemo-view.c commit 6561bf66c37ffcff450c7880300661ee260ec5c7 Author: Cosimo Cecchi Date: 2012-01-02 window: remove unused code M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit b5316226924feb948de5f372962c7174ff8fa10d Author: Cosimo Cecchi Date: 2012-01-02 window: remove nemo_window_show_window() Fold it into the only caller, and simplify its code. M src/nemo-window.c M src/nemo-window.h commit 1d06cfcff92afc46bcaf5b313a604b93d76cbdd9 Author: Cosimo Cecchi Date: 2012-01-02 window: remove useless assignment M src/nemo-window.c commit d84023681be2f192ccbd4fe5c3b07631c683911f Author: Cosimo Cecchi Date: 2012-01-02 window: simplify code Fold function into the only caller. M src/nemo-window.c commit 00ad5bc605488e15a6877ce94cbd0e4b1f42cdb1 Author: Ihar Hrachyshka Date: 2012-01-10 Updated Belarusian translation. M po/be.po commit 7aff7fb6b0e5b7717e06944c09de734270d85ed8 Author: Diego Escalante Urrelo Date: 2011-12-29 floating-bar: misc indentation fixes M src/nemo-floating-bar.c commit 2cd406307863c268d045487daeedeb36e22a19bf Author: Alexander Shopov Date: 2012-01-08 Updated Bulgarian translation M po/bg.po commit 669ab8445bb33f00dfeb6584fdc431ea942fda79 Author: Nguyá»…n Thái Ngá»c Duy Date: 2012-01-06 Updated Vietnamese translation M po/vi.po commit f4d439875b3a101fa195012fb8a6607542e69b9a Author: Nguyá»…n Thái Ngá»c Duy Date: 2012-01-06 po/vi: import from Damned Lies M po/vi.po commit 02c0d8b671ee9cd61374b28d1627ab8edff7fe41 Author: Mattias Põldaru Date: 2012-01-02 [l10n] Updated Estonian translation M po/et.po commit a9627858a6b49e505b97c210e95f0bafa91e0a90 Author: Jovan Naumovski Date: 2012-01-01 Updated Macedonian translation. M po/mk.po commit 54dd59e149edcc6d744bba5cd7576526e9b52075 Author: Wylmer Wang Date: 2011-12-27 Update Simplified Chinese translation M po/zh_CN.po commit aacde57c44b1259ed476507b6288416d999832f9 Author: Andreas N Date: 2011-12-26 Updated Norwegian Nynorsk translation M po/nn.po commit 1a050ded4c3625c56022a1d50b856cf298d1f2c2 Author: Xandru Armesto Date: 2011-12-22 Updated asturian translation M po/ast.po commit c6510f6b07caeeffacbfa062660e4fca0219d958 Author: Jürg Billeter Date: 2011-12-20 build: Add gmodule as dependency With GLib 2.31.4 and later, linking against GIO no longer drags in gmodule. M configure.in commit 54ae064f753582a8b0745110b45724b99eb913a4 Author: Cosimo Cecchi Date: 2011-12-19 release: prepare for 3.3.3 M NEWS M configure.in commit 2de1c3a4a0294006bbcf950f7473ff962848dc1c Author: Cosimo Cecchi Date: 2011-12-19 fdo-dbus: dist the DBus interface XML file Fixes distcheck M data/Makefile.am commit 642835db7ab148e44733206a09bf55cd14660e5a Author: Cosimo Cecchi Date: 2011-12-19 fdo-dbus: don't dist generated dbus sources Use nodist_nemo_SOURCES, like the generated object manager for org.Nemo.FileOperations M src/Makefile.am commit f35e710d3c31fc2af5ddce9c31a52d408e215276 Author: Cosimo Cecchi Date: 2011-12-19 fdo-dbus: use the right include for nemo-debug.h Fixes distcheck M src/nemo-freedesktop-dbus.c commit 85af4ef2e58b45dcd40f6ba692b12e73c6cf6ffd Author: Pierre Wieser Date: 2011-12-19 Set icons from extensions on the context menu GtkActions This way, if icons are set to display in e.g. menus, extensions one will be properly shown. https://bugzilla.gnome.org/show_bug.cgi?id=665822 M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h M src/nemo-view.c commit 773fdc3e2ba7fef4bf824c865a0f3aba14fc785a Author: Stefano Teso Date: 2011-12-04 places-sidebar: make Desktop dir bookmarkable if not shown by default See: https://bugzilla.gnome.org/show_bug.cgi?id=663956 M src/nemo-places-sidebar.c commit 2ee1b4060b1d99c67e528d626514968384277af5 Author: Nelson Benitez Leon Date: 2011-12-13 Show background menu when clicking on blank space Fixes bug 94618 M src/nemo-list-view.c commit 73b2f5e9de469f7997c8ab4d12f1aa542a4e7e54 Author: Nelson Benitez Leon Date: 2011-12-14 Fix race condition when right-clicking after rubberbanding Fixes bug 662979 M libnemo-private/nemo-icon-container.c commit 1fbc4002d38f42a5e9536dc3f1b59438d362d94e Author: Petr Kovar Date: 2011-12-15 Fix Czech translation M po/cs.po commit 6ed0cae9df696b816309b6c6d8fdb2660c66b922 Merge: 11fa184 f01e2e9 Author: Federico Mena Quintero Date: 2011-12-14 Merge branch 'freedesktop-dbus' - bgo#636269 This adds an implementation for the DBus interface org.freedesktop.NemoFileManager1. This lets applications call the file manager to show a file within a folder, to show a folder's contents, or to show a file's properties. The main work behind this is by Akshay Gupta , done during the Google Summer of Code 2011. commit f01e2e9b5fa6dcd0514bdf5efe5f76b4312f1fd3 Author: Federico Mena Quintero Date: 2011-12-14 Add an org.freedesktop.NemoFileManager1.service file for DBus Even though this registers a service for a freedesktop name with a Gnome-specific program (Nemo), we'll just do this for now. Later we can discuss in the DBus list how to launch services with generic interfaces, but specific implementations for each desktop environment. Signed-off-by: Federico Mena Quintero M data/Makefile.am A data/org.freedesktop.NemoFileManager1.service.in commit 73e5a35efcd7607d6a3ee5e8bd5e8278a86d6705 Author: Federico Mena Quintero Date: 2011-12-14 Remove superfluous helper function Signed-off-by: Federico Mena Quintero M src/nemo-properties-window.c commit 371e178550587cad04941493c6129e8e454223ab Author: Cosimo Cecchi Date: 2011-12-14 Use a single method to create properties windows Make startup_id a param of nemo_properties_window_present(). M src/nemo-freedesktop-dbus.c M src/nemo-places-sidebar.c M src/nemo-properties-window.c M src/nemo-properties-window.h M src/nemo-tree-sidebar.c M src/nemo-view.c commit 6e02005986b78879f4d3e23342c90accfa241745 Author: Cosimo Cecchi Date: 2011-12-14 properties-window: parent_widget and startup_id are not mutual Even though we don't (yet) use the same code path when building a properties window for a parent widget and for a startup_id (i.e. there's no call that sets both), there's no reason to make them mutually exclusive in code when creating the window. M src/nemo-properties-window.c commit 326f5d86a5650d201c48acacaf77752d544668da Author: Cosimo Cecchi Date: 2011-12-14 fdo-dbus: coding style cleanups M src/nemo-freedesktop-dbus.c commit c0752563fe6f2a0454069b93c9a29dae11a2e833 Author: Cosimo Cecchi Date: 2011-12-14 fdo-dbus: handle g_file_get_parent() failing g_file_get_parent() can return NULL if the file is a root element. Handle that case gracefully in the code. M src/nemo-freedesktop-dbus.c commit 8aa21c333115cec5eab0cd3965684b9b09dc7fa3 Author: Cosimo Cecchi Date: 2011-12-14 application: streamline code for creating selection list M src/nemo-application.c commit 14f7dd8cdbbe04b84c2b8f75134cefd45aaf9c4b Author: Federico Mena Quintero Date: 2011-12-13 Pass the startup_id when creating the properties window This completes the implementation of the DBus interface. Signed-off-by: Federico Mena Quintero M src/nemo-freedesktop-dbus.c commit 625dac4492e7daf7fef46c8dc4990da5d786efad Author: Federico Mena Quintero Date: 2011-12-13 Add nemo_properties_window_present_with_startup_id() This lets us pass a startup_id string instead of a parent_widget; this will be used from the Freedesktop DBus interface. Signed-off-by: Federico Mena Quintero M src/nemo-properties-window.c M src/nemo-properties-window.h commit 9868b796ec9d4761512d0a948bf0d6438be6702c Author: Federico Mena Quintero Date: 2011-12-13 Don't use nested if()s when a single one will do M src/nemo-properties-window.c commit ebc2d0728553cded8dcb5f65d0075e2e7c9d277e Author: Federico Mena Quintero Date: 2011-12-13 Use g_clear_object() instead of verbose code M src/nemo-freedesktop-dbus.c commit 08c2044e7056a9d6113dbf3613ea6303b6f0180d Author: Federico Mena Quintero Date: 2011-12-13 Implement ShowItems() vs. ShowFolders() from the DBus interface We use the new nemo_application_open_location() to do this; now we can distinguish 'open a location and select something inside it', vs. 'show a location'. Signed-off-by: Federico Mena Quintero M src/nemo-freedesktop-dbus.c commit 29ecfd7fb83c57289fc5e46a05cbead958f4b1ef Author: Federico Mena Quintero Date: 2011-12-13 Add nemo_application_open_location() This is a convenience function so that NemoFreedesktopDBus can cause the application to open a location and optionally select an item within that location. Signed-off-by: Federico Mena Quintero M src/nemo-application.c M src/nemo-application.h commit 3a899726ac482ae90f1b8fb52657ee80fef3a7fe Author: Federico Mena Quintero Date: 2011-12-13 Turn NemoFreeDesktopDBus into a GObject internally This is to match NemoDBusManager. Signed-off-by: Federico Mena Quintero M src/nemo-freedesktop-dbus.c commit 11fa1848dca3af78cd0f984f7c84f2214140f023 Author: Rudolfs Mazurs Date: 2011-12-13 Updated Latvian translation M po/lv.po commit 5294105677f371998043dde98a94847a1246c421 Author: Ryan Lortie Date: 2011-12-13 nemo application: use GActionMap g_application_set_action_group() is deprecated for favour of GActionMap, so use that instead. Bump the glib version dependency for GActionMap. M configure.in M src/nemo-application.c commit 33ca9cd5b0be3dcf092b7174591ede34edf2346d Author: Cosimo Cecchi Date: 2011-12-08 eel: remove unused eel_accessibility_set_name/description M eel/eel-accessibility.c M eel/eel-accessibility.h commit f78dee9affd9c88ce410c42cbf9c1118839d33d7 Author: Cosimo Cecchi Date: 2011-12-08 view: use ATK API directly to set accessible name/description M src/nemo-view.c M src/nemo-window-manage-views.c commit c76dc41521c9327a7aa121f35e68e10b6783f740 Author: Cosimo Cecchi Date: 2011-12-07 application: add a compatibility dummy --browser cmdline option External scripts or desktop files from previous might still call nemo with the --browser option, and it's bad to just fail in that case. Add a dummy (and hidden) cmdline option that does nothing for --browser. https://bugzilla.gnome.org/show_bug.cgi?id=665700 M src/nemo-application.c commit 4b497142b1c2361cf38c0804a283b8b419c3b623 Author: Cosimo Cecchi Date: 2011-12-07 man: remove reference to --browser option from the manual The option is not supported anymore since 3.0. https://bugzilla.gnome.org/show_bug.cgi?id=665700 M docs/nemo.1 commit ecf70ad6a66cc1450935e54ebffd95660ebc05a4 Author: Akshay Gupta Date: 2011-12-06 Implement ShowItemProperties() M src/nemo-freedesktop-dbus.c commit f65bd26d6f3691006c291f88e6c3b1add349d985 Author: Federico Mena Quintero Date: 2011-12-06 Allow creating a properties window with a NULL parent widget When the ShowItemProperties() DBus call comes in, it doesn't come from a parent widget. Instead, it has a startup ID. So, we need to be able to pass a NULL parent_widget to the properties window. Signed-off-by: Federico Mena Quintero M src/nemo-properties-window.c commit 5f3b0071d11cc864d135f35b7b85b07a5395f97a Author: Akshay Gupta Date: 2011-12-06 Implement ShowFolders() NemoApplication doesn't make a distinction between showing files and showing folders, so for now we'll use the same implementation. M src/nemo-freedesktop-dbus.c commit 08b590a4c6014d6a91a525b3183d3266788703a4 Author: Akshay Gupta Date: 2011-12-06 Implement ShowItems() Unfortunately g_application_open() and NemoApplication don't actually use the startup_id. We will have to pass this in another fashion later. M src/nemo-freedesktop-dbus.c commit e7dc7a27001dcadb8f7a2cafb26bbb3be724d801 Author: Federico Mena Quintero Date: 2011-12-06 Initialize the freedesktop DBus manager from NemoApplication Signed-off-by: Federico Mena Quintero M src/nemo-application.c commit e1a2bcecf4d4dea845194c943f82c60f8c6c6d36 Author: Federico Mena Quintero Date: 2011-12-06 Pass the NemoApplication to the freedesktop DBus manager Signed-off-by: Federico Mena Quintero M src/nemo-freedesktop-dbus.c M src/nemo-freedesktop-dbus.h commit 456afcbb6042c8f1ab73f240e5be5eabd681e090 Author: Federico Mena Quintero Date: 2011-12-06 DBus boilerplate for handling the org.freedesktop.NemoFileManager1 service Signed-off-by: Federico Mena Quintero M src/Makefile.am A src/nemo-freedesktop-dbus.c A src/nemo-freedesktop-dbus.h commit aa01e30c0d3d585bd808ed1ab53c5ca396371cd1 Author: Federico Mena Quintero Date: 2011-12-06 Generate the org.freedesktop DBus code Signed-off-by: Federico Mena Quintero M src/.gitignore M src/Makefile.am commit a3c387089e3bb9eaafe8b033bd334d151ccebe06 Author: Akshay Gupta Date: 2011-12-06 Add declaration for the org.freedesktop.NemoFileManager1 DBus interface This is not in dbus-interfaces.xml as that one has a different namespace (org.gnome.Nemo), and that makes the generated code from gdbus-codegen really ugly. By keeping a separate file for this interface, we can get pretty generated code. A data/freedesktop-dbus-interfaces.xml commit 40be4b85f51fc7b192ef7421b2ede27954997cc8 Author: Nelson Benitez Leon Date: 2011-12-02 Make 'next row' behaviour work again by making it general According to feedback on a11y list this should not hurt a11y. Fixes bug 660881 M libnemo-private/nemo-icon-container.c commit 2721796f86efd1e7e118c9531657e815bd1e0c60 Author: Cosimo Cecchi Date: 2011-12-05 idle-queue: remove unused NemoIdleQueue M libnemo-private/Makefile.am M libnemo-private/nemo-directory-private.h D libnemo-private/nemo-idle-queue.c D libnemo-private/nemo-idle-queue.h commit 896a9cf4bbadfc19c6d69fa53bd9ea46cb81989c Author: Rui Matos Date: 2011-12-02 icon-container: use a threshold to start scrolling while rubberbanding This allows us to scroll while rubberbanding when the window is maximized and thus the pointer can't possibly leave the widget area. https://bugzilla.gnome.org/show_bug.cgi?id=665383 M libnemo-private/nemo-icon-container.c commit cdf858fbfccdbca7bd8fc27f0f85e815177ee8c6 Author: Stefano Teso Date: 2011-11-30 Avoid deprecate gtk_widget_get_pointer(). M libnemo-private/nemo-icon-container.c commit 0a5838004030f64d9f27c55a3f2f49275b82b79f Author: Cosimo Cecchi Date: 2011-12-02 properties-window: initiate a new row when no sibling is provided This was the original intent of this code. M src/nemo-properties-window.c commit 098aa9334123334d500c166f13dc47f5f110cd8a Author: Cosimo Cecchi Date: 2011-12-02 window: explicitly destroy the sidebar in _destroy() When the nemo window is destroyed, make sure to explicitly destroy the sidebar before the panes. Destroying all the panes can trigger a callback back into the sidebar, which would then try to access the window pane list from the callback. The pane list was already destroyed and cleared at that point though, and we would segfault. https://bugzilla.gnome.org/show_bug.cgi?id=652320 M src/nemo-window.c commit 7e351fd5ead64be1343eea6d357a2edb25f9a721 Author: Dmitry Shachnev Date: 2011-12-01 Don't allow "New tab" (Ctrl+T) shortcut in desktop window Disable the New Tab action on the desktop. https://bugzilla.gnome.org/show_bug.cgi?id=655256 M src/nemo-desktop-window.c commit f1d9644efe457d84b9a18f250e85b5d70cb46620 Author: Praveen Illa Date: 2011-11-30 Updated Telugu Translation M po/te.po commit 780f8e4abf482628677e4f75ed502e1f18cf2411 Author: Daniel Nylander Date: 2011-11-25 Updated Swedish translation M po/sv.po commit cd99b28b903e0c3c69f142dd5c7977bb791d9cf1 Author: Cosimo Cecchi Date: 2011-11-23 places-sidebar: sort the XDG dirs section for the current locale The XDG dirs section should not hardcode an english ordering, but follow the current locale. https://bugzilla.gnome.org/show_bug.cgi?id=664464 M src/nemo-places-sidebar.c commit 786b34ff9abfae433956077a5feb2978d126ecfb Author: Stas Solovey Date: 2011-11-16 Updated Russian translation M po/ru.po commit a76dce8845b9bca8e01e67ad547ae158cff18456 Author: Thura Hlaing Date: 2011-11-14 [l10n]Added Burmese translation M po/LINGUAS A po/my.po commit 3aeff5a3d2114b77126686bd642716b21f4aa014 Author: Fran Diéguez Date: 2011-11-13 Updated Galician translations M po/gl.po commit b81330c62d232af66c5be7186f2badabecd52673 Author: Daniel Mustieles Date: 2011-11-09 Updated Spanish translation M po/es.po commit 12bc05de21fed18ac985470fa55174629de6470f Author: Kristjan SCHMIDT Date: 2011-11-04 Updated Esperanto translation M po/eo.po commit aff2f078ef222f28a8a32408260efdfc7d8be8d9 Author: Gabor Kelemen Date: 2011-10-29 Fix a small mistranslation in the Hungarian po M po/hu.po commit 9208a93c2d3f85bcb10c05c1cfc55b33b545ca46 Author: Yaron Shahrabani Date: 2011-10-27 Updated Hebrew translation. M po/he.po commit f01c138bc3567cfedb476bcc4e2a66da8b3b38ee Author: Kristjan SCHMIDT Date: 2011-10-26 Updated Esperanto translation M po/eo.po commit b3dde943b7628bf32076b3e375256a775786d05b Author: Cosimo Cecchi Date: 2011-10-25 release: bump to 3.3.1.1 3.3.1 was accidentally released with a wrong tarball, bump version and roll a tarball again. M configure.in commit f18eb3a0b04ab8b094012bb5d0d2abb0bf7b7799 Author: Cosimo Cecchi Date: 2011-10-25 build: switch to XZ M configure.in commit 628c0566f7317c25f30991652a6192d7d8f4fbd8 Author: Cosimo Cecchi Date: 2011-10-25 release: prepare for 3.3.1 M NEWS M configure.in commit 45ee835907056a95c4ae9dad5f7913620ed219d7 Author: Cosimo Cecchi Date: 2011-10-25 eel-string: don't segfault in eel_str_replace_substring for NULL strings Just check if the strings are != NULL before calling strlen() on them. M eel/eel-string.c commit 79525a6502316974bd9e28144b82290b1840dac4 Author: Matej UrbanÄiÄ Date: 2011-10-23 Updated Slovenian translation M po/sl.po commit 26a1e55ab5b8ebb8d441569bb790b0c4976c7bf8 Author: Yaron Shahrabani Date: 2011-10-22 Updated Hebrew translation. M po/he.po commit 2ce3696a73d5eda0b6213311f2bfee7a600d9256 Author: Cosimo Cecchi Date: 2011-10-19 places-sidebar: trivial cleanups M src/nemo-places-sidebar.c commit 4764a856c7a6e5a84d4067e7b105c09a93ffdbe4 Author: Cosimo Cecchi Date: 2011-10-19 places-sidebar: return if we fail to compute a drop position Instead of using an invalid GtkTreePath, which could cause a segfault later. https://bugzilla.gnome.org/show_bug.cgi?id=660876 M src/nemo-places-sidebar.c commit cda2c75df4b95a481e8b774081ec1240d47fa45f Author: Cosimo Cecchi Date: 2011-10-19 places-sidebar: don't assert we have a valid selected iter When reordering bookmarks, don't assert we have a selected iter, since it might not always be the case. https://bugzilla.gnome.org/show_bug.cgi?id=660876 M src/nemo-places-sidebar.c commit 7826dfbdc4cb9a5381b6d9845e0ba7459fcd2fe4 Author: Cosimo Cecchi Date: 2011-10-19 places-sidebar: don't call gtk_tree_model_get() with an invalid path If we click on an empty area of the sidebar, we shouldn't pop up any menu at all anyway, which is what this commit changes. Previously, we would have tried to get a GtkTreePath for the currently selected point and an iter for that (invalid) path, which would lead to gtk_tree_model_get() segfaulting on an invalid iter. https://bugzilla.gnome.org/show_bug.cgi?id=662218 M src/nemo-places-sidebar.c commit 67aaaf9f9a95de0beb8a45f97b378144b93ab9d4 Author: Daniel Mustieles Date: 2011-10-19 Updated Spanish translation M po/es.po commit 11da44db624aadcf8b71950acf05b929caa565b6 Author: Muhammet Kara Date: 2011-10-18 Updated Turkish translation M po/tr.po commit 5208c1c1a2da66ece2562c22dde8ed51d550c1cf Author: György Balló Date: 2011-10-18 Autostart only in GNOME and Unity Don't show desktop icons in other DEs, e.g Xfce and KDE uses it's own desktop implementation. https://bugzilla.gnome.org/show_bug.cgi?id=661942 M data/nemo-autostart.desktop.in commit a90444b3651272119d1d4ab65d70b41b95a87616 Author: Stefano Teso Date: 2011-10-18 places-sidebar: show a Properties item for mounts https://bugzilla.gnome.org/show_bug.cgi?id=546189 M src/nemo-places-sidebar.c commit a598148fde3f08ad69115b96c5a9a821ac16983c Author: Timothy Arceri Date: 2011-10-18 file-operations: show needed space as a secondary message When there's not enough space on the disk, show how much additional space is needed for the operation to complete, instead of a more obscure error message. https://bugzilla.gnome.org/show_bug.cgi?id=542960 M libnemo-private/nemo-file-operations.c commit c590280477db495a362339c512d73daade862329 Author: Cosimo Cecchi Date: 2011-10-18 test: don't use deprecated gtk_vbox_new() M test/test-eel-editable-label.c commit a816e00ef769a3be12a053a29e41f3da1b91c492 Author: Cosimo Cecchi Date: 2011-10-18 all: don't use deprecated GDK pointer methods Use the new GdkDevice methods instead. M eel/eel-editable-label.c M libnemo-private/nemo-dnd.c M libnemo-private/nemo-tree-view-drag-dest.c M src/nemo-notebook.c commit 0594aa1636ef960361cf60d00c58ab94c81ee5d4 Author: Cosimo Cecchi Date: 2011-10-18 all: don't use deprecated GMutex/GThread API Also, threads area always enabled, so we can remove the G_THREADS_ENABLED conditionals. Require GLib 2.31 for this. M libnemo-private/nemo-file-changes-queue.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-search-engine-simple.c commit 04975e6cbc8f82238e3611a26b474b56c46ec1d3 Author: Cosimo Cecchi Date: 2011-10-18 all: don't call g_thread_init() GLib does that for us now. M configure.in M src/nemo-main.c M test/test-copy.c M test/test-nemo-search-engine.c commit e54ace0a550b47c251634ee833884f5bc6ea4be6 Author: Cosimo Cecchi Date: 2011-10-17 editable-label: use GTK_STYLE_CLASS_ENTRY Because that's what it is actually... M eel/eel-editable-label.c commit b143b95f20755fc8425464aa11df3fa2ac2df2ea Author: Cosimo Cecchi Date: 2011-10-17 editable-label: use gtk_render_frame() instead of hardcoding a stroke This allows the stroke to use rounded corners and border images, among other things. M eel/eel-editable-label.c commit f9383acb378762a80a373f124e059aff5e571f21 Author: Cosimo Cecchi Date: 2011-10-17 editable-label: don't hardcode black for the insertion cursor Use the theme foreground/text color instead. M eel/eel-editable-label.c commit 3f95c46dff1c4f71f67d2733f0487350139775cf Author: Cosimo Cecchi Date: 2011-10-17 editable-label: remove useless code No need to call _set_background() on the editable label widget. M eel/eel-editable-label.c commit 8b87a3e86eb228d4414c3d64cc81b7bb56d27076 Author: Cosimo Cecchi Date: 2011-10-17 editable-label: make sure to size_request the padding set on the label And not the alignment, which is an offset inside the allocated size. M eel/eel-editable-label.c commit 4c74f176542935b8ea8f61f9bb9ae6cdb35466ea Author: Cosimo Cecchi Date: 2011-10-17 icon-container: use gdk_window_move() to position the typeahead popup For some reason, gtk_window_move() doesn't always work reliably, while gdk_window_move() seems to always position the window in the requested coordinates. https://bugzilla.gnome.org/show_bug.cgi?id=660807 https://bugs.launchpad.net/ubuntu/+source/nemo/+bug/857710 M libnemo-private/nemo-icon-container.c commit 9a703cea5067f68ef21b90a42856b229d5edc69d Author: Cosimo Cecchi Date: 2011-10-17 icon-container: don't associate Ctrl+F to typeahead search It won't get triggered anyway, as we bind Ctrl+F to show the search bar in NemoWindow. M libnemo-private/nemo-icon-container.c commit fea4112c35c84bdb124a567c2d84a2f2a8bd172d Author: Cosimo Cecchi Date: 2011-10-17 places-sidebar: don't crash when middle clicking on empty space gtk_tree_view_get_path_at_pos() can fail; handle that case instead of passing an invalid GtkTreePath. https://bugzilla.gnome.org/show_bug.cgi?id=657366 https://bugs.launchpad.net/ubuntu/+source/nemo/+bug/830185 M src/nemo-places-sidebar.c commit 03888c1dde59cb2dd3b243e3c72f35757a4c2e5f Author: Cosimo Cecchi Date: 2011-10-17 tree-sidebar: don't call g_free on a GObject list https://bugzilla.gnome.org/show_bug.cgi?id=660906 https://bugs.launchpad.net/ubuntu/+source/nemo/+bug/845408 M src/nemo-tree-sidebar.c commit 0a5aa2a28d82554afb684d815e8180f307ac1897 Author: Ivan Masár Date: 2011-10-16 Updated Slovak translation M po/sk.po commit 9bdca2a00b3c3f6a5e908964b4f3a2e39eec0145 Author: Jiro Matsuzawa Date: 2011-10-17 Updated Japanese translation M po/ja.po commit 4b470c16d7b7190e973b712d9f29d6bccd7f9e83 Author: Andrej ŽnidarÅ¡iÄ Date: 2011-10-14 Updated Slovenian translation M po/sl.po commit 1f23acbe5f526370db2ffec1dec09fea7e6de219 Author: Yuri Myasoedov Date: 2011-10-14 Fixed Russian translation M po/ru.po commit 04ff2cd9e6500b3f9f1052199e1321e33538225b Author: Michael Biebl Date: 2011-10-11 Fix build failure if tracker FTS is enabled M libnemo-private/nemo-search-engine-tracker.c commit 048115fa9c5c1ffa45a8df5fcb52e75f6c3d2641 Author: krishnababu k Date: 2011-10-10 Updated Telugu Translations M po/te.po commit 0dc5b59e637db6bdcc92a5b2bfce4a6a58c9a6e1 Author: Muhammet Kara Date: 2011-10-10 Updated Turkish translation M po/tr.po commit 428b468e8e6e66270cb434f14e4b1f8d7f5354c9 Author: Cosimo Cecchi Date: 2011-10-05 all: remove offset_x/offset_y parameters from eel_pop_up_context_menu() They're unused now. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h M src/nemo-places-sidebar.c M src/nemo-view.c commit 7b290a2b2fee7028e50c0ecf15d5417a7a7dc59d Author: Federico Mena Quintero Date: 2011-10-05 Remove stale 'offset' in eel_pop_up_context_menu() Also, fix the fallback timestamp for the menu popup. Signed-off-by: Federico Mena Quintero M eel/eel-gtk-extensions.c commit 61699ef56eb3091341c5f5a38189e12a11280e3e Author: Cosimo Cecchi Date: 2011-10-05 eel: remove unused eel_gdk_rgba_is_dark() M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit bcc62bec90aec23fb1ede56f0ce0181218fdc81a Author: Cosimo Cecchi Date: 2011-10-05 eel-string: remove unused code M eel/eel-string.c M eel/eel-string.h commit 3a02c89ec0329ee6a1b0eab411eb0f95308626aa Author: Cosimo Cecchi Date: 2011-10-05 all: don't use eel_strlen() M src/nemo-location-bar.c M src/nemo-window-slot.c commit fc1479fc3a614b00d0ff69bd1da62d4dee0a9af9 Author: Cosimo Cecchi Date: 2011-10-05 view: use g_str_has_prefix() instead of eel_str_has_prefix() M src/nemo-view.c commit 3daaaf4a9efa2913bbfbadf1492e670b3e83c4a0 Author: Cosimo Cecchi Date: 2011-10-05 all: don't use eel_strcmp() M eel/eel-glib-extensions.c M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-progress-info.c M src/nemo-properties-window.c M src/nemo-window-slot.c commit 96254fec43923e7ef5a3e78604cb3b6935117f91 Author: Cosimo Cecchi Date: 2011-10-05 eel: remove unused eel-gtk-macros.h file M eel/Makefile.am D eel/eel-gtk-macros.h M eel/eel.h M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-clipboard-monitor.c M libnemo-private/nemo-desktop-directory.c M libnemo-private/nemo-desktop-link-monitor.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-entry.c M libnemo-private/nemo-file.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-merged-directory.c M libnemo-private/nemo-module.c M libnemo-private/nemo-query.c M libnemo-private/nemo-search-engine-simple.c M libnemo-private/nemo-tree-view-drag-dest.c M libnemo-private/nemo-undo-manager.c M libnemo-private/nemo-undo-signal-handlers.c M src/nemo-application.c M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-location-bar.c M src/nemo-view.c M src/nemo-window-manage-views.c M src/nemo-window-slot.c commit 68732195bada37da771bab924352ca3864e2bdde Author: Cosimo Cecchi Date: 2011-10-05 view: don't use EEL_ASSIGN/EEL_IMPLEMENT macros for class signals Not that useful since we have full control over all the views. M src/nemo-view.c commit ce34c8c033d09578f7cb17b8531f6afc95555728 Author: Cosimo Cecchi Date: 2011-10-05 view: don't use EEL_INVOKE_METHOD macro M src/nemo-view.c commit 2797c72a906ed6395afd45b9fa7c516d6ef3299f Author: Cosimo Cecchi Date: 2011-10-05 all: don't use EEL_CALL_METHOD* macros M libnemo-private/nemo-directory.c M libnemo-private/nemo-directory.h M libnemo-private/nemo-file.c M src/nemo-view.c M src/nemo-window-slot.c commit 45e3ad0979d79ba017e84a9f99f605ec562c8ae8 Author: Cosimo Cecchi Date: 2011-10-05 icon-view: simplify code by removing pointless method overrides M src/nemo-icon-view.c M src/nemo-icon-view.h commit deb560128734593d9941f4a414e165b3943d61bf Author: Cosimo Cecchi Date: 2011-10-05 all: don't use EEL_CLASS_BOILERPLATE macro M libnemo-private/nemo-vfs-directory.c M libnemo-private/nemo-vfs-file.c commit f0dc94fed68eb5a52d705391053bd642a88ab1d3 Author: Cosimo Cecchi Date: 2011-10-05 all: don't use EEL_CALL_PARENT* macros Replace them with regular calls to the parent class method pointer. M libnemo-private/nemo-desktop-directory.c M libnemo-private/nemo-desktop-link-monitor.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-merged-directory.c M libnemo-private/nemo-module.c M libnemo-private/nemo-query.c M libnemo-private/nemo-search-engine-simple.c M libnemo-private/nemo-search-engine.c M libnemo-private/nemo-tree-view-drag-dest.c M src/nemo-empty-view.c M src/nemo-list-view.c M src/nemo-location-entry.c M src/nemo-view.c commit 785ee926b36165b4849903e5f4828a17aabe534c Author: Cosimo Cecchi Date: 2011-10-04 properties-window: paint the pie backgorund with the notebook color We have to reset the GtkDrawingArea background to the notebook color, in case the theme specifies them to be different. M src/nemo-properties-window.c commit 8b99f1fae29b333c9beeee3dad848099a66e731d Author: Cosimo Cecchi Date: 2011-10-04 properties-window: port the pie chart GtkTable to GtkGrid M src/nemo-properties-window.c commit 0026899cd9f5cd636b4a44ec838e2ec228b210bb Author: Cosimo Cecchi Date: 2011-10-04 properties-window: port GtkTable to GtkGrid Except for the pie chart, which will be ported in a separate commit M src/nemo-properties-window.c commit ac6797687cc3dc77e1fc6752090a7ef037252ade Author: Cosimo Cecchi Date: 2011-10-04 window: port GtkTable to GtkGrid M src/nemo-window-private.h M src/nemo-window.c commit c6903f412d204ce4ab83fa328fe7df3c81781b68 Author: Cosimo Cecchi Date: 2011-10-04 view: port GtkTable to GtkGrid M src/nemo-view.c commit 29dea2e40f6631935a9479c2cf96534308215183 Author: Cosimo Cecchi Date: 2011-10-04 desktop-item-properties: port GtkTable to GtkGrid M src/nemo-desktop-item-properties.c commit 7f3e5ce7786bfdf728169d222ef7584306f2b445 Author: Cosimo Cecchi Date: 2011-10-04 connect-server-dialog: port GtkTable to GtkGrid M src/nemo-connect-server-dialog.c commit 24658f2ba3c9a9dd12416933942370cd6ff6271c Author: Federico Mena Quintero Date: 2011-10-04 Fix confusion in the fallback size for icons Just caught this when reading the code... https://bugzilla.gnome.org/show_bug.cgi?id=660894 M libnemo-private/nemo-icon-info.c commit d8cfe1080a15fd05a306ee3a6adb5767df4fe58f Author: Kristjan SCHMIDT Date: 2011-10-03 Updated Esperanto translation M po/eo.po commit f1aae7bd99efac46a4f7b67beb53205b6cb89f47 Author: Tiffany Antopolski Date: 2011-10-03 Updated Esperanto translation M po/eo.po commit 0c80c23a771da619bfd6858397d10b2446966fa2 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-10-02 po/vi: better translation of "Go" M po/vi.po commit 530bbec3b5d663ca7e3244446d9bc73f1cf323b0 Author: Cosimo Cecchi Date: 2011-09-29 all: remove initiated_unmount logic from NemoWindow We don't really need this, and it makes the behavior way less convoluted. Now we always try to close the current slot on mount remove, except when it would be the last window at all to be closed. M src/nemo-application.c M src/nemo-places-sidebar.c M src/nemo-view.c M src/nemo-window-slot.c commit 269c6b23cf2b97f74a8c7c2654221be491b60cf4 Author: Cosimo Cecchi Date: 2011-09-29 window: add debug messages for pane closing M src/nemo-window-pane.c M src/nemo-window.c commit 379e0883d06f782fb43d32a1b5031f52c5cfc9b4 Author: Cosimo Cecchi Date: 2011-09-29 window: cleanup nemo_window_close_pane() M src/nemo-window-private.h M src/nemo-window.c commit 3ac3935e9d4a9e40b2e889cb16409cadc30bb8dd Author: Cosimo Cecchi Date: 2011-09-29 window-pane: fix switching to the other pane when closing the last slot We're closing a window slot; when it's the last slot to be closed, we used to call nemo_window_split_view_off() on the wrong pane. Even if we called it on the right pane, it wouldn't have worked anyway, because we could have removed the active pane, and that function always assumes going back to it. Also, we need to ensure that active_slot is set on the new pane, or nemo_window_set_active_slot() won't be called to restore the right window state. https://bugzilla.gnome.org/show_bug.cgi?id=652320 M src/nemo-window-pane.c commit f6bbf0f111f344276472aaa54072bf99ae7be9b2 Author: Cosimo Cecchi Date: 2011-09-29 view: don't assert on window slot signal callback ordering There's no reason to assert on the fact that inactive and active signals will be always emitted in alternate state. If this doesn't happen, just return. https://bugzilla.gnome.org/show_bug.cgi?id=652320 M src/nemo-view.c commit 1c06d97c9663ec5b77f21326490146c9a9d8f9d9 Author: Cosimo Cecchi Date: 2011-09-29 places-sidebar: disconnect volume monitor signals on dispose The GIO volume monitor can survive the sidebar, so we need to disconnect its signals handlers on dispose. https://bugzilla.gnome.org/show_bug.cgi?id=652320 M src/nemo-places-sidebar.c commit 1f61da02d767b2a767d1dc2fd8c6714c6f6a60d0 Author: Cosimo Cecchi Date: 2011-09-28 window-slot: don't go through the back list when checking a mount There's no reason the slot shouldn't be closed if one of the locations in the back history belongs to the mount (what we should do is cleaning up that location from the history, which we don't yet). M src/nemo-window-slot.c commit df47a7e142357ff404dceaf43bf3c7ae492fddcc Author: Cosimo Cecchi Date: 2011-09-28 application: avoid useless checks when removing a mount nemo_window_slot_should_close_with_mount() has the same checks and more. M src/nemo-application.c commit d49f23ae211cb24cc43efa68d46f7867dbe26364 Author: Cosimo Cecchi Date: 2011-09-28 window-pane: turn into a GtkBox, simplify code M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit eaa98a76fbc144ff1f14f2df8fb3d6873541465b Author: Cosimo Cecchi Date: 2011-09-28 desktop-link-monitor: plug a memory leak M libnemo-private/nemo-desktop-link-monitor.c commit 0d191f445da18d0bed1c8ca6d3e05dc4ffae4293 Author: Cosimo Cecchi Date: 2011-09-28 window-manage-views: plug a memory leak We have to free the new selection list when we build it ourselves. M src/nemo-window-manage-views.c commit 37386fab28267cdbedd979fff13fe1a9da81014d Author: Cosimo Cecchi Date: 2011-09-28 list-view: don't activate the previewer when there's no selection Or we'll segfault when trying to access the first item of the selection. https://bugzilla.gnome.org/show_bug.cgi?id=654857 M src/nemo-list-view.c commit 3429a6ff153c85a6a65ccb994b4cb4434e4fffcf Author: Cosimo Cecchi Date: 2011-09-28 icon-container: consolidate typeahead entry timeout handling We have crash reports coming from the search entry typeahead code. I can't really reproduce the bug, but there seems to be at least a problem with the typeahead flush timeout returning TRUE and being rescheduled. Refactor the code to better handle the flush timeout, which hopefully solves those crashes as well. https://bugzilla.gnome.org/show_bug.cgi?id=653800 M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-private.h commit 718b8641935b5a8de67e83ec12f9026aecd41e8c Author: Cosimo Cecchi Date: 2011-09-28 window: small code cleanups M src/nemo-window-private.h M src/nemo-window.c commit d3c158d6c9a6ee40fae660ab56b7d8a40074108c Author: Cosimo Cecchi Date: 2011-09-28 window: make sure to disconnect GSettings signals when finalizing The GSettings object survive the window, so handlers connected to its signals should be disconnected when the window is finalized. https://bugzilla.gnome.org/show_bug.cgi?id=655070 M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window.c commit 82a39de7a3c1265ba1a46d1140a084a12b310e32 Author: Cosimo Cecchi Date: 2011-09-28 places-sidebar: don't crash when not finding the eject symbolic icon If a theme doesn't have media-eject-symbolic, icon_info can be NULL, and we would crash trying to load a pixbuf from it anyway. Fix this and show the stock 'missing image' pixbuf when the theme doesn't have the specified icons. https://bugzilla.gnome.org/show_bug.cgi?id=660277 M src/nemo-places-sidebar.c commit 35059bec98b8ede682e582395b889dc149fc7cba Author: МироÑлав Ðиколић Date: 2011-09-28 Updated Serbian translation M po/sr.po M po/sr@latin.po commit f51bad348ab71e3203a7b76c45d307b0fafc5128 Author: Cosimo Cecchi Date: 2011-09-26 release: prepare for 3.2.0 M NEWS M configure.in commit c6299e775ae7770b5b98ede0b70e90ecd04bc742 Author: Cosimo Cecchi Date: 2011-09-26 trivial: fix a critical when opening preferences Just a trivial cleanup for a critical accidentally introduced in commit db72d73b3cd58493b1b8878a52ff8a9f5d350602 M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit 278a92edf777eb3dc623a4284ef4d81af3f77d27 Author: Andrej ŽnidarÅ¡iÄ Date: 2011-09-26 Updated Slovenian translation M po/sl.po commit 34b5833b704e174c82d943b28e59d91e9531fdbc Author: Carles Ferrando Date: 2011-09-26 [l10n]Updated Catalan (Valencian) translation M po/ca@valencia.po commit 2b296a9d0dfba07b62144e96a52368205c447561 Author: Tommi Vainikainen Date: 2011-09-26 Updated Finnish translation M po/fi.po commit 368d49124774c4bf640f617e4fcf86641dd886e7 Author: Seán de Búrca Date: 2011-09-25 Updated Irish translation M po/ga.po commit 544fcac94f70f3f35105bfad3f6dda21197d7378 Author: Andika Triwidada Date: 2011-09-25 Updated Indonesian translation M po/id.po commit dfb8d194bf9ff460b8d6a7a9e3629ab5b343bb46 Author: Lucas Lommer Date: 2011-09-24 Updated Czech translation M po/cs.po commit 5e83b5591ffccef5e9faa8bc384c7ffd59eab05e Author: Lucas Lommer Date: 2011-09-24 Updated Czech translation M po/cs.po commit 55210fff4df1ea8312b9e276f65dd3e22ec406f0 Author: Inaki Larranaga Murgoitio Date: 2011-09-24 Updated Basque language M po/eu.po commit adb9e12825aedee3b71a1bd9bb4589b22f724946 Author: Jiro Matsuzawa Date: 2011-09-23 Updated Japanese translation M po/ja.po commit a2045383fc726c4d11a1ab08837fd97d9d098a3b Author: Claude Paroz Date: 2011-09-22 Cleaned Assamese translation M po/as.po commit f07aa75bf010653bd9e1a5f5519fec8a029763de Author: Cosimo Cecchi Date: 2011-09-22 icon-canvas-item: don't draw pango layouts when renaming Fixes a regression introduced in commit 95910c94fd46f368b66f02e1961dc5f273b38c82 that causes unwanted text to be drawn while renaming a file in icon view. https://bugzilla.gnome.org/show_bug.cgi?id=659831 M libnemo-private/nemo-icon-canvas-item.c commit 2b9b06cfa8bb431f21af74a5f630646df494eb00 Author: Changwoo Ryu Date: 2011-09-23 Updated Korean translation M po/ko.po commit 9023264e0660b50253a9bf7bffe977e0b3a6fd4c Author: Joe Hansen Date: 2011-09-22 Updated Danish translation M po/da.po commit f985fe035500e57bbede9f0dfb252fc0f2569377 Author: Sweta Kothari Date: 2011-09-22 Updated Gujarati Translations M po/gu.po commit b8238d4a89de55a2e93af7f2aee15cf4148625a6 Author: Gabor Kelemen Date: 2011-09-19 Updated Hungarian translation M po/hu.po commit 2cb91c05718dc5463a52eadf24e6036adfe6e10e Author: Cosimo Cecchi Date: 2011-09-19 icon-canvas-item: don't forget to clip the embedded text rectangle When drawing the embedded text, the pango layout should be clipped to the computed rectangle. https://bugzilla.gnome.org/show_bug.cgi?id=659518 M libnemo-private/nemo-icon-canvas-item.c commit bf1f6bde79f5226388551780dcd7f148c8f55734 Author: Cosimo Cecchi Date: 2011-09-19 release: prepare for 3.1.92 M NEWS M configure.in commit 0a32dd8da8b2a9d10189ef6c8865bb4ec2ca345f Author: Cosimo Cecchi Date: 2011-09-19 users-group-cache: nuke this, as it appears to be unused M libnemo-private/Makefile.am M libnemo-private/nemo-file.c D libnemo-private/nemo-users-groups-cache.c D libnemo-private/nemo-users-groups-cache.h commit b11c8a69479b5307d946dbc5742baf5cca75ae06 Author: Mike Gorse Date: 2011-09-16 Fix accessibility for gtk 3.2, and send object:state-changed:selected The code to derive the EelCanvasAccessible class no longer works as of gtk+ 3.1.9. Currently the recommended behavior is to derive from GtkAccessible. Also, canvas items should send object:state-changed:selected events when selected and unselected; otherwise AT-SPI will not update its cache. https://bugzilla.gnome.org/show_bug.cgi?id=650897 M eel/eel-canvas.c M eel/eel-canvas.h M libnemo-private/nemo-icon-canvas-item.c commit f83324a05375ba1aa97d3e6ea91f4af323f2bd2c Author: Aurimas ÄŒernius Date: 2011-09-18 Updated Lithuanian translation M po/lt.po commit 5d549140c95ebb9e7c5cdf5d7d639cca36a22021 Author: Lê Hoàng Phương Date: 2011-09-18 po/vi.po: changed Bookmark translation from "Liên kết lưu" to "Äánh dấu" M po/vi.po commit 0d1300c2c0790ea510a9253314e0c1f92e241843 Author: Nguyá»…n VÅ© Hưng Date: 2011-09-18 Updated Vietnamese translation M po/vi.po commit 4016176dc43e4c502714d7544000dbed64c95dfe Author: Theppitak Karoonboonyanan Date: 2011-09-18 Updated Thai translation. M po/th.po commit 92e3aded0c213d33e6bbe39f4a9258f4a50a0f7c Author: Ville-Pekka Vainio Date: 2011-09-17 Updated reduced Finnish translation M po/fi.po commit c408390df407fa4b90d4d8bf49a26401ec908512 Author: Ihar Hrachyshka Date: 2011-09-17 Updated Belarusian translation (some fixes after manual testing). M po/be.po commit 8fc72b1b9122cd3dec7c40c2d8f3b24a5038ae46 Author: Alexander Shopov Date: 2011-09-17 Updated Bulgarian translation M po/bg.po commit c0f1c0988790e458351a3e6f6a9bdc494efc0797 Author: Antonio Fernandes C. Neto Date: 2011-09-17 Updated Brazilian Portuguese translation M po/pt_BR.po commit 4fde92db8333dfdb708f57e9b69d3fa74f511663 Author: Joan Duran Date: 2011-09-17 [l10n]Updated Catalan translation M po/ca.po commit 3956b5c163d1b6beda14ab3d47bf78653208c106 Author: Jiro Matsuzawa Date: 2011-09-17 Updated Japanese translation M po/ja.po commit d477edb640c0aa58550e43992fb788f54b2ec700 Author: Mario Blättermann Date: 2011-09-16 [l10n] Updated German translation M po/de.po commit c97c17c4970cb9ae9c38685005995abe2a880921 Author: Daniel Korostil Date: 2011-09-16 Uploaded Ukranian M po/uk.po commit a046d86cd13431eef4bae743c0ca505dffaecca0 Author: dmustieles Date: 2011-09-14 Updated Spanish translation M po/es.po commit cb9d902fccbc462253d60d9a39fa5ee2cce1af7d Author: Yinghua Wang Date: 2011-09-13 update Simplified Chinese (zh_CN) translation M po/zh_CN.po commit 67743ffbc62abeb2bb3511901c95fb57d4ee9d93 Author: Yinghua Wang Date: 2011-09-13 update Simplified Chinese (zh_CN) translation M po/zh_CN.po commit 78be87bc843f71670b41011b645f983bab6ba81d Author: Cosimo Cecchi Date: 2011-09-12 desktop: ensure the desktop metadata is up to date when setting as ready As part of the I/O machinery cycle internal to call_when_ready nemo_file_clear_info() can be called and clear the metadata we previously set during _init. Move the desktop metadata initialization before returning the file as ready, so it's always up to date when the view reads the settings. https://bugzilla.gnome.org/show_bug.cgi?id=655561 M libnemo-private/nemo-desktop-directory-file.c commit 6775e582bcd332eaed925f41555fe4e5c0a3dd71 Author: Cosimo Cecchi Date: 2011-09-12 file: read the emblem icon names from metadata Support for the metadata::emblems got lost during the 3.0 development, re-add support for it. M libnemo-private/nemo-file.c commit 97802bc3f6cfbd464eae6e4375cc8f7d71a218af Author: Cosimo Cecchi Date: 2011-09-12 window-manage-views: scroll to the selected location when opening an URI When opening nemo with a preselected URI, scroll the window to that location in addition to selecting the view element. https://bugzilla.gnome.org/show_bug.cgi?id=658843 M src/nemo-window-manage-views.c commit 3add5865157f6eb66ddf5729ffdf3102c020cc10 Author: Dr.T.Vasudevan Date: 2011-09-12 updated Tamil translation M po/ta.po commit d82cd5965c246173c3f8e3ce39fdde740592259e Author: Rudolfs Mazurs Date: 2011-09-11 Updated Latvian translation. M po/lv.po commit e7c643cea5a4455d34954edfad24ca62dd585156 Author: Jorge González Date: 2011-09-11 Updated Spanish translation M po/es.po commit 7fe6d3d2a4fe48d58afba8c0ee8e40fe60c5d63b Author: Cosimo Cecchi Date: 2011-09-10 tree-sidebar: don't block the parent handler when popping up a menu Otherwise the treeview will not select the row where the event happened. https://bugzilla.gnome.org/show_bug.cgi?id=601725 M src/nemo-tree-sidebar.c commit bc236c95df0b3362b4e51a404bd89e13062afa49 Author: Arash Mousavi Date: 2011-09-10 Updated Persian translation M po/fa.po commit 8873abff5de2fd8039ba52e60a835444527f7349 Author: Duarte Loreto Date: 2011-09-10 Updated Portuguese translation M po/pt.po commit a465c3b91dfadbfb590adc42fee18aaa1b61d9fc Author: Jiro Matsuzawa Date: 2011-09-10 Updated Japanese translation M po/ja.po commit 8d5e8502862f93a188a848ca79779db09e4abf85 Author: A S Alam Date: 2011-09-10 update PunjabiTranslation M po/pa.po commit d56fd8f591b3909ef58d7e191afb400de7a8f75f Author: Kristjan SCHMIDT Date: 2011-09-09 Updated Esperanto translation M po/eo.po commit 99ad534b7b2fae3fdfa15345cbeae01da5dda803 Author: Javier Jardón Date: 2011-09-09 Make maintiner mode enabled by default See http://blogs.gnome.org/desrt/2011/09/08/am_maintainer_mode-is-not-cool/ M configure.in commit a64ac652e217cfd9809f669453da6577a198ae37 Author: Yaron Shahrabani Date: 2011-09-09 Updated Hebrew translation. M po/he.po commit 2f064e560cf949b1e1bc4448eaa277f8e05180d8 Author: David Liang Date: 2011-09-09 icon-container: invalidate the layout cache on style-updated This way label sizes will be recomputed if e.g. DPI settings change. https://bugzilla.gnome.org/show_bug.cgi?id=578468 M libnemo-private/nemo-icon-container.c commit c0e6ac365cd4d4d4add0db1edf6f7506bd85e57f Author: Matthias Clasen Date: 2011-09-09 file-operations: ignore ALREADY_MOUNTED errors when mounting Don't spawn an error dialog in this case. https://bugzilla.gnome.org/show_bug.cgi?id=579645 M libnemo-private/nemo-file-operations.c commit a78d885027d6a49d712b5589fd79c822edf4e17d Author: Cosimo Cecchi Date: 2011-09-08 search-directory: stop the engine when there are no active monitors My understanding of this code suggests the engine should be stopped as soon as the active monitors reach zero. This fixes the Stop button not working while searching anyway, and doesn't seem to cause any collateral damage. https://bugzilla.gnome.org/show_bug.cgi?id=563163 M libnemo-private/nemo-search-directory.c commit fdf0036ca9fbb17b97aefabd95f994190cdc0bac Author: Piotr DrÄ…g Date: 2011-09-08 Updated Polish translation M po/pl.po commit 226595c7ed30e21247d07a063dd7d1f9221306ed Author: Luca Ferretti Date: 2011-09-08 l10n: Updated Italian translation M po/it.po commit 920aa3d94be890f241d3be415540dbde6a81df0a Author: Cosimo Cecchi Date: 2011-09-08 tracker: always reset the cancellable when starting a query Otherwise we can start a query with a cancelled object already, making it fail immediately. M libnemo-private/nemo-search-engine-tracker.c commit ee73c255d75165607c7f04defd5e8edfa3524914 Author: Cosimo Cecchi Date: 2011-09-08 window: make sure not to unref NULL GFiles The GFile pointed by parent here can be NULL after the cycle, so fold the unref in the != NULL block. M src/nemo-window-manage-views.c commit 88b08d691c17b9686938a0b20a37a19ac99cacc3 Author: Cosimo Cecchi Date: 2011-09-08 all: remove is_indexed property on NemoSearchDirectory It doesn't really make sense to artificially change the query target if we're indexed. M libnemo-private/nemo-search-directory.c M libnemo-private/nemo-search-directory.h M libnemo-private/nemo-search-engine-simple.c M libnemo-private/nemo-search-engine-tracker.c M libnemo-private/nemo-search-engine.c M libnemo-private/nemo-search-engine.h M src/nemo-query-editor.c M src/nemo-query-editor.h M src/nemo-window-pane.c M src/nemo-window-slot.c commit aef4bf26ed8b48f6519fec9531bb530783193447 Author: Cosimo Cecchi Date: 2011-09-08 tracker: respect the location URI when searching with tracker M libnemo-private/nemo-search-engine-tracker.c commit a65eb16241ea0e64e5bf2547ffdaebcaa4547574 Author: Claude Paroz Date: 2011-09-08 Updated French translation M po/fr.po commit 6f4d215dd9df1b3b0c7fb4714fda88bc2ef39590 Author: Bruce Cowan Date: 2011-09-08 Updated British English translation M po/en_GB.po commit 92e40dd094a812db6bcc3e60c0830d20b3f07b15 Author: Cosimo Cecchi Date: 2011-09-08 window: steal all accelerators/mnemonics keybindings when renaming If we're renaming, we really want to ignore all the accelerators and mnemonics coming from NemoWindow and NemoView, as they might conflict with the regular bindings expected in an editable widget, such as an editable GtkCellRendererText or EelEditableLabel. This should fix all the recent keybinding-related regressions, such as https://bugzilla.gnome.org/show_bug.cgi?id=658105 https://bugzilla.gnome.org/show_bug.cgi?id=651574 M src/nemo-window.c commit a67212a39bbcd342f0a503d693ebd80fab48ac9c Author: Cosimo Cecchi Date: 2011-09-08 view: add an is_renaming property to NemoView And keep it in sync with the renaming widget. This will be useful to forward events to the view if it's renaming. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-view.c M src/nemo-view.h commit 88b535828ddacd7ec2313d52a21f164aee535fa3 Author: Cosimo Cecchi Date: 2011-09-08 Revert "window: reverse the order of key-press event processing" This reverts commit f76c50a0e46aa7786820f76b3f71b57b44b8d7fb. M libnemo-private/nemo-icon-container.c M src/nemo-list-view.c M src/nemo-window.c commit c55fa6b75ba623b327975fdaa37d5a8e6669e7ac Author: Cosimo Cecchi Date: 2011-09-08 build: fix optional dependency check on libtracker-sparql Commit ffc7c7f98901e8a319b91716d05e521a798dbe43 didn't really work in the case where no tracker was found on the system, really forcing a build dependency. Fix this. https://bugzilla.gnome.org/show_bug.cgi?id=658545 M configure.in commit 8d8979f53cea0e8e48faa9ffba82950013e18ad0 Author: Cosimo Cecchi Date: 2011-09-07 icon-dnd: remove hardcoded highlight frame The call to gtk_render_frame() should be enough; the problem is with Adwaita which does not define a CSS style for the "dnd" class. M libnemo-private/nemo-icon-dnd.c commit 7732a6b35369c1cef56351cc491358c2f6623c5e Author: Cosimo Cecchi Date: 2011-09-07 icon-canvas-item: render the additional text with gtk_render_layout() And add a style class for it. M libnemo-private/nemo-icon-canvas-item.c commit ffc7c7f98901e8a319b91716d05e521a798dbe43 Author: Cosimo Cecchi Date: 2011-09-07 tracker: make the tracker-sparql dependency optional This way it's still possible to specify --enable-tracker=no from the configure line if you want to avoid the tracker dependency. M configure.in M libnemo-private/Makefile.am M libnemo-private/nemo-search-engine.c commit b3da52fefdbf5dc6f8f95fe381181dc47e54d5c3 Author: Stefano Teso Date: 2011-09-07 file: make sure not to use a 0 width/height when scaling the image The problem is that for extreme height-to-width ratio images, gdk_pixbuf_scale_simple () is called with either width or height = 0 (printing a critical warning to the terminal). https://bugzilla.gnome.org/show_bug.cgi?id=329010 M libnemo-private/nemo-file.c commit f1dd42ec1c86e78fa894c07ee6b0c8df60d45acb Author: Cosimo Cecchi Date: 2011-09-07 tracker: use libtracker-sparql directly It's not a problem for nemo to depend on libtracker-sparql here instead of using g_module_open() M configure.in M libnemo-private/nemo-search-engine-tracker.c commit 402b281790c1bca3fc10010008cb1ac6fb997b59 Author: Pavlos Touboulidis Date: 2011-04-11 list-view: Fix default sort order. Removed the extra "uri" element from the sort order mapping array because the settings enum values were being mapped to the wrong strings. https://bugzilla.gnome.org/show_bug.cgi?id=647491 M src/nemo-list-view.c commit ad5b834df34d6a8f3919909b63ce97cc2bda53d4 Author: mads@kiilerich.com Date: 2011-09-07 nemo-autorun-software: handle mime type x-content/unix-software only This is a consequence of the fix for https://bugs.freedesktop.org/show_bug.cgi?id=20562 . This undoes the part of cffb9cf7025 that hardcodes that media with x-content/win32-software are silently ignored, and thus improves on the fix for #524270. Wine or something could now provide a handler for win32-software. https://bugzilla.gnome.org/show_bug.cgi?id=632510 M data/nemo-autorun-software.desktop.in.in M src/nemo-autorun-software.c commit 8978c6375bbe0cd26fffded25bc4606cab2c88e6 Author: Phillip Berndt Date: 2011-02-16 nemo-autorun-software: Use /bin/sh for autorun.sh execution If the autorun file is called autorun.sh it is clearly meant for execution through a sh processor. The benefit of using /bin/sh as the executable is that autorun will also work on FAT formatted media (which does not allow autorun.sh to have +x permission set) https://bugzilla.gnome.org/show_bug.cgi?id=642511 M src/nemo-autorun-software.c commit d1bc9311392e243aa5c9af4b80a373b6dd69d741 Author: Sandro Mani Date: 2011-09-07 mime-actions: don't spawn a warning if we have only one application Don't show a confirmation dialog when we're opening a number of files with the same application. https://bugzilla.gnome.org/show_bug.cgi?id=649811 M src/nemo-mime-actions.c commit 571a6ef755a6190d442739589b686401d75ff40b Author: Tomas Bzatek Date: 2011-04-15 connect-server-dialog: Respect password save setting The "Remember this password" checkbox was not respected when password was specified and connection succeeded for the first time. https://bugzilla.gnome.org/show_bug.cgi?id=641376 M src/nemo-connect-server-dialog.c commit 0ae354ce50394d18be01ca670fdf190d63c1591e Author: Cosimo Cecchi Date: 2011-09-07 search-bar: use gtk_entry_set_icon_from_icon_name() Now that we have an image style class for entry icons, we can style the symbolic color from the theme instead of rendering this manually. This also has the side effect of fixing bugs like https://bugzilla.gnome.org/show_bug.cgi?id=651209 M src/nemo-search-bar.c commit 37e379a5a484b604bd25f0b4cb3269f6e4c942ba Author: Michael Terry Date: 2011-06-29 Look at XDG_CURRENT_DESKTOP to decide if a link is foreign https://bugzilla.gnome.org/show_bug.cgi?id=653660 M libnemo-private/nemo-link.c commit 637289f74536ed2f31e05604401203a9360c439f Author: Michael Terry Date: 2011-06-29 Add Unity to OnlyShowIn https://bugzilla.gnome.org/show_bug.cgi?id=653657 M data/nemo.desktop.in.in commit cbadf49a82c70bb6ef90d63fdc4b43f4cb108598 Author: Cosimo Cecchi Date: 2011-09-07 css: remove custom CSS stylesheet Our custom CSS stylesheet is actually very tied to Adwaita. We don't want to force this style to other GTK+ themes, so the theming information has been moved to Adwaita itself. M data/Makefile.am D data/nemo.css M src/nemo-application.c commit ca7f81e2e9adf325effa11fc55aace4a087ab61b Author: Cosimo Cecchi Date: 2011-09-07 icon-container: use the "rubberband" style class for the selection item Instead of using a custom style property. M data/nemo.css M libnemo-private/nemo-icon-container.c commit 8b676a68b698b705a6008c89d53fded1cf635981 Author: Cosimo Cecchi Date: 2011-09-07 desktop: add a nemo-desktop style class to the desktop canvas So that themes can tweak the color/background of desktop canvas items separately. M libnemo-private/nemo-icon-container.c commit 22707fdc469dfc7548adc8020e3aaf63b20ae1bf Author: Cosimo Cecchi Date: 2011-09-07 eel: remove unused eel_cairo_draw_layout_with_drop_shadows() M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 77eecef417b91bb0c48588513de473f11a5c9896 Author: Cosimo Cecchi Date: 2011-09-07 icon-container: remove unused code caching canvas item colors Caching colors in NemoIconContainer to use them in the canvas item is not needed anymore, as gtk_render_* fetches the right values directly from the style context. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-private.h commit 95910c94fd46f368b66f02e1961dc5f273b38c82 Author: Cosimo Cecchi Date: 2011-09-07 icon-canvas-item: use gtk_render_* methods instead of direct cairo Instead of hardcoding colors and using direct cairo calls to draw the canvas items frame/background/labels, use gtk_render_* methods directly. This has the advantage of making them more friendly with GTK+ themes (by adding a nemo-canvas-item style class to the canvas context when drawing) and removes a ton of convoluted cairo drawing code. M libnemo-private/nemo-icon-canvas-item.c commit 483f13c18f55e489bc15ad266d5612edf96ad95a Author: Matej UrbanÄiÄ Date: 2011-09-07 Updated Slovenian translation M po/sl.po commit 5b09cedf434b53a975074b346d511335fc735cba Author: Rui Matos Date: 2011-08-08 list-view: explicitly set cursor on file name cell renderer on rename The file name column has two cell renderers, one for the icon and another for the name string. Thus, gtk_tree_view_set_cursor() isn't enough to reliably start editing the file name cell since it will try to edit whatever is the currently focused cell in the column. https://bugzilla.gnome.org/show_bug.cgi?id=656128 M src/nemo-list-view.c commit b20d9570c840f696eae5216652d93540bcfdc6db Author: Cosimo Cecchi Date: 2011-09-07 floating-bar: remove some unused code M src/nemo-floating-bar.c commit 00b108c687408db87ebb617186aa8fa62f35c7de Author: Luke Symes Date: 2011-07-16 Don't hide the floating-bar on hover if it is interactive If there are actions set on the floating bar, avoid escaping the pointer. https://bugzilla.gnome.org/show_bug.cgi?id=654558 M src/nemo-floating-bar.c M src/nemo-window-manage-views.c commit 3f892611ab497180fae677abd6520e4cd387877f Author: Stas Solovey Date: 2011-09-07 Updated Russian translation M po/ru.po commit a21d27b66fa307adaf87918f5feb2be44d52fdca Author: Cosimo Cecchi Date: 2011-09-07 places-sidebar: don't manually highlight the symbolic eject icon Set the right style class and state when rendering the icon, so the theming engine can fetch the right color from the theme and color the symbolic icon automatically. M src/nemo-places-sidebar.c commit 1eaae29320deb8dc6f218c13584aac5bbb66acd1 Author: Ihar Hrachyshka Date: 2011-09-07 Updated Belarusian translation. M po/be.po commit 407e426fcd2413a5a27e8bbc9f455da9e3fbbe59 Author: Kjartan Maraas Date: 2011-09-06 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 62bb5efc592a1241bfb0ca5c3773eb8ad899cbcc Author: Chao-Hsiung Liao Date: 2011-09-06 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit fa72a893c4e8558d94c22cb9ed3ed6c417eb265f Author: Daniel Nylander Date: 2011-09-05 Updated Swedish translation M po/sv.po commit 2d66b738054eb27a0f624be5a4a76d038c907b4d Author: Jorge González Date: 2011-09-05 Updated Spanish translation M po/es.po commit 8478047a09576891e30d87232d332da244c8a518 Author: Fran Dieguez Date: 2011-09-05 Updated galician translations M po/gl.po commit 4060b9ee98bb080383e4d973c7ae5be1a515f785 Author: Shaun McCance Date: 2011-09-02 Update help targets and add more useful entries to help menu M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog.c M src/nemo-file-management-properties.c M src/nemo-properties-window.c M src/nemo-shell-ui.xml M src/nemo-view.c M src/nemo-window-menus.c commit 156f61454a06dddadb82990bfd4d287729352ece Author: Ihar Hrachyshka Date: 2011-09-04 Updated Belarusian translation. M po/be.po commit 80d2046dd0df5719daa6ce9b702f0c0265eb7044 Author: André Gondim Date: 2011-09-03 Updated Brazilian Portuguese translation, reviewed by Antonio Fernandes C. Neto . M po/pt_BR.po commit c687d66e473f7094c6af552a69d14d81ae4c3baf Author: Aurimas ÄŒernius Date: 2011-09-03 Updated Lithuanian translation M po/lt.po commit af0022fc388a587726f1186bbe131c666e4d50a3 Author: Tomas Bzatek Date: 2011-09-02 previewer: Fix leaked GError M src/nemo-previewer.c commit e75ff65bc233eaaff108329376ff04b007422668 Author: Stas Solovey Date: 2011-08-31 Updated Russian translation M po/ru.po commit db72d73b3cd58493b1b8878a52ff8a9f5d350602 Author: Vincent Untz Date: 2011-08-30 all: Remove preferences about sound previewing The code was removed, so no need to keep the preference. https://bugzilla.gnome.org/show_bug.cgi?id=657718 M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo.convert M libnemo-private/org.gnome.nemo.gschema.xml.in M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit 3c5cc30d554e641d6013ef196b1a2d7c9424fa41 Author: Cosimo Cecchi Date: 2011-08-29 release: prepare for 3.1.90 M NEWS M configure.in commit 3d44be7ced5267143b3eb2ffcf7118c4fec3a199 Author: Andika Triwidada Date: 2011-08-18 Updated Indonesian translation M po/id.po commit 2d3ba922514b5b5aa5db01214b0dd183a2fdb8e2 Author: A S Alam Date: 2011-08-18 update translation for Punjabi M po/pa.po commit cfb84e3f7e44b0d752541ece747cec0066f0cea9 Author: Theppitak Karoonboonyanan Date: 2011-08-14 Updated Thai translation. M po/th.po commit 945f5bfaf3abbeaf963675ffd5d476cbefde8d74 Author: Piotr DrÄ…g Date: 2011-08-12 Updated Polish translation M po/pl.po commit 7f580504c1fc5904636b9314feab5d5f881a0ea5 Author: Alexander Shopov Date: 2011-08-10 Updated Bulgarian translation M po/bg.po commit a1830fad48e6f5769aab40917f44ebc8447501d4 Author: Kjartan Maraas Date: 2011-08-10 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 484117c8383a655e0c33e1206c6eb09a35692ead Author: Hendrik Knackstedt Date: 2011-08-05 [l10n] Updated German translation M po/de.po commit 99d7f0867eacde30502c5e7d4a074bed5d046dd6 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-08-03 po/vi.po: fix "free space" translation M po/vi.po commit c997bbe8b8bfb423d03f3475088a983e59bd9168 Author: Cosimo Cecchi Date: 2011-07-31 all: remove the built-in hover audio previewer This is not really useful anymore now that we have Sushi, which is way more powerful. M icons/Makefile.am D icons/audio.svg M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-private.h M src/Makefile.am D src/nemo-audio-mime-types.h M src/nemo-icon-view.c commit 065cecec33baf0f8e181da25313cb8030db4da18 Author: Cosimo Cecchi Date: 2011-08-01 application: call Close() on the previewer when there are no windows When the last window is removed from the application object, close the previewer too. M src/nemo-application.c commit f05eaaad2ef96338622c035696148be852c4aca0 Author: Cosimo Cecchi Date: 2011-08-01 previewer: add a wrapper for the Close() remote method M src/nemo-previewer.c M src/nemo-previewer.h commit 60a31b50c2231f9e9f0d624f2ee9cff4800655db Author: Cosimo Cecchi Date: 2011-08-01 previewer: call methods directly on the GDBusConnection Initialize the DBus connection in the constructor and call methods directly on it, instead of keeping the proxy around. M src/nemo-previewer.c commit d0573ec843e73b2832ccc64c08b21c6083526fd9 Author: Lê Trưá»ng An Date: 2011-07-24 Updated Vietnamese translation M po/vi.po commit 2b684e6ea35682ab6e636ca8723fb5d4f5104307 Author: Bruno Brouard Date: 2011-07-31 Updated French translation M po/fr.po commit a1949a8980d0d932ef8effebf44d10e4727cbeb2 Author: Djavan Fagundes Date: 2011-07-28 Fixed a string in Brazilian Portuguese translation M po/pt_BR.po commit f486646784ab6cf519fc9168629b40ca8259655a Author: Henrique P. Machado Date: 2011-07-27 Fixed a string in Brazilian Portuguese translation M po/pt_BR.po commit a000844b5a6039375b0e4176dd4c0f7083b46cb7 Author: Cosimo Cecchi Date: 2011-07-27 thumbnails: make sure to cache all mime types from gdk-pixbuf G_N_ELEMENTS() does not work for heap-allocated arrays, and always returns 1, so we were not actually caching all the supported mime types for a specific pixbuf loader after the first. This should also fix nemo not thumbnailing e.g. compressed SVG images, as reported in [1]. [1] https://bugzilla.gnome.org/show_bug.cgi?id=655406 M libnemo-private/nemo-thumbnails.c commit 0ee113dc1c5affda3eabf73b4c70c77456509d20 Author: Cosimo Cecchi Date: 2011-07-25 release: prepare for 3.1.4 M NEWS M configure.in commit 475ed89d6e6ac99f46700babd16671f88bd1386c Author: Didier Roche Date: 2011-07-25 Remove "Create Launcher" entry option "Create launcher" entry from nemo seems weird as nemo doesn't draw the desktop for GNOME Shell, and this rely on a gnome-panel binary. This brings inconsistency between the two sessions. https://bugzilla.gnome.org/show_bug.cgi?id=654848 https://bugs.launchpad.net/bugs/723861 M src/nemo-actions.h M src/nemo-desktop-icon-view-ui.xml M src/nemo-desktop-icon-view.c M src/nemo-directory-view-ui.xml M src/nemo-view.c M src/nemo-view.h commit 3caf41765453c3c4cf9a73aae87b185d099598f9 Author: Antoine Jacoutot Date: 2011-06-20 Turn nemo_window_close() into a virtual method. nemo_window_close() is now a virtual method that will behaves according to NemoWindowClass: it won't do anything if the window is a NemoDesktopWindow (i.e. it won't close it) which would prevent desktop icons from disappearing. nemo_application_close_all_windows() will now skip hiding windows but close them right away. https://bugzilla.gnome.org/show_bug.cgi?id=652724 M src/nemo-application.c M src/nemo-desktop-window.c M src/nemo-window.c M src/nemo-window.h commit 2bbbc01dc6429e948aed0bbf077e1b77880352ee Author: Antoine Jacoutot Date: 2011-07-15 Move the 'File System' shortcut down the list in the sidebar. Users access more often the XDG dirs than the root filesystem, so it makes sense to move it below. https://bugzilla.gnome.org/show_bug.cgi?id=654681 M src/nemo-places-sidebar.c commit 8686479b2be23735caec35c401d24db499cb2f2c Author: Cosimo Cecchi Date: 2011-07-21 icon-names: use 'drive-harddisk-system' as File System icon Now that it has been added to gnome-icon-theme-extras. https://bugzilla.gnome.org/show_bug.cgi?id=620085 M libnemo-private/nemo-icon-names.h commit 3f42d04301d9a8fcf43f176d1e601356489eb84f Author: Cosimo Cecchi Date: 2011-07-21 window: remove 'Clear History' from the 'Go' menu This is a leftover from the past, when we used to have a global history list. Now that Nemo is not persistent and we don't have that anymore, it doesn't really make sense to keep this menu item. https://bugzilla.gnome.org/show_bug.cgi?id=654422 M src/nemo-shell-ui.xml M src/nemo-window-menus.c M src/nemo-window.c M src/nemo-window.h commit 75960497c6c8e657f010aef7d2bbbf1fda19c4ad Author: Cosimo Cecchi Date: 2011-07-21 location-bar: don't pack an useless box in the bar The bar is an horizontal box already, no need to pack another hbox in it. This also fixes content not expanding in the available width, as noted in https://bugzilla.gnome.org/show_bug.cgi?id=654389. M src/nemo-location-bar.c commit 283e9b32cae61b5501ece85d1dacb1e1c29c4b85 Author: Cosimo Cecchi Date: 2011-07-21 file: use g_format_size_full instead of printf-ing the long string Now that GLib has g_format_size_full(), we can easily format the long string (e.g. 45MB (45,123,456 bytes)) using it, instead of our custom printf function. M libnemo-private/nemo-file.c commit 3e69fb702393cf42486321c88cede4668329b4c8 Author: Ryan Lortie Date: 2011-07-20 all: switch to g_format_size() g_format_size_for_display() has been deprecated in GLib and replaced with g_format_size(). Follow that change. https://bugzilla.gnome.org/show_bug.cgi?id=654995 M configure.in M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file.c M src/nemo-properties-window.c M src/nemo-view.c commit 2160de69245ad15826f6aed1a5ef15455d7851d0 Author: Cosimo Cecchi Date: 2011-07-14 a11y: remove some unused code M eel/eel-accessibility.c M eel/eel-accessibility.h commit a7bd0741e0772f3b143e5c1d77860cce8f3d9872 Author: Ihar Hrachyshka Date: 2011-07-14 Updated Belarusian translation. M po/be.po commit 227ccadc10af524ad1104d36c1343f26be55cf67 Author: Rudolfs Mazurs Date: 2011-07-13 Updated Latvian translation. M po/lv.po commit 613f7180ca741b201e5933d1ebf41fe811a722b4 Author: Abduxukur Abdurixit Date: 2011-07-07 Added UG translation M po/ug.po commit 4d68a3bbab0e6157f83c90288b58bdfebace63c2 Author: Muhammet Kara Date: 2011-07-06 Updated Turkish translation M po/tr.po commit fb45c737e0f7080bd0f51c532311b942a20e38a1 Author: Muhammet Kara Date: 2011-07-06 Fixed a few funny errors in Turkish translation M po/tr.po commit 614b7d3b2b7d09dc4bf19a51ae56a2a087212c99 Author: Muhammet Kara Date: 2011-07-03 Updated Turkish translation M po/tr.po commit 391d537f224204803ef8b50344892166cd9808fa Author: Kjartan Maraas Date: 2011-07-02 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 5817e7ad138f053c80d9257693dbacccb88eecbf Author: Cosimo Cecchi Date: 2011-07-01 release: prepare for 3.1.3 M NEWS M configure.in commit 34bbbc57864e454bdddcc59f322bf06b56254ef6 Author: Cosimo Cecchi Date: 2011-07-01 all: remove some unneeded includes M eel/eel-gtk-extensions.c M libnemo-private/.gitignore M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-tree-view-drag-dest.c M src/.gitignore commit 5c6950277332ca53fceb27d58fa3f06101737726 Author: Cosimo Cecchi Date: 2011-07-01 all: use g_cclosure_marshal_generic() instead of generating marshallers M eel/Makefile.am M eel/eel-canvas.c M eel/eel-editable-label.c M libnemo-private/Makefile.am M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-tree-view-drag-dest.c M src/Makefile.am M src/nemo-query-editor.c M src/nemo-view.c M src/nemo-window.c commit 922307d634a0401c8cc29bee70c6335b2eb9a17c Author: Cosimo Cecchi Date: 2011-06-28 build: bump GTK+ dep to 3.1.6 We need it for GtkOverlay. M configure.in commit eb8ba09e82cbf7045d75a638ef69318e65a8a75f Author: Ihar Hrachyshka Date: 2011-06-28 Updated Belarusian translation. M po/be.po commit 49db9b14ed4e08887e4dc3e5e4cd4c184f48d4ad Author: Ihar Hrachyshka Date: 2011-06-26 Updated Belarusian translation. M po/be.po commit ff6b4f64ab2499e149d2d75e812b2e6e40d68156 Author: МироÑлав Ðиколић Date: 2011-06-25 Updated Serbian translation M po/sr.po M po/sr@latin.po commit 6ac24b5381c7a26f85b8c72662c9ac4a54269e26 Author: Cosimo Cecchi Date: 2011-06-21 application: make sure --no-default-window works when used with an URI M src/nemo-application.c commit ffd2125b13ac591428cf73ac3c0021849d36058a Author: Daniel Nylander Date: 2011-06-20 Updated Swedish translation M po/sv.po commit ea4609ff6123798edf93b0e54b8b03a2fda94fce Author: Gabor Kelemen Date: 2011-06-19 Fix an inconsistency and a too long button M po/hu.po commit 95d45f1994795942774b039ba0de6933d9ffa5c7 Author: Paolo Borelli Date: 2011-06-18 Fix gobject warning about nonexisting property NemoDesktopWindow does not have an "app" propety anymore. M src/nemo-application.c M src/nemo-desktop-window.c M src/nemo-desktop-window.h commit 4c37f5a1c1c7861b45359e36a5efd868cf3f3bb0 Author: Cosimo Cecchi Date: 2011-06-16 all: don't return a reference when getting the application singleton This simplifies the code a bit. Also, remove the useless "app" property on NemoWindow while we're at it. M src/nemo-application.c M src/nemo-application.h M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-location-bar.c M src/nemo-main.c M src/nemo-places-sidebar.c M src/nemo-progress-ui-handler.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit 2b9ebd30e880733d3f40430d1d022ae2f8a4bf77 Author: krishnababu k Date: 2011-06-15 Corrections in Telugu file M po/te.po commit 296ef2be9726185ee08552d3e8bb17d2a98a40b7 Author: Paolo Borelli Date: 2011-06-05 Add "Add Bookmark" to the sidepane context menu https://bugzilla.gnome.org/show_bug.cgi?id=651931 M src/nemo-places-sidebar.c commit 67482b37c8b6581262da28798b6b4e36419b4852 Author: krishnababu k Date: 2011-06-15 Updated Telugu Translations M po/te.po commit aa3eff54fcab36a1fab561ec8527608e12a1496b Author: Cosimo Cecchi Date: 2011-06-13 overlay: remove unused gedit-overlay-child D src/gedit-overlay-child.c D src/gedit-overlay-child.h commit 17b2ff9b002498b8e6ce28c7bf846b0daf3ce206 Author: Cosimo Cecchi Date: 2011-06-13 release: update for 3.1.2 M NEWS M configure.in commit 63e37acc17900e81605b994e8d4e6dd59f1769da Author: Cosimo Cecchi Date: 2011-06-13 floating-bar: fix background/frame rendering M src/nemo-floating-bar.c commit 752ab2718ba4f7e968678facfd8dd0ea6b0e4b26 Author: Cosimo Cecchi Date: 2011-06-13 css: cleanup the CSS file a bit M data/nemo.css commit a28a89ab8112a5207d5413e5f767f191d1d13339 Author: Cosimo Cecchi Date: 2011-06-13 floating-bar: port to GtkOverlay M src/Makefile.am D src/gedit-overlay.c D src/gedit-overlay.h M src/nemo-floating-bar.c M src/nemo-floating-bar.h M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit 6260482af6804adda242d7a8582ccdd155beb9e0 Author: Cosimo Cecchi Date: 2011-06-13 all: don't use Gtk[H/V]Box in UI files M src/nemo-bookmarks-window.ui M src/nemo-file-management-properties.ui commit d6de7f5f0ff90775445c3dc353328301c66f0de1 Author: Cosimo Cecchi Date: 2011-06-13 all: don't use deprecated Gtk[H/V]Box M libnemo-private/nemo-column-chooser.c M libnemo-private/nemo-column-chooser.h M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-mime-application-chooser.h M src/nemo-connect-server-dialog.c M src/nemo-desktop-item-properties.c M src/nemo-image-properties-page.c M src/nemo-image-properties-page.h M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-notebook.c M src/nemo-pathbar.c M src/nemo-progress-info-widget.c M src/nemo-progress-ui-handler.c M src/nemo-properties-window.c M src/nemo-query-editor.c M src/nemo-view.c M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window.c commit 2c37855719d90413705bd102ef5a29aac33f598a Author: Teliute Date: 2011-06-12 Update Simplified Chinese translation. M po/zh_CN.po commit e46d446be937d0e43ffea1bbc41381388706cf42 Author: Matej UrbanÄiÄ Date: 2011-06-10 Updated Slovenian translation M po/sl.po commit f657a12a9f1da481e7a580335b682749ac4b01cf Author: Javier Jardón Date: 2011-06-09 libnemo-private: Use 'const' instead G_CONST_RETURN M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-icon-info.h commit a8443f64b6554b640f9bd39b3470284127b7bc3f Author: Javier Jardón Date: 2011-06-09 eel: Use 'const' instead G_CONST_RETURN M eel/eel-editable-label.c M eel/eel-editable-label.h commit 253e72f88a85759fe0630aecfb9cea4011e74e5a Author: Kjartan Maraas Date: 2011-06-07 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 64d608f8cc2d6e266900e5a33402249b20dfec1e Author: Fran Diéguez Date: 2011-06-06 Updated Galician translations M po/gl.po commit 12541f6a1ab1fbf30b032dc628aca147d6de2ad0 Author: Yaron Shahrabani Date: 2011-06-04 Updated Hebrew translation. M po/he.po commit e36c6f5871f6f16833361ce57a4845d46e73f3f1 Author: Yaron Shahrabani Date: 2011-06-04 Updated Hebrew translation. M po/he.po commit 092ba8f674341769579bc515389e7bb67035824d Author: Daniel Mustieles Date: 2011-06-04 Updated Spanish translation M po/es.po commit f83bdf0081bfb5d6b8caad8848a267fecb95b85b Author: Cosimo Cecchi Date: 2011-06-03 connect-server: handle closing of the dialog while connecting If we start a connect operation, but close the dialog before providing the credential details, cancel the operation and hide the dialog, instead of segfaulting. The dialog will eventually be destroyed when the the mount operation terminates (with error). M src/nemo-connect-server-dialog.c M src/nemo-connect-server-operation.c commit e3f055c886e9db0c105de59e80573a9715c41060 Author: Cosimo Cecchi Date: 2011-06-03 eel-string: don't use deprecated gatomic API M eel/eel-string.c commit a0d9614d204d0494d329e04c1d7652e451c2573f Author: Cosimo Cecchi Date: 2011-06-03 toolbar: disconnect the GSettings callback on dispose M src/nemo-toolbar.c commit b62ab1413cca6694b9b09fc9d241bbf3581a56e6 Author: Djavan Fagundes Date: 2011-06-03 Updated Brazilian Portuguese translation M po/pt_BR.po commit a5a4bddf12ff29205757858af81fd3665a68c3f2 Author: Cosimo Cecchi Date: 2011-05-31 application: pass in the array length while looping over it M src/nemo-application.c commit d0240a4319561551adc5e0cdb94bb5486d3f3308 Author: Carles Ferrando Date: 2011-05-29 [l10n]Updated Catalan (Valencian) translation M po/ca@valencia.po commit 1f01e04e135c77722cd3d06065f4ceed20d19219 Author: Jorge González Date: 2011-05-29 Updated Spanish translation M po/es.po commit ea223de6187778ce0a0a70356009f1c24c084c57 Author: Jorge González Date: 2011-05-29 Updated Spanish translation M po/es.po commit 178bae2b656b2cae7ad39f81076fca7c65adf429 Author: Yuri Myasoedov Date: 2011-05-28 Updated Russian translation M po/ru.po commit 362696f86bce90dcfa599bf6f4e17ffd0a679860 Author: Cosimo Cecchi Date: 2011-05-25 metadata: add a metadata::custom-icon-name metadata key It's similar to metadata::custom-icon, only that it works on icon names instead of URIs. https://bugzilla.gnome.org/show_bug.cgi?id=626338 M libnemo-private/nemo-file.c M libnemo-private/nemo-metadata.c M libnemo-private/nemo-metadata.h commit fc3d9af1dff85ef27ff44ea4e71b269a2b700e7d Author: Cosimo Cecchi Date: 2011-05-24 autostart: add an autostart desktop file It will autostart nemo automatically based on the GSettings key org.gnome.desktop.background show-desktop-icons. https://bugzilla.gnome.org/show_bug.cgi?id=647267 M data/Makefile.am A data/nemo-autostart.desktop.in commit 636c06bdc3397b1c6bad78afe2094c149c59f6fb Author: Cosimo Cecchi Date: 2011-05-24 css: update for new GtkCssParser M data/nemo.css commit e239f2a150f34b7f7b4730772fae5a372a7924d1 Author: Cosimo Cecchi Date: 2011-05-23 floating-bar: copy code from Epiphany to hide the floating bar on hover This doesn't currently work perfectly if the overlay child is a GtkTreeView - more investigation is needed. In the meanwhile, it's still better than not hiding the bar ever, so here it is. https://bugzilla.gnome.org/show_bug.cgi?id=648740 M src/nemo-floating-bar.c commit f0649b5bb808aa71fcab52c3e61f5e6419928432 Author: Cosimo Cecchi Date: 2011-05-23 gedit-overlay: update from upstream M src/gedit-overlay-child.c M src/gedit-overlay.c commit 5c949fffcb0de62fd5375f546fa94dd50ec7f86f Author: Cosimo Cecchi Date: 2011-05-24 application: rewrite GApplication command line handling Do the command line parsing in local_command_line for the set of options we're interested in parsing there (e.g. directories to open, self checks and --quit); move the rest of initialization in nemo_application_startup() and use g_application_open() and a custom "quit" action to forward the requests to the main application. This also fixes these two bugs. https://bugzilla.gnome.org/show_bug.cgi?id=649336 https://bugzilla.gnome.org/show_bug.cgi?id=637157 M src/nemo-application.c M src/nemo-application.h M src/nemo-connect-server-dialog-nonmain.c M src/nemo-location-bar.c M src/nemo-places-sidebar.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c commit b9272618934a4c177166e5f7771e6ab6cabcc31b Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-05-24 po/vi.po: updated UI to match nemo-preview.page M po/vi.po commit e738e686af858c38ca7c0b32426b3a1dfea0d9a2 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-05-24 po/vi.po: fix up UI to match nemo-views.page M po/vi.po commit f76c50a0e46aa7786820f76b3f71b57b44b8d7fb Author: Cosimo Cecchi Date: 2011-05-23 window: reverse the order of key-press event processing Usually the default GtkWindow handler for key-press events processes them in the following order: - calls gtk_window_activate_key() to process mnemonics/accelerators for the toplevel window - calls gtk_window_propagate_key_event() to propagate the events to the focus widget - chains up to parent if both fail We want gtk_window_propagate_key_event() to be called before gtk_window_activate_key(), as when we're focusing an editable widget (e.g. renaming a file), we want all keybindings to apply to that, e.g. Delete, Ctrl+Delete (or Ctrl+W if we're e.g. using an emacs-mode GTK+ binding set). This interferes a bit with the type-ahead search windows that NemoIconContainer and GtkTreeView pop up; we can control the former, but not the latter, so we need a bit of a hack in NemoListView to prevent the search window to steal the pasted URI, and still not handle the event. https://bugzilla.gnome.org/show_bug.cgi?id=314431 M libnemo-private/nemo-icon-container.c M src/nemo-list-view.c M src/nemo-window.c commit fae5d9242e2edf0881a382ed8cb19599c27cdc49 Author: Cosimo Cecchi Date: 2011-05-23 query-editor: add a border around the query editor widgets https://bugzilla.gnome.org/show_bug.cgi?id=647737 M src/nemo-query-editor.c commit f5e967f964b88ad7e4cc81818e9c0092d842e0a8 Author: Stefano Teso Date: 2011-05-23 connect-server: strip the scheme if it matches the chosen method If e.g. ftp://ftp.example.com is specified as an address, and the FTP method is chosen, we should strip "ftp://" automatically from the address before connecting. https://bugzilla.gnome.org/show_bug.cgi?id=643608 M src/nemo-connect-server-dialog.c commit c17d7bec375b1a8838d6132ccced89da6b092316 Author: Cosimo Cecchi Date: 2011-05-23 location-entry: use symbolic icons for the secondary action hint https://bugzilla.gnome.org/show_bug.cgi?id=647685 M src/nemo-location-entry.c commit b30bda3e1f341b107fbe4f73f1d7b769504d23cd Author: Cosimo Cecchi Date: 2011-05-23 view: add the "view" style class to the icon container Not to the NemoView scrolled windows. M src/nemo-icon-view-container.c M src/nemo-view.c commit c78c3022f07aa790a1f21c48e4ebf62712c6b70f Author: Cosimo Cecchi Date: 2011-05-09 dbus: don't generate the docbook file M libnemo-private/Makefile.am commit 2cf6e53496967b1e00cc026e33c7b63c587c78b4 Author: Cosimo Cecchi Date: 2011-05-09 release: prepare for 3.1.1 M NEWS M configure.in commit ab6436cfa60a7f5088dd92f3d6dec74e0527b086 Author: Cosimo Cecchi Date: 2011-05-09 previewer: avoid creating the dbus proxy more than once M src/nemo-previewer.c commit 16b76b5f97dda14e2c3397345965a07ecc1cd377 Author: Cosimo Cecchi Date: 2011-05-09 previewer: don't warn out if the bus name is not owned by anybody M src/nemo-previewer.c commit a8f2c97e5f67fa1c309cf694f8ca00f5dc38abb9 Author: Cosimo Cecchi Date: 2011-05-01 previewer: don't return a new ref to the singleton It's easier to use this way, and we don't have to create a new DBus proxy every time. M src/nemo-previewer.c M src/nemo-previewer.h M src/nemo-view.c commit 71b8a7a8d66f0c927be9b7c12199d1472043ed66 Author: Alexander Larsson Date: 2011-04-29 Add close_if_already_visible argument to nemo_previewer_call_show_file As per the changes in sushi M src/nemo-previewer.c M src/nemo-previewer.h M src/nemo-view.c commit f087da3353074f7476a563ab62d5ac7cf0d65e41 Author: Cosimo Cecchi Date: 2011-04-27 previewer: drop the x/y coordinates arguments M src/nemo-previewer.c M src/nemo-previewer.h M src/nemo-view.c commit 703c5004a7b05959e3dd554974f28b46df3f0609 Author: Cosimo Cecchi Date: 2011-04-25 previewer: lazily create the DBus proxy M src/nemo-previewer.c M src/nemo-view.c commit e5bf6ef0ec8ca50990aff4afd08a4139d4a75798 Author: Cosimo Cecchi Date: 2011-04-25 debug: add a debug flag for the previewer M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h commit 034eeb090458443b97fbe9b601a045defb5435f9 Author: Cosimo Cecchi Date: 2011-04-25 list-view: hook up the previewer in list view No support for icon locations yet, but it's not implemented in the previewer either. M src/nemo-list-view.c commit ccfd4e1c1d9166c78badac8d83958270cf7aef9e Author: Cosimo Cecchi Date: 2011-04-21 all: hook up the previewer with NemoIconView M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M src/nemo-icon-view.c M src/nemo-view.c M src/nemo-view.h commit 4241ccfd39b6013d2ddd7fbd58aabf5ef1a2302d Author: Cosimo Cecchi Date: 2011-04-21 previewer: add a NemoPreviewer DBus wrapper class M src/Makefile.am A src/nemo-previewer.c A src/nemo-previewer.h commit 9669b91d70ec1cf59933df53f9c22ed16670bb90 Author: Alexander Larsson Date: 2011-05-04 Update all .gitignore files M .gitignore M data/.gitignore M eel/.gitignore M libnemo-private/.gitignore M src/.gitignore commit 7c27c4ce158d09be188b529882ecd5c6b0c17db7 Author: Alexander Larsson Date: 2011-05-04 Convert the nemo dbus support to use gdbus-codegen This required latest glib code to work. M data/Makefile.am A data/dbus-interfaces.xml M libnemo-private/Makefile.am M libnemo-private/nemo-dbus-manager.c commit fa6e44717818d7f9239558f81b90c32dceddf58a Author: Alexander Larsson Date: 2011-05-04 Add size_request to IconContainer to work around unncecessary relayouting The GtkScrolledWindow uses the widget prefered size as a guess as to whether scrollbars are needed or not in the automatic scrollbars case. If we don't report anything for them we typically get it wrong and cause two size allocate calls on the child each time, with different sizes. This (the two sizes speicifically) will cause unnecessary relayouts of the window. So, we just report the current size of the layed out icons as the prefered size. This is somewhat wrong as its depending on previous size_allocation calls rather than the "ideal" size of the widget, but since the ideal size is ignored anyway and just used for this it works well. M libnemo-private/nemo-icon-container.c commit 0cad983521edd476ece360236b6e71e4048bfc70 Author: Alexander Larsson Date: 2011-05-04 Remove old special-cased "select source folder" We now do this generically, so no need to special case it in the "go up" case. M src/nemo-window-slot.c commit b15f61369e3618f4dc2cd3cef5af3698c45706a0 Author: Alexander Larsson Date: 2011-05-04 Always select the folder you "came from" when navigating upwards We used to special case this for the up button, but that now only exists as a keyboard shortcut. This more generic approach gets the same feature also for pathbar navigation and back/forward history navigation. M src/nemo-window-manage-views.c commit e9a7007284b9520855cdbb16fa4724ca0f1739d9 Author: Alexander Larsson Date: 2011-05-04 Really open in new window on the pathbar contect menu item Turns out that we didn't pass the NEW_WINDOW flag in the handler for the LocationOpenAlternate action. This is used when right-clicking on the location label or the pathbar. M src/nemo-view.c commit 41c7cb2ae8fb98fab2cd9b0cfb59cf6dee4d476c Author: Alexander Larsson Date: 2011-05-03 icon-view: Only resort during relayout if necessary We don't need to resort unless e.g. a file changed or was added. Additionally, for weird reason this makes the keyboard focus handling work when deleting a file (file after deleted gets focus). This was broken due to a relayout happening due to a size_allocate due to a style set due to a focus change when going to/from the "are you sure" dialog. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-private.h commit 31546b509d351e89d8bc0ee23074e8e0ecddbca2 Author: Cosimo Cecchi Date: 2011-05-02 application: don't look at DESKTOP_AUTOSTART_ID anymore Now that we don't support being a session component anymore, it doesn't make sense to special case the session autostart. This also breaks opening new windows when nemo is added to ~/.config/autostart, which is now the supported way of having desktop icons automatically, as we end up reading the env variable every time when parsing the command line (as the original process will always have that set) and refuse to show a window. https://bugzilla.gnome.org/show_bug.cgi?id=649063 M src/nemo-application.c commit e251214df28bc7c0b749d1ba0be1ab2048ecd06c Author: Abduxukur Abdurixit Date: 2011-05-02 Added UG translation M po/ug.po commit a9ea2becdf91c417a64083ecdad5f80fb97e6e51 Author: Daniel Korostil Date: 2011-05-02 Uploaded Ukranian M po/uk.po commit 495cb46d54f0b551756c71fb6d5ba60e67f08d61 Author: Cosimo Cecchi Date: 2011-05-01 places-sidebar: disconnect from bookmark list changed signal on dispose This should hopefully fix this crash https://bugzilla.redhat.com/show_bug.cgi?id=699184 M src/nemo-places-sidebar.c commit ac70a95ecc44ba259b684f737bb108f1458fa9dc Author: Cosimo Cecchi Date: 2011-05-01 mime-actions: don't free the activation parameters early This fixes a segfault when clicking on the "Select Application" button when opening a file with no default applications, like in https://bugzilla.redhat.com/show_bug.cgi?id=699850 M src/nemo-mime-actions.c commit 3676b08856c4d6cc0a827e9de8f708edefdf2e44 Author: Cheng-Chia Tseng Date: 2011-05-01 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 61502a06524dd9dffac9d2ae97e9a57037343b28 Author: Daniel Nylander Date: 2011-05-01 Updated Swedish translation M po/sv.po commit 902b0cd4cc1848b44fb2445ebcc0f8157cdc092f Author: Matej UrbanÄiÄ Date: 2011-04-28 Updated Slovenian translation M po/sl.po commit 254ad76a6f861b4846cb53907dd580fb81a96b05 Author: Cosimo Cecchi Date: 2011-04-28 progress-ui-handler: don't add progress infos to the window twice We were adding them twice in case there was already one operation running. https://bugzilla.gnome.org/show_bug.cgi?id=648857 M src/nemo-progress-ui-handler.c commit 8e8f0ed6edd3c5d4f9cca0e07a5624a3d5e2ec29 Author: Cosimo Cecchi Date: 2011-04-28 places-sidebar: make sure to return if we click inside empty space https://bugzilla.gnome.org/show_bug.cgi?id=648872 M src/nemo-places-sidebar.c commit f850fcc0eee61014472e698e6bdd36093ff9dfe2 Author: Andrej ŽnidarÅ¡iÄ Date: 2011-04-27 Updated Slovenian translation M po/sl.po commit a21e3e21940b84f93e0e82320ccfbb6e9a9f2cc3 Author: Cosimo Cecchi Date: 2011-04-27 places-sidebar: use per-side border widths for the sidebar frames This adds a border to the sidebar. M data/nemo.css M src/nemo-places-sidebar.c commit f6dc5f319fb79203bd7645e49420d2a4b57c0373 Author: Cosimo Cecchi Date: 2011-04-25 toolbar: set the icon size to SMALL_TOOLBAR So that the Search button icon is drawn with a smaller size. M src/nemo-toolbar.c commit 3cf09dc4e47ca0db181dd34af22977b8e91cf0f9 Author: Ask H. Larsen Date: 2011-04-25 Updated Danish translation M po/da.po commit 7a8f54b3bbff53b17d46dc6306636852636d1609 Author: Stefano Teso Date: 2011-04-25 places-sidebar: fix opening of selected items by pressing Enter Don't use get_cursor() to open the current item in the sidebar, and use the tree selection instead, as we modify the selection manually when evaluating up/down keypresses. https://bugzilla.gnome.org/show_bug.cgi?id=648555 M src/nemo-places-sidebar.c commit 83a7d27b36120d1ae54a2f5aa4af30f04d470bf2 Author: Cosimo Cecchi Date: 2011-04-25 icon-container: don't chain up style-updated for the desktop container Chaining up resets the background to the default color, which is not what we want for the desktop container. https://bugzilla.gnome.org/show_bug.cgi?id=648137 M libnemo-private/nemo-icon-container.c commit f0d52a7a29ca0b503ed160bd21e4f1a3354f6394 Author: Abduxukur Abdurixit Date: 2011-04-24 Added UG translation M po/ug.po commit e218bff9a4f790f0915f342d764559ee399fa8ee Author: Jiro Matsuzawa Date: 2011-04-25 Updated Japanese translation M po/ja.po commit 7288e91d77f63f4014fa5247bd8a59849f302871 Author: Arash Mousavi Date: 2011-04-23 Updated Persian translation M po/fa.po commit 2f070016690ec488b1ac46d6ab2faf860e0c59b6 Author: Bruce Cowan Date: 2011-04-20 Updated British English translation M po/en_GB.po commit 630fb578c1d86d4c14118025e9c33c8959d6ecf2 Author: YunQiang Su Date: 2011-04-17 fix a mistake of Chinese(Simplified) translation M po/zh_CN.po commit 4a69d60ecf5c6b48492e7dafda7a77e719f9f060 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-04-14 Updated Vietnamese translation M po/vi.po commit 679486ff6db16138027aa85c2aadbb9d272bc984 Author: Cosimo Cecchi Date: 2011-04-12 places-sidebar: make sure the eject icon is rendered 16x16 https://bugzilla.gnome.org/show_bug.cgi?id=647570 M src/nemo-places-sidebar.c commit fde63a6c6f0484f7284fd57ff26abe9d41c93196 Author: Daniel Mustieles Date: 2011-04-11 Updated Spanish translation M po/es.po commit 902aac532bac0da871591bbe481673d2c2d83907 Author: Ã…smund Skjæveland Date: 2011-04-11 Updated Norwegian Nynorsk translation M po/nn.po commit 6c7bd69033676d2e3f5c25b4308bd59e9d540bda Author: Ã…smund Skjæveland Date: 2011-04-11 Updated Norwegian Nynorsk translation M po/nn.po commit fdbca53ae2e7c387d05136656fd9c75fd982c863 Author: Alexander Shopov Date: 2011-04-10 Updated Bulgarian translation M po/bg.po commit a96761350ad422ec084c12f649562f9a2a83963d Author: Cosimo Cecchi Date: 2011-04-08 window: treat regular files as selection when opening a location This allows to call `nemo uri:///path/to/file` from the command line to open uri:///path/to with file pre-selected. https://bugzilla.gnome.org/show_bug.cgi?id=632427 M src/nemo-window-manage-views.c commit 3751310f941ed5df4a2a027ab594df015b3f815c Author: Yaron Shahrabani Date: 2011-04-08 Updated Hebrew translation. M po/he.po commit 07a6fb24fda755288346f11afb670cb3c05028fe Author: Cosimo Cecchi Date: 2011-04-07 icon-container: clear the drag state before popping up context menu Otherwise, a fake drag state will leak into the next motion-notify event when the menu has been dismissed, causing a segfault. https://bugzilla.gnome.org/show_bug.cgi?id=550253 M libnemo-private/nemo-icon-container.c commit d8b632765ca1b70d909d4e206f40590ee379a305 Author: Cosimo Cecchi Date: 2011-04-07 search-bar: set redraw_on_allocate(), like GtkInfoBar does This fixes artifacts while resizing. A similar patch was committed to GtkInfoBar in https://bugzilla.gnome.org/show_bug.cgi?id=587716. https://bugzilla.gnome.org/show_bug.cgi?id=647013 M src/nemo-search-bar.c commit e6dc21ba3b908ed93e08e39731733c871a91e171 Author: Paul Seidler Date: 2011-04-07 libnotify: need at least 0.7.0 https://bugzilla.gnome.org/show_bug.cgi?id=647088 M configure.in commit a8539a688bf83e1ab79167e257df308d1424a103 Author: Cosimo Cecchi Date: 2011-04-07 icon-container: reset the double click counter after a double click If we don't do this, we ignore any other double click event that happen during the next 'gtk-double-click-time' interval after the first double click. Thanks to Tanyel A. Nimeu for the initial patch. https://bugzilla.gnome.org/show_bug.cgi?id=647062 M libnemo-private/nemo-icon-container.c commit f200bfbe8332c0df74335f608f68350609e435d7 Author: Cosimo Cecchi Date: 2011-04-07 preferences: use g_settings_bind_with_mapping() for radiobuttons This also fixes radiobuttons preferences not being applied when opening the properties dialog. https://bugzilla.gnome.org/show_bug.cgi?id=644478 M src/nemo-file-management-properties.c commit 392359db6d6496b325044d809d96b034a2298514 Author: Cosimo Cecchi Date: 2011-04-07 conflict-dialog: make the rename entry expand the whole width M libnemo-private/nemo-file-conflict-dialog.c commit 1457f53c27f6d2f84d0c9eb76c1c8cffd1177e95 Author: Cosimo Cecchi Date: 2011-04-07 conflict-dialog: don't force a size request on the labels This is not required anymore in GTK+ 3 M libnemo-private/nemo-file-conflict-dialog.c commit b8077a7ad65f54e397dd3fa1b32f97b838ba590e Author: Cosimo Cecchi Date: 2011-04-07 conflict-dialog: don't forget to show the primary label Reported in https://bugzilla.redhat.com/show_bug.cgi?id=693922 M libnemo-private/nemo-file-conflict-dialog.c commit f100883058fac79a913d93d1d1157498c87d7912 Author: Fran Diéguez Date: 2011-04-07 Updated Galician translations M po/gl.po commit f49b62649a092a56e2cf6203db0fef08d2ed7618 Author: Cosimo Cecchi Date: 2011-04-06 pathbar: use a NemoFile instead of a GFile as a drag target The NemoFile tracks changes in the file name, so it solves the bug reported in https://bugzilla.gnome.org/show_bug.cgi?id=581748 M src/nemo-pathbar.c M src/nemo-window-slot-dnd.c M src/nemo-window-slot-dnd.h commit 8905b1f91253cfe36fa2c42e179831097b3c9aec Author: Wouter Bolsterlee Date: 2011-04-06 Updated Dutch translation by Wouter Bolsterlee M po/nl.po commit 13793fdc3f5fd884ff5f92093244157b751bd185 Author: Cosimo Cecchi Date: 2011-04-06 window: don't avoid same-uri reloads for the desktop Otherwise it will not reload when toggling desktop-is-home-dir. M src/nemo-window-manage-views.c commit 90b2084cf3f6be689b250ddfd318e33f19f8420d Author: Cosimo Cecchi Date: 2011-04-06 desktop-window: always reset is_loaded when setting the real directory M src/nemo-desktop-window.c commit 25aa3e7f391c905236397a38cf052b0b12bc792a Author: Cosimo Cecchi Date: 2011-04-06 desktop-window: disconnect the gsettings handler on dispose M src/nemo-desktop-window.c commit 8ade659212745eb91631e00d8e878e919a13858a Author: Cosimo Cecchi Date: 2011-04-06 icon-container: don't setup the regular background on the desktop M libnemo-private/nemo-icon-container.c commit ec447586d5f7a5f60f21436a868cfe28d315f1f1 Author: Cosimo Cecchi Date: 2011-04-06 places-sidebar: always add Home as a built-in place M src/nemo-places-sidebar.c commit f9bd05d254555e70ee5295fe08919a8c9d94ca79 Author: Cosimo Cecchi Date: 2011-04-06 places-sidebar: fix a typo in the GSettings key we listen to M src/nemo-places-sidebar.c commit 19d420a28b47723d8e7deb7561cc714be336e655 Author: Cosimo Cecchi Date: 2011-04-06 window-menus: use U+2013 EN DASH in the author copyright string https://bugzilla.gnome.org/show_bug.cgi?id=646735 M src/nemo-window-menus.c commit 6dbb7d159cfc277815d990dd157e2020608698a5 Author: Marvin Schmidt Date: 2011-04-05 configure: Fix libexif check https://bugzilla.gnome.org/show_bug.cgi?id=646849 M configure.in commit 77ba57813e5eaa1fc8260f6e56ef7645093be690 Author: Rodrigo Padula de Oliveira Date: 2011-04-05 Updated Brazilian Portuguese translation M po/pt_BR.po commit 9db9888bea1f0084055bf653cfb46e7b000647c9 Author: Bruno Brouard Date: 2011-04-05 Updated French translation M po/fr.po commit 319ded082ce47f384db3bfc9d7cab2fbe80e1a85 Author: Amitakhya Phukan Date: 2011-04-05 Updated Assamese translations M po/as.po commit 5f190c65784ff9b2b72e36cd0018dfbfab524b98 Author: Daniel Nylander Date: 2011-04-05 Updated Swedish translation M po/sv.po commit aaaee6de758f70005ffdd343a4b7354e3664f471 Author: Cosimo Cecchi Date: 2011-04-04 icon-container: rework the colors used for additional text labels We now use the insensitive color for the normal state, and make them follow the filename color for selected states. This also fixes https://bugzilla.gnome.org/show_bug.cgi?id=319982, tested with the HighContrast theme. M data/nemo.css M libnemo-private/nemo-icon-container.c commit ced6d22409c3a849b86b75bb867f267a3cdad800 Author: Cosimo Cecchi Date: 2011-04-04 window-menus: don't hardcode year values in the translatable string https://bugzilla.gnome.org/show_bug.cgi?id=646735 M src/nemo-window-menus.c commit bb6578da85fff3d28e6a71f9933b1bd34e7c27bc Author: Chao-Hsiung Liao Date: 2011-04-05 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit edd3c43beb5efbc13f55d73e8c9818966a031ad1 Author: Cosimo Cecchi Date: 2011-04-04 dnd: rework handling of _NETSCAPE_URL dnd links Previously we used to to the following: * default to always "ask", unless the copy was explicit * when dropped, we did not actually ask anything but we would trigger an async mimetype query_info and: - trigger a file asking whether to download or to link for text files - silently link for HTML files - silently download for every other mimetype * if the query_info was not completed within one second, we would download by default This is somewhat broken, as the DnD icon is not what you would expect; also downloading is not usually done with DnD from the browser, and it's also expensive, so it should never be the default, but an explicit choice. It also makes it impossible to create links for anything else than text or HTML. Change the policy to always link by default, unless the user explicitly requests the copy. M libnemo-private/nemo-dnd.c M src/nemo-view-dnd.c commit 2afe78a92cc402207e7f3a0189eca95311651076 Author: Cosimo Cecchi Date: 2011-04-04 file: use a GIcon to store the custom icon of desktop files Instead of a filename string. This also has the side-effect of fixing https://bugzilla.gnome.org/show_bug.cgi?id=615509 M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-link.c M libnemo-private/nemo-link.h commit e68c6e071915fe680ed44e824ccafdb1470a39bb Author: Jordi Serratosa Date: 2011-04-04 [l10n]Fixes on Catalan translation M po/ca.po commit 3f17316c34335a9ea8a82d8940506759d88c6fcd Author: Joan Duran Date: 2011-04-04 [l10n]Updated Catalan translation M po/ca.po commit 07c70ab3a65f1d67293a467b742dda729b85156b Author: Jamil Ahmed Date: 2011-04-05 Updated Bengali translation M po/bn.po commit 35311e217ac8f11e97628316c35d6093589507b0 Author: Cosimo Cecchi Date: 2011-04-04 thumbnails: remove unused struct definition M libnemo-private/nemo-thumbnails.c commit 93a0d7fd735c1670c0787c3daa7f84003994da5d Author: Cosimo Cecchi Date: 2011-04-04 thumbnails: remove obsolete check for GLib < 2.14 compatibility M libnemo-private/nemo-thumbnails.c commit f9c6ca979f753339b91c125c363a927fceb64283 Author: Cosimo Cecchi Date: 2011-04-04 thumbnails: remove code unused for years M libnemo-private/nemo-thumbnails.c commit 088d0968f837364374bdea20eda0fa4534338202 Author: Daniel Mustieles Date: 2011-04-04 Updated Spanish translation M po/es.po commit 367572b907d1cd970135e546b3237522b9720c7d Author: Cosimo Cecchi Date: 2011-04-03 application: don't redirect windows on computer:// when unmounting It's confusing now that we don't have a desktop. Redirect to the user home instead. This also has the side effect of fixing https://bugzilla.gnome.org/show_bug.cgi?id=615963 M src/nemo-application.c commit b37f08ef618b6418711a7c70ff7485961bc9058d Author: Cosimo Cecchi Date: 2011-03-31 places-sidebar: don't return TRUE in button-release when we eject Otherwise the GtkTreeView default handler won't run cleaning up what it set up in button-press-event and the next motion-event will trigger the DnD to begin. https://bugzilla.gnome.org/show_bug.cgi?id=646302 M src/nemo-places-sidebar.c commit 2644c6ef4e7839e976d4861d6c86e16e34d46a13 Author: Cosimo Cecchi Date: 2011-03-31 icon-canvas-item: make sure to reset the default cursor ond destruction We might be destroyed while hovering while in single-click mode, so make sure the default cursor is always cleared when finalizing, if we didn't get a leave event. https://bugzilla.gnome.org/show_bug.cgi?id=315023 M libnemo-private/nemo-icon-canvas-item.c commit a47b2efd9b265f92e306e855ede0af3f19881f0c Author: Cosimo Cecchi Date: 2011-04-04 build: bump version to 3.1.0 on master M configure.in commit 7c3ba0e86f5b6ba4859457c1fd57f6f443601cab Author: Yuri Myasoedov Date: 2011-04-04 Updated Russian translation M po/ru.po commit 60ecc80a6057ebb5605f1ef1eb51e6cf8785a1e1 Author: Piotr DrÄ…g Date: 2011-04-04 Updated Polish translation M po/pl.po commit 2641de616d77df714d743a58a52228a6632a1df1 Author: Wolfgang Stöggl Date: 2011-04-04 [l10n] Updated German translation M po/de.po commit 635d472128e9687daa3b466f43765ee116921712 Author: Lukas Lommer Date: 2011-04-04 Updated Czech translation M po/cs.po commit 6efe6113d1a2ee61eaf2feed818689f25023e687 Author: Cosimo Cecchi Date: 2011-04-04 release: release 3.0.0 The future is now. M NEWS M configure.in commit acce5e1c70e10ef550cfed888a852e5048dc4b3d Author: Cosimo Cecchi Date: 2011-04-04 release: update AUTHORS M AUTHORS M src/nemo-window-menus.c commit 681e24ae18f5f4cf6275171154383fb0aeaf1d1a Author: Cosimo Cecchi Date: 2011-04-04 release: require the latest stable versions of our dependencies M configure.in commit 278425bbcd806571f7d5369e53a15d5f22e51551 Author: Cosimo Cecchi Date: 2011-04-03 window: make sure we always force opening in new windows on the desktop https://bugzilla.gnome.org/show_bug.cgi?id=646548 M src/nemo-window-manage-views.c commit 68b57af6e476253b36d8652a681bade6facbd259 Author: Cosimo Cecchi Date: 2011-04-03 places-sidebar: disconnect the gsettings handler callback in _dispose() The GSettings object is a global singleton, so it will always survive the sidebar; we should make sure to disconnect all the settings signal when destroying the sidebar. https://bugzilla.gnome.org/show_bug.cgi?id=646664 M src/nemo-places-sidebar.c commit d4cce11671471427f1b62fc658e05d4f6637b3e9 Author: Chao-Hsiung Liao Date: 2011-04-04 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 42d58b3db4b639521c0346ec8d9afc3f60c30603 Author: Inaki Larranaga Murgoitio Date: 2011-04-04 Updated Basque language M po/eu.po commit 4611ba0cd09b1c63c67930f72c90edb2e4f3b83e Author: Wolfgang Stöggl Date: 2011-04-03 [l10n] Updated German translation, umlauts fixed M po/de.po commit b35740dd52162a87a19ef8ed6a56a6736e5736ec Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-04-03 Updated Vietnamese translation M po/vi.po commit b67ee41bc6601fc26bea2457dc8865e0df5e5f98 Author: Piotr DrÄ…g Date: 2011-04-02 Updated Polish translation M po/pl.po commit ce1f95f6f8ee17cb7613564295566ffd99d8e930 Author: Shankar Prasad Date: 2011-04-02 Updated kn translations M po/kn.po commit c6fc0d81c87f6c3bdfb457a98fbb386dfa36683e Author: Shankar Prasad Date: 2011-04-02 Updated kn translations M po/kn.po commit 333ce240832b66f46d8b9bfdfa4b294c1bf26fbd Author: Shankar Prasad Date: 2011-04-02 Updated kn translations M po/kn.po commit 7ddc0b3bb207fe0b9243b90f1c73b0bcf76490d4 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-04-02 Updated Vietnamese translation M po/vi.po commit 6fc1a0b5cedba6dc28dc995eb7a0688869239c71 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-04-02 po/vi.po: import from Damned Lies M po/vi.po commit 0a10d4355e2e144d6731fa12a981841e1ea7b9b9 Author: Gabor Kelemen Date: 2011-04-01 Updated Hungarian translation M po/hu.po commit c6279ac229545d7f64b64212383df2753482e233 Author: Giorgio F. Gilestro Date: 2011-04-01 Fix up accidental error in last commit The accelerator ended up as stock id instead. M src/nemo-view.c commit cce40272e35b20b4aaf5f93109a05b7bb89704d5 Author: Giorgio F. Gilestro Date: 2011-04-01 Use ctrl-delete as the keyboard shortcut to trash files This change was made to make it harder to accidentally trigger a file delete. We still support the trash that will let you get a trashed file back, and we will get undo support to make this even easier. However, that only works if you know you deleted the wrong file, not if you accidentally hit delete while the nemo window was focused. M src/nemo-view.c commit 803783c2479258aad8f2278dde95101b9e4b90ca Author: Shankar Prasad Date: 2011-04-01 Updated kn translations M po/kn.po commit e72093c2b0490b481a6b894bf84dd46075b7ef21 Author: Jiro Matsuzawa Date: 2011-03-31 Updated Japanese translation. M po/ja.po commit 952269914060f48f941053120e6035440c8cfc6f Author: Милош Поповић Date: 2011-03-31 Added Serbian translation M po/sr.po M po/sr@latin.po commit 7421f629c9493344846890a46e475667b9aae0b1 Author: Dr.T.Vasudevan Date: 2011-03-31 Updated Tamil translation M po/ta.po commit d011084103db0ace13a7011d53f68cf9a3489464 Author: Dr.T.Vasudevan Date: 2010-12-03 Updated Tamil translation M po/ta.po commit 80fab3f7a7447efbd4323cf372f846d4d59141a5 Author: Cosimo Cecchi Date: 2011-03-30 release: update for 2.91.94 M NEWS M configure.in commit f294a4e80626793624d76d6002b094d1c0809de4 Author: Alexander Larsson Date: 2011-03-30 Fix up eject button hover in places sidebar We were calling gtk_tree_view_column_cell_get_position() without properly loading the cell attribute for the right row before. We fix this by calling gtk_tree_view_column_cell_set_cell_data(). With this in place we can also use the x_offset for the position and avoid the whole summing of widths. Due to a bug in Gtk which expands the eject icon cell renderer we have to right align it so that it lines up properly. https://bugzilla.gnome.org/show_bug.cgi?id=640741 M src/nemo-places-sidebar.c commit b57c42f7fbe7fd90cdc6ff59b2f7c160dd3198af Author: Chao-Hsiung Liao Date: 2011-03-30 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 3fd5eda0fc01f56ce9ae9b68b744651d73342259 Author: Ask H. Larsen Date: 2011-03-30 Updated Danish translation M po/da.po commit cf21e9aa47c67861422ada02c7fa327340d63140 Author: Cosimo Cecchi Date: 2011-03-29 pathbar: keep a ref to the GFile while updating the path When desktop-is-home-dir changes, we force a re-layout of all the buttons, which in turn unrefs the passed-in GFile, as the ref would belong to an old button. Fix this by assuming a ref while calling nemo_path_bar_update_path(). https://bugzilla.gnome.org/show_bug.cgi?id=551543 M src/nemo-pathbar.c commit aed2cce6c36543457f5f1ad8f8c05f2fa147b1f2 Author: Matej UrbanÄiÄ Date: 2011-03-29 Updated Slovenian translation M po/sl.po commit e7d80384ab00d52149452e77cd566ee381474b36 Author: Gintautas Miliauskas Date: 2011-03-29 Updated Lithuanian translation. M po/lt.po commit 85ae5ae7e3174c05199ff6557c1cc905ad1d1075 Author: Sandeep Shedmake Date: 2011-03-29 Updated Marathi Translations M po/mr.po commit 08665d5c7ae146c45f5f9855b3ea60c22b1372ad Author: Lukas Lommer Date: 2011-03-29 Updated Czech translation M po/cs.po commit d01f3377a2724bb6582f13c48f7cd1b97b1b869b Author: Lukas Lommer Date: 2011-03-29 Updated Czech translation M po/cs.po commit c7c860a264db211a0a68ee963ce29c7fcb2ad334 Author: Alexander Larsson Date: 2011-03-28 Make sure we free custom accessibility objects Custom accessibility objects, such as NemoIconContainerAccessible need to be freed when their corresponding widget/object dies, right now we're not unreferencing the accessible, so its always leaked. M eel/eel-accessibility.c commit 69a3e83971e2f0963d0c68f4b3e84612ff4032e8 Author: Shaun McCance Date: 2011-03-27 Fixing help buttons to go to new gnome-help pages M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog.c M src/nemo-file-management-properties.c M src/nemo-properties-window.c M src/nemo-view.c M src/nemo-window-menus.c commit ac6ec79231cf3d0cbd076ea5a76b154c9930df68 Author: Henrique P. Machado Date: 2011-03-27 Updated Brazilian Portuguese translation. M po/pt_BR.po commit fed40498e77eb037826391eabdf5f359ad72ba78 Author: Abduxukur Abdurixit Date: 2011-03-27 Added UG translation M po/ug.po commit ca8392d39f57dcbc17d2de84c90fb4e4d473f074 Author: Ivan Masár Date: 2011-03-27 Updated Slovak translation M po/sk.po commit 0889c0e56d13329a835324cf20160a69591a6757 Author: Yuri Myasoedov Date: 2011-03-27 Updated Russian translation M po/ru.po commit 5c34337057c96621d2d43690b262eab98c287a1a Author: Kjartan Maraas Date: 2011-03-26 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 4e75a3b805b007c863ad2eb4b3be62a97249c33d Author: Cosimo Cecchi Date: 2011-03-25 icon-view: clear the icon view when destroying it This ensures all NemoFiles are properly unreffed when destroying the view, and fixes a leak. M src/nemo-icon-view.c commit 199e5adb8a51c9cd54a644de60b01d9c0cd2170d Author: Cosimo Cecchi Date: 2011-03-25 release: update for 2.91.93 M NEWS M configure.in commit 7268e3f449a7ae762dcc5b72cb8a36d7ed3362e2 Author: Alexander Larsson Date: 2011-03-25 Don't leak sidebar widgets Sidebar widgets are normal widgets these days and should be standard floating stuff owned by the container they end up with. So, we should no longer ref_sink them. M src/nemo-places-sidebar.c M src/nemo-tree-sidebar.c commit d781d414e40840422c201dd61637135358c75ab3 Author: Alexander Larsson Date: 2011-03-25 Don't leak NemoFile for bookmarks in places sidebar M src/nemo-places-sidebar.c commit 695efe7cb3f9a96e7c870c36d30e2759d800d2d5 Author: Alexander Larsson Date: 2011-03-25 Better debugging for NemoDirectory leaks M libnemo-private/nemo-directory.c commit 1d48f02ea1bf274d8fb0d70b61bed337bbda06c2 Author: Alexander Larsson Date: 2011-03-25 Add custom foreach to eel_g_hash_table_new_free_at_exit This can be used to get some sort of printout for leaks in non-string hashtables. M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h M eel/eel-stock-dialogs.c M eel/eel-string.c M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M src/nemo-properties-window.c commit 1a8aadd2d02554a308c33a2b88b95c6d7ef5be7f Author: Lukas Lommer Date: 2011-03-24 Updated Czech translation M po/cs.po commit 101796d8b02133f238a757e4d754915e1d276095 Author: Kjartan Maraas Date: 2011-03-22 Updated Norwegian bokmÃ¥l translation M po/nb.po commit f45510bbb82d6ffa23bf8a54b8596fb5f34ae5e3 Author: Mattias Põldaru Date: 2011-03-22 [l10n] Updated Estonian translation M po/et.po commit 41fd10dafd7fe0240dc13bf33140e8aa22d87333 Author: Cosimo Cecchi Date: 2011-03-21 Update for 2.91.92 M NEWS M configure.in commit 2cf698346aca25a48a11edeccc34530e15843a6a Author: Cosimo Cecchi Date: 2011-03-21 file-operations: update the test to the new duplicate string behavior The test was in some cases checking for what we don't actually want to happen. Change it to match current behavior. M libnemo-private/nemo-file-operations.c commit 40947ed576b14777eb3106a3b0350b471455905d Author: Cosimo Cecchi Date: 2011-03-21 file-operations: make sure to handle correctly hidden files extensions This is a fixup of c250b5702329e71c61f6e7f4e26227925c5b1e90 M libnemo-private/nemo-file-operations.c commit 1f31ab18d932a778aa409dd3cadffb34d5f4ae54 Author: Cosimo Cecchi Date: 2011-03-21 css: apply a soft gradient to the floating bar. M data/nemo.css commit 9dc263518f71a2a06ec808be79c2bc0a9fe17129 Author: Cosimo Cecchi Date: 2011-03-21 window: make sure to never show the floating bar on the Desktop https://bugzilla.gnome.org/show_bug.cgi?id=644172 M src/nemo-desktop-icon-view.c M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window.c commit c250b5702329e71c61f6e7f4e26227925c5b1e90 Author: Cosimo Cecchi Date: 2011-03-21 Properly strip extensions when placing the duplication string We use a similar matching filter to the one we use when renaming. It's not ideal (mimetypes are hardcoded, and probably some are missing), but at least we're consistent. https://bugzilla.gnome.org/show_bug.cgi?id=351290 M eel/eel-vfs-extensions.c M eel/eel-vfs-extensions.h M libnemo-private/nemo-file-operations.c commit e0726b71cbbe3ddd9548546991a30951ecc1f21e Author: Cosimo Cecchi Date: 2011-03-21 slot: don't ref the view returned by _get_current_view() https://bugzilla.gnome.org/show_bug.cgi?id=643968 M src/nemo-window-slot-dnd.c M src/nemo-window-slot.c commit 2d71f734864647c23aa3e35374da9058beb0dc2e Author: Kristjan SCHMIDT Date: 2011-03-21 Updated Esperanto translation M po/eo.po commit ddc303bc2b23704911299ba28aab3f0e74fb88ee Author: Kristjan SCHMIDT Date: 2011-03-21 Updated Esperanto translation M po/eo.po commit 1ac3b5dd7100e75d8d579e7dc4c6fabb192a2dee Author: Kristjan SCHMIDT Date: 2011-03-21 Updated Esperanto translation M po/eo.po commit 76e10b322b5e0689c16881f10a3854e207a44c09 Author: Cosimo Cecchi Date: 2011-03-21 places: hide "Open in new Tab/Window" when using separate windows M src/nemo-places-sidebar.c commit 2cd9c4b84059f3e00ed6222ab43c34a974e2c550 Author: Cosimo Cecchi Date: 2011-03-21 view: cleanup "Open in new Tab/Window" items when using separate windows We were displaying a lot of useless entries in the menus in such case. M src/nemo-actions.h M src/nemo-directory-view-ui.xml M src/nemo-view.c commit 572ded742f9146a6bca8f5000804f291338db9b8 Author: Stefano Teso Date: 2011-03-21 view: set the right open flags when opening in a new window https://bugzilla.gnome.org/show_bug.cgi?id=644675 M src/nemo-view.c commit 58e544c260349a01242f40769e61e9b7098069fd Author: Cosimo Cecchi Date: 2011-03-21 window-pane: toggle the search button when showing a saved search https://bugzilla.gnome.org/show_bug.cgi?id=645027 M src/nemo-window-pane.c M src/nemo-window-slot.c commit 111be78c86bc824b291d9b402a2ff897b2fa2dc7 Author: Cosimo Cecchi Date: 2011-03-21 query-editor: make all the labels' appearance consistent M src/nemo-query-editor.c commit c863defffa222ec60eff29c5f31ab73131799912 Author: Cosimo Cecchi Date: 2011-03-21 query-editor: theme the query editor like the other cluebars M data/nemo.css M src/nemo-query-editor.c M src/nemo-query-editor.h commit 1469c27280be10a92aa92195023eb1bbf4a5d10c Author: Cosimo Cecchi Date: 2011-03-21 file-utilities: return "Home" as a title for the home directory Make it consistent with the rest of the UI. https://bugzilla.gnome.org/show_bug.cgi?id=645136 M libnemo-private/nemo-file-utilities.c commit dac5908d505542362cc51c5c21e0b9220715395a Author: Cosimo Cecchi Date: 2011-03-21 pathbar: don't unconditionally iterate over buttons when scrolling This should fix https://bugzilla.gnome.org/show_bug.cgi?id=645198 M src/nemo-pathbar.c commit a2d928754e9b65ce9c7ac93127b61abdd7cbb2f4 Author: Dirgita Date: 2011-03-20 Updated Indonesian translation M po/id.po commit 8129f1c78ac57aa96588228489860c315ef265c2 Author: Rudolfs Mazurs Date: 2011-03-19 Updated Latvian translation. M po/lv.po commit 71548f90dfe368b2ce3396bef6d2099e3b800bdf Author: Wouter Bolsterlee Date: 2011-03-19 Updated Dutch translation by Wouter Bolsterlee M po/nl.po commit 83587589effec5b76a6dd7032f374db4135fae12 Author: Gabor Kelemen Date: 2011-03-19 Updated Hungarian translation M po/hu.po commit 8094cacbdf5914f2a50c1a17cb93701890aafec3 Author: Lucian Adrian Grijincu Date: 2011-03-17 Updated Romanian translation M po/ro.po commit 9d27856f2e62479eca0adae87f1cf6f1bf6cf92c Author: Lucian Adrian Grijincu Date: 2011-03-17 Updated Romanian translation M po/ro.po commit e2bfbbd6d8ae577bb16cd215a2d106dcc31f6d8a Author: Cosimo Cecchi Date: 2011-03-17 view: use GTK_STYLE_CLASS_VIEW for NemoView So that NemoIconContainer also inherits the proper style class. M src/nemo-view.c commit 9c65f3b6675fb927a96a7dd52d6fec4eb700adce Author: Cosimo Cecchi Date: 2011-03-17 window: use GTK_STYLE_CLASS_SIDEBAR for the nemo sidebar M configure.in M data/nemo.css M src/nemo-window.c commit 32fdd13a6e92f9e36dc8476043c4b93f61a6eca9 Author: Gintautas Miliauskas Date: 2011-03-17 Updated Lithuanian translation. M po/lt.po commit f70c2c981adb794bf996b077f2dcfa299d689e61 Author: Mario Blättermann Date: 2011-03-17 [l10n] Updated German translation M po/de.po commit 99d84db2ccc8b7cd998a6704cc34b83cbcac4760 Author: Cosimo Cecchi Date: 2011-03-15 window-pane: use _split_view_off() to close the active pane with Ctrl+W This makes nemo' behavior consistent with what happens when F3 is pressed. M src/nemo-window-pane.c commit 633929a88b8941a4b817bd34b27ce5d8fbe3a804 Author: Cosimo Cecchi Date: 2011-03-15 css: theme the search bar and the cluebar with the proper colors M data/nemo.css commit 515610602463758c08d4ce5514219a83c3e05bfe Author: Cosimo Cecchi Date: 2011-03-15 search-bar: rework to make it more similar to the 3.0 mockups This involves rendering a background over the box, using symbolic icons and other goodness. M src/nemo-search-bar.c M src/nemo-toolbar.c commit 319cda6e9430b4aa74e052ee41086d82fc5bb530 Author: Cosimo Cecchi Date: 2011-03-15 window-slot: cleanup packing of extra widgets Don't pack them in a frame+eventbox, but just use the GtkBox. M src/nemo-window-slot.c M src/nemo-window-slot.h commit d73ded51a677700ad76201851af255f5ba6192d3 Author: Cosimo Cecchi Date: 2011-03-15 x-content-bar: make NemoXContentBar a GtkInfoBar M src/nemo-x-content-bar.c M src/nemo-x-content-bar.h commit 3b3fe092c77b685516495ae8239d6b5aa7c37072 Author: Cosimo Cecchi Date: 2011-03-15 trash-bar: make NemoTrashBar a GtkInfoBar M src/nemo-trash-bar.c M src/nemo-trash-bar.h commit a2df8af91ed91934c16a0a959c1e178b2849c46e Author: Fran Diéguez Date: 2011-03-15 Updated Galician translations M po/gl.po commit 45945cd45776a020b1f8ce5e61c0db7faa1895f4 Author: Cosimo Cecchi Date: 2011-03-15 window: add back the resize grip At the same time, add a bit more padding to the floating bar label, so that it won't be covered by the grip. Remove some margin at the bottom of the window too. M data/nemo.css M src/nemo-floating-bar.c M src/nemo-window.c commit ad8dd8389670d85e8afacb58dc7971cc2b81b9eb Author: Cosimo Cecchi Date: 2011-03-15 window-slot: let the "Loading" floating bar appear only after a timeout It will appear only if loading takes more than 500ms. M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit 275744644c95cc039efae7029a94814b47274ff7 Author: Cosimo Cecchi Date: 2011-03-15 floating-bar: don't use a yellow color for the floating bar Make it also a bit shorter. M data/nemo.css M src/nemo-floating-bar.c commit 00a9b3ae50db1cd609ee3eb4a556c851fc046906 Author: Duarte Loreto Date: 2011-03-13 Updated Portuguese translation M po/pt.po commit df4e4aa5d62e2ef23fdbf0a3ca09107e89d89ff6 Author: Ã…smund Skjæveland Date: 2011-03-13 Updated Norwegian Nynorsk translation. M po/nn.po commit 55585048b94c492fa32a60359a14472da8a4f7c4 Author: Claude Paroz Date: 2011-03-12 Updated French translation Contributed by Gérard Baylard, Bruno Brouard and Claude Paroz. M po/fr.po commit a3a69db247c58066fcd7ae9b3c6e596fa7f21060 Author: Bruce Cowan Date: 2011-03-12 Updated British English translation M po/en_GB.po commit 7536e18ed8fdf50274625837c022ce5ee843c340 Author: Tomas Bzatek Date: 2011-03-11 Bengali translation: Fix malformed format string Originally reported as https://bugzilla.redhat.com/show_bug.cgi?id=578086 Related to commits a1a8f97c9dcd9fdbbbfdddcec7f7d8da85a68dfb and 5b31e211ff20645c548949bd8d012b7bcaa39bf2 M po/bn.po commit b47b01d95f332f6a50157cb2d4940bd920455518 Author: Piotr DrÄ…g Date: 2011-03-11 Updated Polish translation M po/pl.po commit 9cf0a0a1bde02fababd047cced3c36ffa6f9543e Author: Khaled Hosny Date: 2011-03-11 Updated Arabic translation M po/ar.po commit c25ae0f18ca87c561178bd57b191fd13ec3edc38 Author: Manoj Kumar Giri Date: 2011-03-10 Updated Oriya Translation M po/or.po commit 86bd3f63bcdf7cdfdc0ebb12104856f7d085510b Author: Andrej ŽnidarÅ¡iÄ Date: 2011-03-09 Updated Slovenian translation M po/sl.po commit 85e624e496ddcbea78826545308aac09541bbfde Author: Andrej ŽnidarÅ¡iÄ Date: 2011-03-09 Updated Slovenian translation M po/sl.po commit 3800f7c7957ac155d96b0b8605197fd7de8cd943 Author: Cosimo Cecchi Date: 2011-03-08 css: make the backgorund of the floating bar button transparent M data/nemo.css commit e021dd0f9c73c4cbf6e8e00f1ca6863c99a7056c Author: Cosimo Cecchi Date: 2011-03-08 toolbar: use a raised button for Search M src/nemo-toolbar.c commit eb340743b260def298ed64a45d2b6112f7c71589 Author: Joan Duran Date: 2011-03-08 Updated Catalan translation M po/ca.po commit 30fca4b7b9afad5edb884ef7e6b8370fc88951ec Author: Kjartan Maraas Date: 2011-03-08 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 5b6d156f57ad630646c2c3e779d094b98766d529 Author: Cosimo Cecchi Date: 2011-03-07 Release 2.91.91 M NEWS M configure.in commit 9465370aad15fe7b20923ad1009a5d3314edc621 Author: Cosimo Cecchi Date: 2011-03-07 places: use iters to cycle items in the sidebar M src/nemo-places-sidebar.c commit ede178516796568e5d0b596cc720a3cb56dfaaf5 Author: Cosimo Cecchi Date: 2011-03-07 toolbar: set the primary-toolbar style class on the toolbar M src/nemo-toolbar.c commit 896138b17cf6bb8be87bfac3394af641972a364b Author: Luca Ferretti Date: 2011-03-07 Fixed a typo M po/it.po commit 894fe97a070004ad3317fa59fa8cb20851c9ab81 Author: Changwoo Ryu Date: 2011-03-06 Updated Korean translation M po/ko.po commit 96e53868862fb43b54b8e3f5cf9258615bc26fad Author: Andrej ŽnidarÅ¡iÄ Date: 2011-03-05 Updated Slovenian translation M po/sl.po commit 7af7225fce4ede640cf9eca3a2e11115bf542ff7 Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-03-05 Updated Vietnamese translation M po/vi.po commit 0e20049361db4a0d8926e98702501392e98efdcd Author: Nguyá»…n Thái Ngá»c Duy Date: 2011-03-05 po/vi.po: import from Damned Lies M po/vi.po commit 4359343f94d255929621fb4fa1f08b67ded4bf96 Author: Cosimo Cecchi Date: 2011-03-03 list-view: fix expand/fill visibility of the column editor dialog M src/nemo-list-view.c commit ab4fb0cdee781120d35f041a2198f203da2678cd Author: Daniel Korostil Date: 2011-03-02 Uploaded Ukranian M po/uk.po commit 7035f1c2d444b066e079abc50a8664bccf69fe05 Author: Daniel Nylander Date: 2011-03-01 Updated Swedish translation M po/sv.po commit 2ed8c3b4c3ac88996b6bbd961f9bc3fee6c14789 Author: Daniel Korostil Date: 2011-03-01 Uploaded Ukranian M po/uk.po commit 9b4ce4d88d5bc8374d218534f5ee616fdd64ef79 Author: Daniel Korostil Date: 2011-02-28 Uploaded Ukranian M po/uk.po commit f84f6578c5068fe3216387240420f41b2d00db41 Author: Cosimo Cecchi Date: 2011-02-28 css: don't put toolbar style here It's in gnome-themes-standard until we found a more generic way of expressing it. M data/nemo.css commit ba262758489a726afbfcbfe60f1f0c79f20d179a Author: Rudolfs Mazurs Date: 2011-02-27 Updated Latvian translation. M po/lv.po commit d12544d94d11cfe403f0a4f2f82b0ff569a623d6 Author: Gabor Kelemen Date: 2011-02-27 Updated Hungarian translation M po/hu.po commit 789d71e7edbc3f60668c305adb4da9bbdd94b4d6 Author: Stefano Teso Date: 2011-02-26 places-sidebar: skip section headers on keynav https://bugzilla.gnome.org/show_bug.cgi?id=643137 M src/nemo-places-sidebar.c commit 089315b56f78113bd26d18bb40d0132b84954ebe Author: Stefano Teso Date: 2011-02-26 typeahead-find: make sure the search widget is on-screen when maximized https://bugzilla.gnome.org/show_bug.cgi?id=642953 M libnemo-private/nemo-icon-container.c commit a5d4e41129e00461426312cdffa392b59ac30118 Author: Stefano Teso Date: 2011-02-26 bookmarks: bookmarked saved searches should use the saved-search icon https://bugzilla.gnome.org/show_bug.cgi?id=643057 M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-icon-names.h commit 02446f2cdb990fabebdefaed339227d6f52a495e Author: Cosimo Cecchi Date: 2011-02-25 icon-view: doesn't make sense to use g_timeout_add_seconds for preview https://bugzilla.gnome.org/show_bug.cgi?id=574033 M src/nemo-icon-view.c commit 5e2edee2e8dc6b4eababdff993176d591cc2a6e6 Author: Cosimo Cecchi Date: 2011-02-25 list-view: make sure not to select the extension on rename Delay calling gtk_editable_select_region() until after gtk_tree_view_set_cursor() https://bugzilla.gnome.org/show_bug.cgi?id=627110 M src/nemo-list-view.c commit a9515134c3bce4df1d1563340394b796ae40d183 Author: Stefano Teso Date: 2011-02-25 list-view: create folders in subdirectories when possible Don't always choose the tree root as parent when creating a new folder, but look at the current selection's directory. https://bugzilla.gnome.org/show_bug.cgi?id=330644 M src/nemo-list-view.c M src/nemo-view.c M src/nemo-view.h commit 97b1ff2fa3b4d706969ab40d4bf17adad281e42f Author: Cosimo Cecchi Date: 2011-02-25 list-view: unfreeze updates on focus out It's not really right, as GtkTreeView should always emit editing-canceled on the right renderer for us, but if you click away from the entry, it doesn't, so this is just a workaround until the GTK+ bug is fixed. M src/nemo-list-view.c commit 3645b11f392c649455472bc1b3a8c8f581c37c74 Author: Cosimo Cecchi Date: 2011-02-25 file: make sure not to pass g_utf8_collate() NULL strings M libnemo-private/nemo-file.c commit e939b36481815dbdf4053dba070f17d02a1efc38 Author: Cosimo Cecchi Date: 2011-02-25 desktop-file: remove obsolete x-directory/* mimetypes They got deprecated. https://bugzilla.gnome.org/show_bug.cgi?id=612694 M data/nemo.desktop.in.in commit 50ee32a1b46f0e0dea68b57c72070247bad9b7f7 Author: Cosimo Cecchi Date: 2011-02-25 window-slot: use the actual view as relative-widget Instead of special-casing the scrolled window in the overlay code, we directly set the actual view as relative-widget from the slot. M src/nemo-window-slot.c commit 23aa30fec0da95b58a9336da58115a3a04a21eb4 Author: Cosimo Cecchi Date: 2011-02-25 overlay: sync with gedit upstream As one of my patches got rejected. M src/gedit-overlay.c commit a2093ba1340334fa2733aa3ba2c00e7d1cfb683e Author: Cosimo Cecchi Date: 2011-02-25 view: remove nemo_view_get_widget() Having a function just to call a cast seems a bit weird... M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window-slot.c commit 2632e266fbc794de5e912ac1f37dfaa8f4ed0904 Author: Rodrigo Moya Date: 2011-02-25 Plug memory leak M libnemo-private/nemo-icon-info.c commit f45d398de73c1eee924e55aadba96254d8091932 Author: Rodrigo Moya Date: 2011-02-24 Guard against filename being NULL on nemo_icon_info_lookup M libnemo-private/nemo-icon-info.c commit 6c9cfec6cca8fc51049eac6c7677516b5d241677 Author: Cosimo Cecchi Date: 2011-02-24 places-sidebar: use the widget type directly instead of defining a class M data/nemo.css M src/nemo-places-sidebar.c commit 5df17020848a51d1211451274ae6816562d53503 Author: Cosimo Cecchi Date: 2011-02-24 all: remove shadows from scrolled windows and add a bottom margin To better match the mockups M src/nemo-places-sidebar.c M src/nemo-view.c M src/nemo-window.c commit c024477bd59761cfa683117dafe47cd08fda3f52 Author: Cosimo Cecchi Date: 2011-02-24 window-slot: adapt to overlay API changes M src/nemo-window-slot.c commit 2aa5c4844b3f4fe6b26c72d74ccfc9352a11f3f4 Author: Cosimo Cecchi Date: 2011-02-24 overlay: sync with upstream, and add a case for scrolled windows M src/gedit-overlay-child.c M src/gedit-overlay.c M src/gedit-overlay.h commit b220d722a0748763ebe1370a49831c24d734f7f8 Author: Cosimo Cecchi Date: 2011-02-24 all: move the floating bar to NemoWindowSlot M src/nemo-floating-bar.h M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit d0706a08eefb73aa515cb445e57c0360637cce12 Author: Cosimo Cecchi Date: 2011-02-24 places-sidebar: don't activate 'Rename' shortcut for non-bookmarks M src/nemo-places-sidebar.c commit d2c34101172415c63fe3c89e62ea1bf8bca15d9d Author: Cosimo Cecchi Date: 2011-02-24 editable-label: only clear the selection if we change to insensitive This is borrowed from GtkEntry, and should properly fix https://bugzilla.gnome.org/show_bug.cgi?id=642766 M eel/eel-editable-label.c commit 8d9cb34aec31955874b59d7d90ca4a57c6ddbcf4 Author: Kjartan Maraas Date: 2011-02-24 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit d6f2b28ea999a2d36d023c80dfd9fb4d7ffd83d6 Author: Aron Xu Date: 2011-02-24 Update Simplified Chinese translation. M po/zh_CN.po commit 18b496bc28a59987d161b5272244a808f5c06e2c Author: Cosimo Cecchi Date: 2011-02-23 places-sidebar: discard special dirs if they are assigned to the home https://bugzilla.gnome.org/show_bug.cgi?id=643121 M src/nemo-places-sidebar.c commit 24e447ed71d986f8806dfcc75a7d2c32cb47dbd0 Author: Cosimo Cecchi Date: 2011-02-23 tree-sidebar: cope with being shown in separate windows Use the same strategy as in NemoPlacesSidebar to decide where new window should be opened. M src/nemo-tree-sidebar.c commit 187604bc871c9b09be29794713c5db211d075d48 Author: Cosimo Cecchi Date: 2011-02-23 window: make sure to disconnect the sidebar changed id signal When the window is finalized. M src/nemo-window.c commit 5ae01f04d69f9e1d24cda75e9046aea4b4e96cd1 Author: Cosimo Cecchi Date: 2011-02-23 places-sidebar: respect middle-click for separate windows mode Make it consistent with the rest, i.e. close behind. This also fixes a crasher. M src/nemo-places-sidebar.c commit 0e6d9d7da5e2deac33d14261fbe9a22bbc7de192 Author: Cosimo Cecchi Date: 2011-02-23 window-pane: don't open another window when toggling off the search When 'Open new windows in separate folders' is toggled. This is not yet complete, but fixes at least one case. M src/nemo-window-pane.c commit 29e8f4564400640cc19e0fd7753ea8b2bac9d555 Author: Cosimo Cecchi Date: 2011-02-23 properties-window: add a border around the notebook This makes it visually consistent with other nemo notebooks, and with e.g. the GNOME3 control-center. M src/nemo-properties-window.c commit 4b6ba5bbccb934b9c595003ea1218913dd33d0c9 Author: Cosimo Cecchi Date: 2011-02-23 view: disconnect the statusbar visibility signal handler on finalize M src/nemo-view.c commit b6c86952f816dc698fed3ebb91231cc9e1ea5745 Author: Matej UrbanÄiÄ Date: 2011-02-23 Updated Slovenian translation M po/sl.po commit 75b7885bcd6e77bf16f7fa9d6bee44ac0c53ce94 Author: Matej UrbanÄiÄ Date: 2011-02-23 Updated Slovenian translation M po/sl.po commit 20be3147adefe2a8e2f7d03ccebe791f09fd5060 Author: Matej UrbanÄiÄ Date: 2011-02-23 Updated Slovenian translation M po/sl.po commit 3f9cc6132af4fb06b7b1467e9544c8853843183c Author: Alexander Shopov Date: 2011-02-23 Updated Bulgarian translation M po/bg.po commit 415aef2af3e8a7491ee0605f5082a696640680f8 Author: Cosimo Cecchi Date: 2011-02-22 dbus-manager: install a DBus service file M data/Makefile.am A data/org.gnome.Nemo.service.in commit b76e3c666d1da08cc70bd09a293c2ed319861bcd Author: Cosimo Cecchi Date: 2011-02-22 dbus-manager: hold the GApplication for 5 seconds upon startup This is needed so that nemo can be started as a DBus service with --no-default-window and be able to handle incoming method calls without quitting before receiving them. M libnemo-private/nemo-dbus-manager.c M libnemo-private/nemo-dbus-manager.h M src/nemo-application.c commit 25e74f522cd49af07b2be6b92cc3a7421a57f5fc Author: Cosimo Cecchi Date: 2011-02-22 Fix distcheck M po/POTFILES.in commit 32f4f370a37eced91270202ed7ff02cd4db46d8d Author: Cosimo Cecchi Date: 2011-02-22 Release 2.91.90.1 M NEWS M configure.in commit a0569367b029140ca15cdd5d0d78a3577c3d6d83 Author: Cosimo Cecchi Date: 2011-02-22 module: make modules for extension that pull in ORBit resident ORBit installs atexit() handlers, which would get unloaded together with the module now that the main process doesn't depend on GConf anymore, causing nemo to sefgault at exit. If we detect that an extension would pull in ORBit, we make the module resident to prevent that. M libnemo-private/nemo-module.c commit 8ff66dc5aeb7c573ef3deb6100fa151e9f9349e9 Author: Ivar Smolin Date: 2011-02-22 [l10n] Updated Estonian translation M po/et.po commit c40521ffbc4e990e4633be41e730b28eec26f1f5 Author: Cosimo Cecchi Date: 2011-02-21 icon-info: remove unused code M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-icon-info.h commit 150b95ca0c668568e0e5d04701048d6f1fc1636b Author: Cosimo Cecchi Date: 2011-02-21 zoom-control: remove unused NemoZoomControl M src/Makefile.am M src/nemo-window.c D src/nemo-zoom-control.c D src/nemo-zoom-control.h commit ee701773633e2b5f2a70988ca16ace47d002e382 Author: Luca Ferretti Date: 2011-02-21 Updated Italian translation M po/it.po commit 50647b100ddb52f61c50f973d89f883d346442bb Author: Cosimo Cecchi Date: 2011-02-21 Release 2.91.90 M NEWS M configure.in commit aea7f1f49601c34398f8b62b3650f7c3db8d1171 Author: Cosimo Cecchi Date: 2011-02-21 all: fix some includes M src/nemo-toolbar.c M src/nemo-window-pane.c commit b89a352e0d37193d00de7085ad4ef18f6f2d36a2 Author: Cosimo Cecchi Date: 2011-02-21 configure: depend on stable GTK+/GLib versions M configure.in commit ead6bf5b5d80a0d4937d7b8f84dd2cdc53db73e4 Author: Luca Ferretti Date: 2011-02-21 Updated Italian translation M po/it.po commit 1cfe6c78c610c616873314e2fa76cb085116cf96 Author: Cosimo Cecchi Date: 2011-02-21 tracker-engine: update to 0.10, using libtracker-sparql https://bugzilla.gnome.org/show_bug.cgi?id=642770 M libnemo-private/nemo-search-engine-tracker.c commit a8a5b8d8eae041e7ae10a553d0990fc7ee5dc3cd Author: Stefano Teso Date: 2011-02-21 icon-container: fix setting the selection when renaming Closes: bgo #642766 M libnemo-private/nemo-icon-container.c commit 6dd4e0aed74bb7da6fc471ff6f032884f93643b5 Author: Cosimo Cecchi Date: 2011-02-21 application: remove the ConsoleKit listener I just moved it to the gnome-settings-daemon plugin where it should belong. M src/nemo-application.c commit a3f2a8814453860b1fb8d4c1aa9637011b46f7fb Author: Stefano Teso Date: 2011-02-21 nemo-view: Ignore scripts directory if it's a broken symlink Closes: bgo#633683 M src/nemo-view.c commit 585e46b63b691ccc4a618ddc01b686954da287a3 Author: Yaron Shahrabani Date: 2011-02-21 Updated Hebrew translation. M po/he.po commit 527aa458d57036cb74c3f855cd1eb724da1e3ad6 Author: Cosimo Cecchi Date: 2011-02-21 window: remove another couple of unused defines M src/nemo-window-private.h commit 8ec1999f09ff40b6a1a8b511efbf36b692144503 Author: Cosimo Cecchi Date: 2011-02-21 window: remove useless defines M src/nemo-window-private.h commit 9531e7cb106f161d8a43da7ca161fac8becd3de6 Author: Cosimo Cecchi Date: 2011-02-21 window: plug a leak Don't leak the GtkSizeGroup after we add widgets to it. Also, move it to the pane, where it should belong now. M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window.c commit 243a3f883f7b2969c11ddac8c6d46521ffa5ef4d Author: A S Alam Date: 2011-02-21 update Punjabi Translation by A S Alam M po/pa.po commit 945ff33b72928e13b2206ccb869f63420cd9de94 Author: Cosimo Cecchi Date: 2011-02-20 window-menus: fix indentation M src/nemo-window-menus.c commit 322a3d0094082a32d357d0358174025c296a46dd Author: Cosimo Cecchi Date: 2011-02-20 window: fix behavior of the Search action Make the toolbar button active state consistent with the menu, and simplify the code handling it a bunch. M src/nemo-shell-ui.xml M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c M src/nemo-window.h commit eb9a291ad09d77cd01131209f68beaa04ef45626 Author: Cosimo Cecchi Date: 2011-02-20 navigation-state: bind "active" for toggle actions So that we can use this objet for "Search" M src/nemo-navigation-state.c commit 808332169bb8000c57d55e267d4abf4dcad3a481 Author: Jorge González Date: 2011-02-20 Added Spanish translation M po/es.po commit 7a3360c812ac30858ca7281c3d34fd132c454f63 Author: Matej UrbanÄiÄ Date: 2011-02-20 Updated Slovenian translation M po/sl.po commit 763109bb17cd326195ff44951977243a6e6712d1 Author: Cosimo Cecchi Date: 2011-02-19 file-operations: make sure not to show the dialog before calling _run() This had no noticeable effect before, but with gnome-shell's modal dialog animation, it causes the dialog flickering before being picked by the WM. M libnemo-private/nemo-file-operations.c commit 01c61be847dbb30f7392794ad0fec6228e82904d Author: Cosimo Cecchi Date: 2011-02-19 all: plug some memory leaks M src/gedit-overlay.c M src/nemo-floating-bar.c commit bdb71b79540e5a7265ff08bf4353dd580c32411a Author: Cosimo Cecchi Date: 2011-02-19 overlay-child: make sure to intialize required fields M src/gedit-overlay-child.c commit 89b84688b36a769478bd4593cceace6e2636c86c Author: Kjartan Maraas Date: 2011-02-19 Fix this after the window and spatial cleanups M po/POTFILES.in commit e68968479783e0ff3e4f7c8b7391471d06597306 Author: Kjartan Maraas Date: 2011-02-19 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit ddd59a578e403e815f76006477bf5eaea5b20c1e Author: Cosimo Cecchi Date: 2011-02-18 window: accumulate saving the sidebar width in GSettings We don't want to hammer DConf with writes. M src/nemo-window-private.h M src/nemo-window.c commit 56b249cc804bcea81d0308afe45ac2e5084dc6d7 Author: Cosimo Cecchi Date: 2011-02-18 floating-bar: ellipsize the description label Until we have a better way to truncate it at the right point when there's not enough space. M src/nemo-floating-bar.c commit 695d067571292c6475761e1ae4c453615f611a00 Author: Cosimo Cecchi Date: 2011-02-18 overlay: fixup allocation in the overlay Give the children the right size they request, and make sure they don't get more space allocated than the width of their parent. M src/gedit-overlay-child.c M src/gedit-overlay.c commit 1fd64c8188a513ec0321e2ff70225f9a7c52b3ad Author: Cosimo Cecchi Date: 2011-02-18 pathbar: cleanups M src/nemo-pathbar.c commit 7545af6c31ff45998167d008f3320a69d5531f7c Author: Cosimo Cecchi Date: 2011-02-18 pathbar: clean up forward declarations and unused properties No real code change here. M src/nemo-pathbar.c commit 369eaac5796263e49dd0502aedc6d9137d160132 Author: Cosimo Cecchi Date: 2011-02-18 pathbar: remove unused code M src/nemo-pathbar.c M src/nemo-pathbar.h commit 36a47b4a7ea52c860818e0e8a4f795a365ba2e2c Author: Daniel Korostil Date: 2011-02-18 Uploaded Ukranian M po/uk.po commit 2fde89de52f465051dbc85e3d00f57941275e4a7 Author: Daniel Korostil Date: 2011-02-18 Uploaded Ukranian M po/uk.po commit 6a11ecdde028a4972559491a3c0ec7799cc8c882 Author: Cosimo Cecchi Date: 2011-02-18 icon-canvas-item: make the icon frame transparent when not prelit This fixes icons on the desktop appearing weird. M libnemo-private/nemo-icon-canvas-item.c commit 1d3d4a1e954fcc15f2a9c7d933e7bc65c5330cc3 Author: Cosimo Cecchi Date: 2011-02-18 all: remove 'Tighter Layout' option It's just broken, and we already have icon view if we want something tighter. M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M libnemo-private/nemo-metadata.c M libnemo-private/nemo-metadata.h M libnemo-private/nemo.convert M libnemo-private/org.gnome.nemo.gschema.xml.in M src/nemo-actions.h M src/nemo-convert-metadata.c M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui M src/nemo-icon-view-ui.xml M src/nemo-icon-view.c M src/nemo-icon-view.h commit 822b99ee1de297fbe78548a1a7fa96d1be737f72 Author: Cosimo Cecchi Date: 2011-02-18 list-view: make sure not to activate items while chaining up The event activation is done entirely in our signal handler, and row-activated should only be used for the typeahead search box. M src/nemo-list-view.c commit 1988c7bc5feff1a2630b2603d558d1c376b12c9f Author: Cosimo Cecchi Date: 2011-02-18 views: fix alternate locaiton opening somewhat It was broken after the last changes. Also, add some comments to clarify how things work. M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-window-manage-views.c commit 491948284e453440798f14e29ba65737f44c5d46 Author: Cosimo Cecchi Date: 2011-02-18 debug: add a debug flag for the icon view M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h commit 765d81d0b68e3b2d430b9ca0716a3f67607440df Author: Alexander Larsson Date: 2011-02-18 Change compact-view all-columns-have-same-width default to false This particular option is what makes the lables-on-the side part of compact view useful (and compact) over the normal icon view. Having it off by default is just weird. M libnemo-private/org.gnome.nemo.gschema.xml.in commit 2d904c778ce5b30649c4789f35fcd3ea44e7fa59 Author: Alexander Larsson Date: 2011-02-18 Remove debug spew from previous commit M src/nemo-window-manage-views.c commit e5f4a1f0fe63b324cc62e94a46599b2e187b1121 Author: Cosimo Cecchi Date: 2011-02-17 window-manage-views: initialize a variable M src/nemo-window-manage-views.c commit bdc7f2172f9e8b1c58d3f8a8d90ae157702dde3e Author: Cosimo Cecchi Date: 2011-02-17 window-manage-views: fix an oversight in previous commit M src/nemo-window-manage-views.c commit a58eb87e294c02ec61668ef6d02d701626ef8b98 Author: Cosimo Cecchi Date: 2011-02-17 window-manage-views: don't create two windows when opening in new win We were creating two windows at startup if the 'Open in different windows' option was toggled on. M src/nemo-window-manage-views.c commit 936a1749bb79217decc47ec2e12c7f3c40823f97 Author: Cosimo Cecchi Date: 2011-02-17 window: fix some missing signal handlers/overrides M src/nemo-window.c commit cff594aeba0cb62f3316eb8a14114091ca4c6d11 Author: Cosimo Cecchi Date: 2011-02-17 window: cleanup header M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit f57a958039400b38897bf7ad5cc2f2e686921624 Author: Cosimo Cecchi Date: 2011-02-17 location-dialog: remove NemoLocationDialog The only user was NemoSpatialWindow M src/Makefile.am D src/nemo-location-dialog.c D src/nemo-location-dialog.h commit b1589b8c22baa2d9508aabe96fc8bafd99bcdb71 Author: Cosimo Cecchi Date: 2011-02-17 all: fix the desktop window without spatial mode Basically disable all the window chrome for the desktop window. M src/nemo-desktop-window.c M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit 4bf81e0d4883b9b6a6dfab120b096bea26a46a0a Author: Cosimo Cecchi Date: 2011-02-17 window: merge the navigation window XML into the shell XML There's no such distinction anymore. M src/Makefile.am D src/nemo-navigation-window-ui.xml M src/nemo-shell-ui.xml M src/nemo-window-menus.c commit df516e1f09ded17bea6a4fc4fd8b974f61e799b4 Author: Cosimo Cecchi Date: 2011-02-17 all: merge NemoNavigationWindow into NemoWindow M src/Makefile.am M src/nemo-application.c M src/nemo-application.h M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-desktop-window.c M src/nemo-desktop-window.h M src/nemo-icon-view.c M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-mime-actions.c M src/nemo-navigation-action.c D src/nemo-navigation-window-menus.c D src/nemo-navigation-window.c D src/nemo-navigation-window.h M src/nemo-notebook.c M src/nemo-places-sidebar.c M src/nemo-view.c M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-menus.c M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit 4cf05a8c91bda94aac6d403947cbb402a68019d2 Author: Cosimo Cecchi Date: 2011-02-17 window: fix class casting madness M src/nemo-window.c commit 9af483dbbea8fc6fc41f4bc726522d7583ccf677 Author: Cosimo Cecchi Date: 2011-02-17 all: merge NemoNavigationWindowSlot into NemoWindowSlot M src/Makefile.am M src/nemo-application.c M src/nemo-navigation-action.c D src/nemo-navigation-window-slot.c D src/nemo-navigation-window-slot.h M src/nemo-navigation-window.c M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c commit 238bc1452138e1aae44dcc95121b749ab4d805d0 Author: Cosimo Cecchi Date: 2011-02-17 window-pane: remove useless class vfuncs M src/nemo-window-pane.h commit 67384aa0d21e90816d5ee084b56bb43b1e94af60 Author: Cosimo Cecchi Date: 2011-02-17 all: merge NemoNavigationWindowPane into NemoWindowPane M src/Makefile.am M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-navigation-window-menus.c D src/nemo-navigation-window-pane.c D src/nemo-navigation-window-pane.h M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-notebook.c M src/nemo-toolbar.h M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 0e73140437c97c23b480f137ce8c88113900a336 Author: Cosimo Cecchi Date: 2011-02-17 all: assume all windows are navigation windows M src/nemo-application.c M src/nemo-bookmarks-window.c M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window.c commit b6b63e35792fd50cbe71bf87e44d5233cd879b3d Author: Cosimo Cecchi Date: 2011-02-17 all: remove NemoSpatialWindow M src/Makefile.am M src/nemo-bookmarks-window.c M src/nemo-desktop-window.h M src/nemo-location-dialog.c D src/nemo-spatial-window-ui.xml D src/nemo-spatial-window.c D src/nemo-spatial-window.h M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-private.h M src/nemo-window.c commit 9d70e3e2a0b8af6eef1a10749a985896ba449e37 Author: Cosimo Cecchi Date: 2011-02-17 desktop-window: make NemoDesktopWindow a navigation window We still have to fix sidebar/toolbar visibility though. M src/nemo-desktop-window.c M src/nemo-desktop-window.h commit 073e1f9454d52523837a3a2073d710206c90a808 Author: Cosimo Cecchi Date: 2011-02-17 all: remove spatial windows methods from NemoApplication M src/nemo-application.c M src/nemo-application.h M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c M src/nemo-spatial-window.c commit edc5310062e8617727423e7508951de1abe0b1b9 Author: Cosimo Cecchi Date: 2011-02-17 all: remove NemoWindowOpenMode enumeration The mode is now always decided by the GSettings preference. M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-mime-actions.c M src/nemo-mime-actions.h M src/nemo-navigation-window-pane.c M src/nemo-places-sidebar.c M src/nemo-spatial-window.c M src/nemo-tree-sidebar.c M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window-types.h commit e94fe49ef856a4658fd3fcbb228b78bb0d7b0657 Author: Alexander Larsson Date: 2011-02-17 Don't show a desktop target in copy/move to if desktop is not shown M src/nemo-view.c commit e74376ee27a232e559a3ef98918f0742d6fa376a Author: Alexander Larsson Date: 2011-02-17 Don't show desktop in sidebar if desktop is not visible or if home is desktop By default there is no more desktop anymore, so its kinda weird to have it highly visible in the ui, as there should be nothing there. M src/nemo-places-sidebar.c commit 4298e522e25ea5075090822a5497164051373a4b Author: Alexander Larsson Date: 2011-02-17 Disable the status bar by default in new windows M libnemo-private/org.gnome.nemo.gschema.xml.in commit 055b16f45c4d3c7b5b543df5b8457702f2d3164e Author: Cosimo Cecchi Date: 2011-02-17 window-bookmarks: make sure we get an icon for bookmarks in the menu M src/nemo-window-bookmarks.c commit e978429c15a5a6d99c0dfeecb2ce889d1a6d0529 Author: Cosimo Cecchi Date: 2011-02-17 search-bar: make the search bar a regular GtkBox M src/nemo-search-bar.c M src/nemo-search-bar.h commit c4060407ef76d2566d02cd6dacf06381585ace17 Author: Cosimo Cecchi Date: 2011-02-16 all: set some junctions to better fit the mockup M src/nemo-places-sidebar.c M src/nemo-view.c commit d9640b96ef746cbfe5de6ddd21ae06052aa33fa8 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window: fix text setting/unsetting on Search button M src/nemo-navigation-window.c commit 46b297a523d7f679891299d2a6a4ccac03927ed1 Author: Cosimo Cecchi Date: 2011-02-16 eel: remove unused method M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 6acaf5d7ede7054a258f555331358054e1835813 Author: Cosimo Cecchi Date: 2011-02-16 window-menus: remove sneaky code for middle-click toolbar actions We support it directly where we already care now. M src/nemo-window-menus.c commit 6fa4065d55ffa792105576fd2b99ead5913b36f0 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window: don't create custom actions for the menu items We can use normal actions for those, and use the custom actions in the toolbar, as we already do. M src/nemo-navigation-window-menus.c commit b644be6ed4f7da02a700a2f74401c4f5273dca46 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window: remvoe useless Search action from the nav group M src/nemo-navigation-window-menus.c commit 0e168f61a0012127ee0c40ef642b0818471212b7 Author: Cosimo Cecchi Date: 2011-02-16 all: remove NemoViewAsAction The rationale being the same as for NemoZoomAction M src/Makefile.am M src/nemo-navigation-window-menus.c D src/nemo-view-as-action.c D src/nemo-view-as-action.h commit 38dea32b3da5610990348be37c3f9454cec54773 Author: Cosimo Cecchi Date: 2011-02-16 all: remove NemoZoomAction Now that we don't use it on the toolbar anymore, it's useless to keep around. M src/Makefile.am M src/nemo-navigation-window-menus.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window.c D src/nemo-zoom-action.c D src/nemo-zoom-action.h commit d83173021f5adc99b5eec468e0c4d5ddfeed4218 Author: Cosimo Cecchi Date: 2011-02-16 window: just use nemo_view_set_is_active() Don't roundtrip through NemoWindowSlot, as that's what it would do anyway. M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c commit a08625badd19790faca002f1fd6c7049f2d680ba Author: Cosimo Cecchi Date: 2011-02-16 window: active_pane might be NULL if we're destroying the window M src/nemo-window.c commit a74eac5f4446928cfa00ead53f972f7de678b914 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window-pane: don't bother always setting the active pane The toolbar is insensitive when not active anyway, so this is useless. M src/nemo-navigation-window-pane.c commit 40bfe945c48bc368c11be4341a6c3f27b5543960 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window-pane: cleanup the class a bit M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit de4b00057e06fdc675d640c65c9a459f9fdb2725 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window: integrate the back/forward actions with the state So that the current back.forward state propagates to menus. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window.c M src/nemo-window-private.h commit d6df8a9d7bc4b902de76c22504f2fa63557d7985 Author: Cosimo Cecchi Date: 2011-02-16 navigation-state: add NemoNavigationState M src/Makefile.am A src/nemo-navigation-state.c A src/nemo-navigation-state.h commit 0c60fd28a1852a101caef1e4cd783b26012cd7fc Author: Cosimo Cecchi Date: 2011-02-16 toolbar: make sure to hold a ref to the action group M src/nemo-toolbar.c commit 698f109a70c063d47b4ff4adeec78724f674fe6d Author: Cosimo Cecchi Date: 2011-02-16 navigation-window: little cleanup M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.h commit e18dddb0f6ff0a91e25929b667687b87c8d20ee5 Author: Cosimo Cecchi Date: 2011-02-16 window-pane: make sure we set another pane as active when closing M src/nemo-window-pane.c commit 3634db080bcf57534b47860908370da5d5cdfad9 Author: Cosimo Cecchi Date: 2011-02-16 window-slot: move window_slot_close() to nemo-window-slot.c Why on earth should it be somewhere else? M src/nemo-application.c M src/nemo-navigation-window-pane.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-slot.h M src/nemo-window.c commit 610b14e6c85d16d519a0c9665ada09b289d21de7 Author: Cosimo Cecchi Date: 2011-02-16 window-pane: move code around Makes things more readable. M src/nemo-window-pane.c M src/nemo-window-pane.h commit a0e572e833c0e27c147d99094dc5655297a38be5 Author: Cosimo Cecchi Date: 2011-02-16 location-bar: remove manual API for setting insensitive widgets It's not needed anymore M src/nemo-location-bar.c M src/nemo-location-bar.h commit dd6b7f734252fb9a3813be9856e6c8a44c9bc01a Author: Cosimo Cecchi Date: 2011-02-16 pathbar: remove hackish API M src/nemo-pathbar.c M src/nemo-pathbar.h commit 79c27eb5fbe998a0ed2f79541b4487db5f575958 Author: Cosimo Cecchi Date: 2011-02-16 navigation-window-pane: make the whole toolbar insensitive when inactive M src/nemo-navigation-window-pane.c commit d2c02297befb39526408d938b46cd8269d9d8549 Author: Cosimo Cecchi Date: 2011-02-15 window: remove some other useless code M src/nemo-spatial-window.c M src/nemo-window-private.h M src/nemo-window.c commit 63d5316f6bf85e41bc5be76d551a19c55ab07957 Author: Cosimo Cecchi Date: 2011-02-15 window: remove unused code M src/nemo-window.c M src/nemo-window.h commit 476d462bce0bce5fdc367daea3e14be8603f5c3d Author: Cosimo Cecchi Date: 2011-02-15 all: remove the concept of global history list It's not that useful now that nemo is not a long running application anymore. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-window-manage-views.c M src/nemo-window-private.h M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c commit 8974c917ecb202a0dad4871c79dc8d7306e28feb Author: Cosimo Cecchi Date: 2011-02-15 window-menus: move bookmark-related menu code where it belongs M src/nemo-window-bookmarks.c M src/nemo-window-menus.c commit 7309d5576f28de33e9a5e5653037264110893490 Author: Cosimo Cecchi Date: 2011-02-15 ui-utilities: centralize a helper function M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h M src/nemo-navigation-window-menus.c M src/nemo-window-menus.c commit 1755d56bdfefabf0b764aa3531e93f8fb18d73b0 Author: Cosimo Cecchi Date: 2011-02-15 window-pane: remove active_slots madness We can't have more than one active slot at the same time anyway. M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 3a27963142a0ef942631f88f2576f8bc29076898 Author: Cosimo Cecchi Date: 2011-02-15 navigation-window-pane: cleanup header M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h commit c4d48d522dccb915041c9521789a47d2bea0e1e4 Author: Cosimo Cecchi Date: 2011-02-15 window: cleanup window_pane_zoom madness M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 75f4f95bed048d955cabd7e521b6cc78182a0903 Author: Cosimo Cecchi Date: 2011-02-15 search-bar: simplify boilerplate code M src/nemo-search-bar.c commit 28afe6fde1d12083b915f0040c84157ebd461df7 Author: Cosimo Cecchi Date: 2011-02-15 navigation-window: set/unset text on 'Search' according to split mode M src/nemo-navigation-window.c commit 3e0fa2ef6166160131f4d0051e3ac0c065be52e0 Author: Cosimo Cecchi Date: 2011-02-15 view: use the right label if we're searching M src/nemo-view.c commit 600352c410a57214cc8fbb9789cf6b43dde55388 Author: Cosimo Cecchi Date: 2011-02-15 navigation-window: use g_settings_bind() a little more M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h commit d05c85a0808c48b987dbc438538530f8506d9dfd Author: Cosimo Cecchi Date: 2011-02-15 style: add some junction properties M src/nemo-toolbar.c M src/nemo-view.c commit 193f850cd11d909a0af9e95ec0dea7ad91c62160 Author: Cosimo Cecchi Date: 2011-02-15 ui-utlities: remove unused function M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h commit 6ebdfd9b5477178c9ab28c19e270b9dc4a53d6df Author: Cosimo Cecchi Date: 2011-02-15 window: don't care looking for toolbar extension items As we removed them. M src/Makefile.am M src/nemo-navigation-window-slot.c M src/nemo-window-manage-views.c D src/nemo-window-toolbars.c commit d3cee086e7be525046c8a16a08b15bfa996871fa Author: Cosimo Cecchi Date: 2011-02-15 libnemo-extension: remove the ability to add toolbar items We want to fully control our toolbar now. M configure.in M libnemo-extension/nemo-menu-provider.c M libnemo-extension/nemo-menu-provider.h commit 417bb5c31758a3b321fbac0d53402bed1034c6db Author: Cosimo Cecchi Date: 2011-02-15 navigation-window: use g_settings_bind() for statusbar visibility M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h commit 1373f01db2180f080e1d7b02e1655fecb33c21f2 Author: Cosimo Cecchi Date: 2011-02-15 toolbar: fix toolbar with split pane The way we used to instantiate the toolbar, from the navigation window UIManager, did not work fine in the new UI design, as we have a toolbar for each pane now; so we must instantiate a new UIManager for each pane, and add to it the navigation action group to fetch actions from. M src/Makefile.am M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-ui.xml A src/nemo-toolbar-ui.xml M src/nemo-toolbar.c M src/nemo-toolbar.h commit 7131487c8bebbbad075b238ec03934a78cf233d9 Author: Cosimo Cecchi Date: 2011-02-15 places-sidebar: use a symbolic icon for eject M src/nemo-places-sidebar.c commit a572b7355b12a99083b7489bf991a8f929b1a80a Author: Cosimo Cecchi Date: 2011-02-15 view: accumulate floating bar status setting in a timeout We use half of the double-click-time as a good heuristic. M src/nemo-view.c commit 5a21e22cb0603a77d0a8bf89f6197c799df7ba4d Author: Cosimo Cecchi Date: 2011-02-14 css: theme things a bit more M data/nemo.css commit caf3233bfc9e7a6e4cd4ed41245ca5d02fdd46e0 Author: Cosimo Cecchi Date: 2011-02-14 window: hide resize grip M src/nemo-window.c commit acd688037d2a8ccf675526a46ee1d8180301cedd Author: Cosimo Cecchi Date: 2011-02-14 view: use the floating bar as a temporary statusbar if it's off We use a slightly different status message in this case, where we don't care about free space on the volume. M src/nemo-view.c commit dc80c71c1a742e0134401e765652672a71e46809 Author: Cosimo Cecchi Date: 2011-02-14 view: always create the floating bar in _init() And show/hide it and its components according to what we're currently doing. M src/nemo-view.c commit b30c9ad791961a6cbf5622c1e3c34b8a088c0439 Author: Cosimo Cecchi Date: 2011-02-14 floating-bar: add _cleanup_actions() M src/nemo-floating-bar.c M src/nemo-floating-bar.h commit b75521b56f24bffa320ad7bb5bc61be6fa12cb96 Author: Cosimo Cecchi Date: 2011-02-14 floating-bar: add a bit more whitespace around the label M src/nemo-floating-bar.c commit b86054a34b9933180d9e847048a26d712505b04a Author: Cosimo Cecchi Date: 2011-02-14 sq iintegrate with view M src/nemo-view.c commit da3905c073456129874867df1572c8586a9a1f00 Author: Cosimo Cecchi Date: 2011-02-14 sq look like M data/nemo.css M src/nemo-floating-bar.c commit d44378ee0adf944bb13a987e4aa79abf1b15693e Author: Cosimo Cecchi Date: 2011-02-14 icon-view: cleanup of supports_* properties M src/nemo-desktop-icon-view.c M src/nemo-icon-view.c M src/nemo-icon-view.h commit 621106fd68a9e2d86f5e62876fd3e2844c2d85ac Author: Cosimo Cecchi Date: 2011-02-14 view: refactor supports_zooming into a property M src/nemo-desktop-icon-view.c M src/nemo-view.c M src/nemo-view.h commit 8544bdb09511cff7edc0382009e6ca0d1f607cd6 Author: Cosimo Cecchi Date: 2011-02-14 desktop-icon-view: adapt the desktop icon view to recent changes M src/nemo-desktop-icon-view.c M src/nemo-icon-view.c M src/nemo-icon-view.h commit 246d7177acf8fa2ddec512e96310f5e31889cfd5 Author: Cosimo Cecchi Date: 2011-02-14 view: add a 'show-floating-bar' property for classes to override So we can disable it on the Desktop. Also, cleanup the _class_init() code a bit while we're here. M src/nemo-view.c commit fec9449efc444e1dc25eeebf474a59f3aa16b75d Author: Cosimo Cecchi Date: 2011-02-14 view: hook up the overlay in the view M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-view.c M src/nemo-view.h commit db0c274ffaa2d4d95329716cad8b5af319fa9936 Author: Cosimo Cecchi Date: 2011-02-14 floating-bar: make it more similar to the mockups M data/nemo.css M src/nemo-floating-bar.c commit 8728a440f1fb9e661d5553b30e60f57f5460007d Author: Cosimo Cecchi Date: 2011-02-14 floating-bar: make the class more flexible - add dialog-like actions - add show/hide spinner M src/nemo-floating-bar.c M src/nemo-floating-bar.h commit bcec4c4ecf1b77d7e803f4e84689c6e3b1413fcf Author: Cosimo Cecchi Date: 2011-02-14 floating-bar: add NemoFloatingBar M src/Makefile.am A src/nemo-floating-bar.c A src/nemo-floating-bar.h commit 43f310d0c2ffa2c99c21b332650a9a86b9adc0ab Author: Cosimo Cecchi Date: 2011-02-14 squash overlay M src/gedit-overlay.c commit 5ca133a198326a5aac65c3ef3ddca9af2424bdf5 Author: Cosimo Cecchi Date: 2011-02-14 overlay: update GeditOverlay from upstream M src/gedit-overlay.c commit c16127a438ff9654cbd63dbbc3859dc9916d0160 Author: Cosimo Cecchi Date: 2011-02-11 overlay: borrow GeditOverlay implementation from gedit M src/Makefile.am A src/gedit-overlay-child.c A src/gedit-overlay-child.h A src/gedit-overlay.c A src/gedit-overlay.h commit f5e17ca2b9e27437963155c459f0584eccc45deb Author: Cosimo Cecchi Date: 2011-02-11 icon-view-container: remove useless dispose impl M src/nemo-icon-view-container.c commit f718677e60eafcb4214ef8d4a9831fd2e597e5d0 Author: Cosimo Cecchi Date: 2011-02-11 view: don't emit the clear signal M src/nemo-view.c commit 24f1f12a7092312af689c49b9f57d888ce9b6b8c Author: Cosimo Cecchi Date: 2011-02-11 selection-canvas-item: add getter for 'width-pixels' M libnemo-private/nemo-selection-canvas-item.c commit 79c9f9e854284c35fc8485efed4850787799a1cf Author: Cosimo Cecchi Date: 2011-02-11 css: style the floating bar according to the mockups M data/nemo.css commit c27b221329aedbe9b18c6bf02a49193475390a2d Author: Cosimo Cecchi Date: 2011-02-11 navigation-window: use a symbolic icon for the search button M src/nemo-navigation-window-menus.c commit b4f5d1a9eb4d1389a1c198bb16a28ca35bdf5f60 Author: Cosimo Cecchi Date: 2011-02-11 navigation-window: remove spinner code M src/nemo-navigation-window.c M src/nemo-window-toolbars.c commit 42f53017794f288a7c8709b297f0f6de1c368e94 Author: Cosimo Cecchi Date: 2011-02-11 selection-canvas-item: make fade-out time configurable M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-selection-canvas-item.c M libnemo-private/nemo-selection-canvas-item.h commit 5b3208302e2bb5a3d8f2f68ac785a4aa64e8b8a6 Author: Cosimo Cecchi Date: 2011-02-11 selection-canvas-item: make sure the item is destroyed after fading out M libnemo-private/nemo-selection-canvas-item.c commit e16f5d44fa67e2222f3a3ba30842e5697d76078f Author: Cosimo Cecchi Date: 2011-02-11 icon-container: only use icon elements to calculate layout bounds Canvas items like e.g. a NemoFloatingBarItem do not add up to the layout bounds calculation. M libnemo-private/nemo-icon-container.c commit 3c749cf9da882043cc5a5cb938f8831831dec768 Author: Cosimo Cecchi Date: 2011-02-11 selection-canvas-item: remove useless Xrandr code which does nothing This code doesn't seem to actually do anything M configure.in M libnemo-private/nemo-selection-canvas-item.c commit 854d310d34de8c45a43d7b94755fde45de2540fa Author: Cosimo Cecchi Date: 2011-02-10 navigation-window: cleanup cast madness M src/nemo-navigation-window.c commit f84f5bb0379b0eea4a9e4e1df72f3038587269eb Author: Cosimo Cecchi Date: 2011-02-10 navigation-window: ensure toolbar search button toggles as expected M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit d02d193409f53d11bb68ea97683ddc2dc83a088a Author: Cosimo Cecchi Date: 2011-02-10 window-menus: set is-important to 'Search' M src/nemo-navigation-window-menus.c commit ec87bd5216871dc2cc8c539b51f45be4096bcd2f Author: Cosimo Cecchi Date: 2011-02-10 navigation-window: remove commented out code M src/nemo-navigation-window.c commit f269eb0f1ff68c1f2ede2c8533a3764cafa11cf8 Author: Cosimo Cecchi Date: 2011-02-10 window-menus: remove is-important from back/forward nav actions M src/nemo-navigation-window-menus.c commit 67946b38ce482201e0da7dbf6e955e06038fa2c9 Author: Cosimo Cecchi Date: 2011-02-10 toolbar: build the toolbar and the location bar with a GtkUIManager M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-ui.xml M src/nemo-toolbar.c M src/nemo-toolbar.h commit ba531b1184310455127fa06691f3722052a2eb6c Author: Cosimo Cecchi Date: 2011-02-10 window-menus: merge the UI from XML while initializing actions Because we need it to be ready when setting up the window pane M src/nemo-navigation-window-menus.c commit 80ea58e844365d0bb097436ed8c0359e07cfd793 Author: Cosimo Cecchi Date: 2011-02-10 navigation-window: initialize actions before setting up the pane This is needed so that the pane can use those actions to build the toolbar. We also have to remove the code that updates split view actions from _initialize_actions(), as it requires the pane is realized. It should not be much of an issue, as that code is called when loading an URI anyway (and so it is called afterwards when loading the window). M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c commit 5756ac82bab3a63708544aeef47ee5b0e9b508da Author: Cosimo Cecchi Date: 2011-02-10 navigation-action: do not use a GtkMenuToolButton As it always has dropdown arrows, which we don't want to see. Make it a Firefox-like button instead, where you can either right click or keep the mouse button pressed for an amount of time to activate the context menu. M src/nemo-navigation-action.c commit 7363013201ec2950958db529ea96c0f2442b3c53 Author: Cosimo Cecchi Date: 2011-02-09 all: remove unused GSettings keys M libnemo-private/nemo-global-preferences.h M src/nemo-file-management-properties.c commit 66c46dd6d2cdbaeae38e9b42b083c17ebf3ed65d Author: Cosimo Cecchi Date: 2011-02-09 location-bar: use dash and not underscore in signal name M src/nemo-location-bar.c commit 0ea4ca0709c361a4e2adf5e061108abf5c7017e3 Author: Cosimo Cecchi Date: 2011-02-09 navigation-window-menus: use g_settings_bind() for toolbar visibility This also reduces the code complexity by a fair bit M src/nemo-navigation-window-menus.c commit 47958798846c8bbf85f2e28abc9b66d8266e890f Author: Cosimo Cecchi Date: 2011-02-09 navigation-window: comment out old toolbar code for now M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c commit 211dda1ded746708019b11dd497dde21adfb8c4d Author: Cosimo Cecchi Date: 2011-02-09 navigation-window: cope with NemoNavigationWindowPane changes M src/nemo-navigation-window.c commit 1a95b0117e095885fc6ec4c3903c909c4f48f377 Author: Cosimo Cecchi Date: 2011-02-09 slot: remove NemoBarMode M src/nemo-navigation-window-slot.h commit ff264ed954842d933c9fa5dcd6d8b48366ce60c6 Author: Cosimo Cecchi Date: 2011-02-09 navigation-window-pane: rework to make use of NemoToolbar M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h commit 36e9be912735ce02929aaace8fb618e31bb91b59 Author: Cosimo Cecchi Date: 2011-02-09 navigation-window: don't use search_bar_is_showing() NemoToolbar is smart enough to take care of visibility alone. M src/nemo-navigation-window.c commit 865556e2e2073c41f687a4752571bfdf593deeb3 Author: Cosimo Cecchi Date: 2011-02-09 navigation-window: don't tirgger toolbar visibility with GSettings It's done internally by NemoToolbar M src/nemo-navigation-window.c commit b34fb9648fcd58f17e09590e2dc9e0dae8af3757 Author: Cosimo Cecchi Date: 2011-02-09 navigation-window: remove methods to toggle toolbar visibility This will be done automatically by NemoToolbar and inside the methods to trigger temporary visibility. M src/nemo-navigation-window.c M src/nemo-navigation-window.h commit a56b468038964ba6ceea5efae74b1520d8e2429a Author: Cosimo Cecchi Date: 2011-02-09 window-toolbars: clean up includes M src/nemo-window-toolbars.c commit bd36e2d04baeeeeafc2fcf2f00383fbc367de735 Author: Cosimo Cecchi Date: 2011-02-09 toolbar: add NemoToolbar M src/Makefile.am A src/nemo-toolbar.c A src/nemo-toolbar.h commit ca1fa0c2b05edd8e76bb6314a7cb7c1adc4f3319 Author: Cosimo Cecchi Date: 2011-02-08 navigation-bar: remove useless abstract class Merge the useful pieces into NemoLocationBar itself, which is the only implementor anyway. M src/Makefile.am M src/nemo-location-bar.c M src/nemo-location-bar.h D src/nemo-navigation-bar.c D src/nemo-navigation-bar.h M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit 6f0a2036197cf03095b0a775c35983bc42885fb1 Author: Kjartan Maraas Date: 2011-02-17 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit dde08b0914b1ec42ecfbbbee47673e8fe3975319 Author: Sweta Kothari Date: 2011-02-17 Updated Gujarati Translations M po/gu.po commit f8bea223f63eb0ed62ddf22062c94d1c76fea234 Author: Alexander Shopov Date: 2011-02-17 Updated Bulgarian translation M po/bg.po commit 8f9dda634d5143dda92a8bf987ca083225ab174c Author: Mario Blättermann Date: 2011-02-13 [l10n] Updated German translation M po/de.po commit ae6122fb8212e56f2c5a3afad5b84d532ed3ffc1 Author: Changwoo Ryu Date: 2011-02-13 Updated Korean translation M po/ko.po commit 17323012e2ebc3b65be673a7524e021f84434810 Author: Yaron Shahrabani Date: 2011-02-12 Updated Hebrew translation. M po/he.po commit b0760d0c50aea36ab95a81794f35b739c3ab08f5 Author: Chao-Hsiung Liao Date: 2011-02-11 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 06e1c2822bc543566eb71ea6f6208a3c82da67fe Author: Mahyar Moghimi Date: 2011-02-10 Updating Persian Translation M po/fa.po commit a425e4ed04d0323e1770ca4889affc4564c66a05 Author: Mahyar Moghimi Date: 2011-02-10 Updating Persian Translation M po/fa.po commit 20df7410f143960c206efce19e0f404df3265c93 Author: Mahyar Moghimi Date: 2011-02-10 Updating Persian Translation M po/fa.po commit 917a3e2097f52d2e8223011b672dffadc6674472 Author: Cosimo Cecchi Date: 2011-02-08 gsettings: rename our gschema path to /org/gnome/nemo M libnemo-private/org.gnome.nemo.gschema.xml.in commit fbabd8e4f13fb7312f3921f3a1633b586a4b048c Author: Cosimo Cecchi Date: 2011-02-08 editable-label: chain up in style_updated() M eel/eel-editable-label.c commit 4e47a409e990418f541ec9c5f5b5e1567eb04297 Author: Alexander Larsson Date: 2011-02-07 Avoid spew in the common case of non-existing desktop metadata file M libnemo-private/nemo-desktop-metadata.c commit 98feec44b9d93fc029e95b682ec29eb104c60320 Author: Craig Keogh Date: 2011-02-06 Remove configure.in ACLOCAL_FLAGS, now in Makefile.am (GNOME bug 641629) M configure.in commit 43573325a03536a93869f0a080dc0b2257e7e258 Author: Craig Keogh Date: 2011-02-06 Honor aclocal flags (GNOME bug 641629) M Makefile.am commit 01e5b514d9155e73448365d5f994a967da2d58f2 Author: Cosimo Cecchi Date: 2011-02-07 pathbar: use "Home" for the home button, instead of the username M src/nemo-pathbar.c commit df482adbbdb62f422f9c3eabb5aa1ac7a638e700 Author: Kjartan Maraas Date: 2011-02-06 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit ed109037524dec6dbf11b4a840eb9b4ea82c9e2f Author: Fran Diéguez Date: 2011-02-06 Updated Galician translations M po/gl.po commit c926b072165b822af8dfd6f5d8a413809bb6b541 Author: Cosimo Cecchi Date: 2011-02-05 bookmark: apply name and custom-name during construction M libnemo-private/nemo-bookmark.c commit 8233aadcdd5dcf57d66c7c70df4e507ed32020ed Author: Ivar Smolin Date: 2011-02-05 [l10n] Updated Estonian translation M po/et.po commit 52d148c29a931ffaee715f714e7fd507901f7054 Author: Daniel Mustieles Date: 2011-02-05 Updated Spanish translation M po/es.po commit 21527ca0cdfc3bb4fa2bba86363ffd2b8a795fd1 Author: Daniel Mustieles Date: 2011-02-05 Updated Spanish translation M po/es.po commit eb69bfd91cca98f40f1c60f1198224c6b0e9ac61 Author: Ivar Smolin Date: 2011-02-05 [l10n] Updated Estonian translation M po/et.po commit 842a639da7450449877a31f1b0a52188c737b6c6 Author: Cosimo Cecchi Date: 2011-02-04 i18n: fix POTFILES.in M po/POTFILES.in commit 9e5a32831826ad609f8ad5315e5b6f72bda5c51f Author: Cosimo Cecchi Date: 2011-02-04 Release 2.91.9 M NEWS M configure.in commit 82fb99a34a6c27f6881e0a049d9882756b615f42 Author: Stefano Teso Date: 2011-02-04 location-entry: fix auto-complete for non-local URIs https://bugzilla.gnome.org/show_bug.cgi?id=635333 M src/nemo-location-entry.c commit 1212e12456347da601a77de013082fd1beac8463 Author: Stefano Teso Date: 2011-02-04 query: don't crash with empty .savedSearch files Be more robust against empty .savedSearch files. https://bugzilla.gnome.org/show_bug.cgi?id=601205 M libnemo-private/nemo-query.c commit 8f5d29b21b2ab82250bf516f9263aa473dfd64f1 Author: Stefano Teso Date: 2011-02-04 bookmark: don't make the name/custom-name props construct-only This was probably a typo from the refactoring of the object. https://bugzilla.gnome.org/show_bug.cgi?id=641484 M libnemo-private/nemo-bookmark.c commit 59d7af27e1d62e01108058088c5f9faf980832b3 Author: Khaled Hosny Date: 2011-02-04 Updated Arabic translation M po/ar.po commit 41de4e52b43c8ed5c9118860dac7caa303ebbc5b Author: Cosimo Cecchi Date: 2011-02-04 list-view: add a FIXME comment M src/nemo-list-view.c commit 4f17fb7db7b8736ebb4fe82ddb1c279777847730 Author: Cosimo Cecchi Date: 2011-02-04 list-view: workaround a GtkTreeView regression See https://bugzilla.gnome.org/show_bug.cgi?id=641518 for details M src/nemo-list-view.c commit f324265d1795a7d23af3ece0e48ce9479e1e5bb5 Author: Luca Ferretti Date: 2011-02-04 Updated Italian translation M po/it.po commit c2bcaeb0da84d5759571e365a3a5e71e48d70952 Author: Luca Ferretti Date: 2011-02-03 connect-server-dialog: add missing mnemonics and use proper capitalization M src/nemo-connect-server-dialog.c commit 5c89e3157752fa9311f0ca5e2310885187270ac8 Author: Yaron Shahrabani Date: 2011-02-04 Updated Hebrew translation. M po/he.po commit 11cc68cbcc154f7e84975861b26c177ae92547aa Author: Cosimo Cecchi Date: 2011-02-03 progress-ui: add a notification when all transfer complete M src/nemo-progress-ui-handler.c commit 046927432a01f7a4bb7a4dc9c96005548950ca79 Author: Cosimo Cecchi Date: 2011-02-03 progress-ui: add a "Show Details" action to the notification M src/nemo-progress-ui-handler.c commit 8536b7134f75f23c044772d583402bbe1ebf6174 Author: Cosimo Cecchi Date: 2011-02-03 progress-ui: first cut implemneting file ops progress with notifications M configure.in M src/nemo-application.c M src/nemo-progress-ui-handler.c commit b9fe2ecb4894895e063c4cbda5f62b7ad54b7449 Author: Cosimo Cecchi Date: 2011-02-02 progress-info: split UI of NemoProgressInfo into its own object M libnemo-private/nemo-progress-info.c M src/Makefile.am A src/nemo-progress-info-widget.c A src/nemo-progress-info-widget.h M src/nemo-progress-ui-handler.c commit adab8f5fe5681dcb06be4d6fbaa674624b49b6b5 Author: Cosimo Cecchi Date: 2011-02-02 progress-info: add NemoProgressUIHandler It will take care of the various states of file operation progress' user interface. M src/Makefile.am M src/nemo-application.c A src/nemo-progress-ui-handler.c A src/nemo-progress-ui-handler.h commit a0f89473830575ae39a568608bc58f3f92c6f4a4 Author: Cosimo Cecchi Date: 2011-02-01 progress-info: split progress information notify into a new manager M libnemo-private/Makefile.am A libnemo-private/nemo-progress-info-manager.c A libnemo-private/nemo-progress-info-manager.h M libnemo-private/nemo-progress-info.c M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h M src/nemo-application.c M src/nemo-application.h M test/test-copy.c commit 2a86f1c60ba847951145ea3570bcf4e7a26a18f1 Author: Fran Diéguez Date: 2011-02-03 Updated Galician translations M po/gl.po commit bfece2283aacd609ce3466b6f27539b03f215e8e Author: Mattias Põldaru Date: 2011-02-03 [l10n] Updated Estonian translation M po/et.po commit 52b59769ea4944eaebdef26c271b8c1c45aa0493 Author: Daniel Nylander Date: 2011-02-02 Updated Swedish translation M po/sv.po commit eb6a4a8eaea16b6fa4d377b759e306016073d2fe Author: William Jon McCann Date: 2011-02-02 Use Files as launcher name https://bugzilla.gnome.org/show_bug.cgi?id=641256 M data/nemo.desktop.in.in commit a293b96241714a8d07e2b8aecd34ce61aff117ad Author: Cosimo Cecchi Date: 2011-02-01 eel: remove unused eel-canvas-util M eel/Makefile.am D eel/eel-canvas-util.c D eel/eel-canvas-util.h M libnemo-private/nemo-icon-canvas-item.c commit 2870f8f8ef38350451ddf36dfc704b2a0e66c616 Author: Cosimo Cecchi Date: 2011-02-01 selection-canvas-item: fix copyright header I copied it from the wrong file. M libnemo-private/nemo-selection-canvas-item.c M libnemo-private/nemo-selection-canvas-item.h commit 6b03a56dbd932de2b274bf61f78ae12f4ed7da0b Author: Cosimo Cecchi Date: 2011-02-01 icon-container: use the fade out effect for rubberbanding M libnemo-private/nemo-icon-container.c commit bd30e3d0670e437c55e82b544565a539331154d5 Author: Cosimo Cecchi Date: 2011-02-01 selection-canvas-item: implement a fade out effect M libnemo-private/nemo-selection-canvas-item.c M libnemo-private/nemo-selection-canvas-item.h commit b13969228d4d96c3ff677090e888f2aa9d026083 Author: Cosimo Cecchi Date: 2011-02-01 selection-canvas-item: simplify GObject properties M libnemo-private/nemo-selection-canvas-item.c M libnemo-private/nemo-selection-canvas-item.h commit 8853b7bf92271ff093803ccdfb3079512d12149d Author: Cosimo Cecchi Date: 2011-02-01 Move EelRectCanvasItem to its own object in libnemo-private/ eel-canvas-rect-ellipse has quite some unused code that make it hard to modify. M eel/Makefile.am D eel/eel-canvas-rect-ellipse.c D eel/eel-canvas-rect-ellipse.h M libnemo-private/Makefile.am M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c A libnemo-private/nemo-selection-canvas-item.c A libnemo-private/nemo-selection-canvas-item.h commit 67687dd50433d620ddd931d983462ca131dd48bb Author: Cosimo Cecchi Date: 2011-02-01 desktop-metadata: initialize a variable M libnemo-private/nemo-desktop-metadata.c commit 513e94c31e22d340888b139c50c43b6f2d037703 Author: Cosimo Cecchi Date: 2011-02-01 desktop-metadata: append a terminator for single-length strv values This is needed so that we can differentiate between single-length strv and regular string values when reading them back from the keyfile, which does not store the type of its values. This way, we make sure that we always respect the actual metadata type in GFileInfo. M libnemo-private/nemo-desktop-metadata.c commit 25754a54bb0889187d9b5cb45e6c32ae9321f038 Author: Cosimo Cecchi Date: 2011-02-01 desktop-metadata: group multiple desktop metadata saving calls M libnemo-private/nemo-desktop-metadata.c commit aa552113606e24d331c6c62de0f5406351600d7f Author: Cosimo Cecchi Date: 2011-01-31 Release 2.91.8 M NEWS M configure.in commit 3f55f369c00044a3d93c6bb10aa9e7c025548d5d Author: Cosimo Cecchi Date: 2011-01-31 build: remove GConf dependency altogether M configure.in commit 4227f0b1708d36d464ffce207c75b429bec1917b Author: Cosimo Cecchi Date: 2011-01-31 convert-metadata: don't migrate the desktop metadata to GConf M src/nemo-convert-metadata.c commit 389789e8f102f794780a2842e9506dc23ddd6a08 Author: Cosimo Cecchi Date: 2011-01-31 preferences: don't use GConfClient anymore M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h commit 632bf39a23e5457d76540063eff69b36e36459d0 Author: Cosimo Cecchi Date: 2011-01-31 desktop-metadata: use a keyfile instead of GConf to store it M libnemo-private/Makefile.am M libnemo-private/nemo-desktop-directory-file.c M libnemo-private/nemo-desktop-directory-file.h M libnemo-private/nemo-desktop-icon-file.c A libnemo-private/nemo-desktop-metadata.c A libnemo-private/nemo-desktop-metadata.h M libnemo-private/nemo-metadata.h commit c62a8ff91596da4d14b56a52400baa52e05c2ccc Author: Cosimo Cecchi Date: 2011-01-31 desktop-directory-file: don't use eel boilerplate M libnemo-private/nemo-desktop-directory-file.c commit 3d0dc4d6d763c70630e82f5a5c69a6745af70866 Author: Gabor Kelemen Date: 2011-01-31 Fix a mistranslation M po/hu.po commit 678c5216ebe3987b7b268d27fc0af78f09e58d94 Author: Cosimo Cecchi Date: 2011-01-30 sort-order: resync sort order property with NemoFileSortType This makes the sorting preference reliably work again. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/org.gnome.nemo.gschema.xml.in M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit 6a6c18d4d62adc14cfc41769ab5ce37793d51c16 Author: Cosimo Cecchi Date: 2011-01-30 icon-view: save sort metadata only when the user explicitly changes it M src/nemo-icon-view.c commit c1fa2a49e02552a2fb334f7cb766a32f0c201ad1 Author: Cosimo Cecchi Date: 2011-01-30 eel: remove eel_g_settings_add_auto_* functions M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit 253345f0841a38fcf02023bc2acd8bdc26842160 Author: Cosimo Cecchi Date: 2011-01-30 all: don't use eel_g_settings_add_auto_* methods It makes no sense to use caching now with GSettings, as lookup operations are fast enough. M libnemo-private/nemo-file.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-thumbnails.c M src/nemo-desktop-icon-view.c M src/nemo-icon-view.c M src/nemo-list-view.c commit e14351baf9f252a57395f2982e05ccecc504d646 Author: Cosimo Cecchi Date: 2011-01-30 icon-view: move desktop view's get_view_id to a proper implementation Instead of hardcoding IS_DESKTOP_ICON_VIEW() checks in the parent class. M src/nemo-desktop-icon-view.c M src/nemo-icon-view.c commit fdf30fd8c54c25e952ecc313af6d5325cf062452 Author: A S Alam Date: 2011-01-29 update Punjabi Translation by A S Alam M po/pa.po commit b97ee5da0bb1ab6ad4cc0f2a1d795ee7f64b5ec5 Author: Cosimo Cecchi Date: 2011-01-28 Update MAINTAINERS and DOAP files M MAINTAINERS M nemo.doap commit 454b2caf1ba89a62321486db10c87e63217031b8 Author: Cosimo Cecchi Date: 2011-01-28 application: don't call mount_removed_callback() on pre-unmount The unmount process follows this flow: - pre-unmount is emitted - GIO performs checks to see whether the volume is safe to unmount, and spawns GtkMountOperation dialogues accordingly - if everything is fine, the unmount signal is emitted So, it's wrong to close or redirect windows from pre-unmount, as the mount could actually not be unmounted after that. M src/nemo-application.c commit 35bf6c86b53b68a61389f270aa0ce1ff2715ff7c Author: Cosimo Cecchi Date: 2011-01-27 Clean up our desktop file (#640687) - remove the 'System' category - remove autostart interactions with gnome-session M data/nemo.desktop.in.in commit e7b6fd0e59ec49fbe6216c157eea2a92b384d39e Author: Tomas Bzatek Date: 2011-01-27 Clarify the reason for recent nemo_file_peek_display_name() workaround M libnemo-private/nemo-file.c commit 8f6245a80cfd571274813fe4d5d950769d02bfba Author: Tomas Bzatek Date: 2011-01-27 Prevent a crash in nemo_file_peek_display_name() on invalid NemoFile This is more a workaround only, expect assert failures at other places when something bad happens. There's a race condition somewhere, this patch only prevents immediate crash. Patch by Marcus Husar https://bugzilla.gnome.org/show_bug.cgi?id=602500 M libnemo-private/nemo-file.c commit fd03c910a73ba18459e68baaf15e8dd295acd5c1 Author: Stefano Teso Date: 2011-01-26 places-sidebar: allow keyboard navigation with Enter/Space (#637768) M src/nemo-places-sidebar.c commit 4f4c07b1f9964d437f70c89d94e9585429a69f91 Author: Fran Diéguez Date: 2011-01-27 Get Galician translations back from wrong commit M po/gl.po commit dace8ba5c2068e80bb9d99a1370f0c1a989fb72a Author: Fran Diéguez Date: 2011-01-27 QA of Galician translations M po/gl.po commit 17793d3bb90dbde51c95f73867bf75d6546cf88f Author: Fran Diéguez Date: 2011-01-27 QA of Galician translations M po/gl.po commit a63aaa68f14bec6507d36e856a4ed79d969b1be3 Author: Cosimo Cecchi Date: 2011-01-25 desktop-background: make sure to hold a ref in the 'changed' idle Otherwise we might end up accessing object fields after it was destroyed. https://bugzilla.gnome.org/show_bug.cgi?id=640420 M libnemo-private/nemo-desktop-background.c commit 6d079cc40ab1dfab5b7d60cac44b655d4d243f3d Author: Cosimo Cecchi Date: 2011-01-24 editable-label: fix some drawing regressions Also, remove the copy/pasted gtkpango code again, as we can have a better rendering without it. M eel/eel-editable-label.c commit d4230de8667764e02dbb966b5d806ff78ced2fd5 Author: Cosimo Cecchi Date: 2011-01-24 all: silence new warnings from GCC 4.6 GCC 4.6 introduced a new warning about variables declared and initialized, but not really used in the function body. Remove all of these occurrences to build cleanly. M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas.c M libnemo-private/nemo-clipboard.c M libnemo-private/nemo-desktop-icon-file.c M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-entry.c M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-saved-search-file.c M libnemo-private/nemo-search-directory-file.c M libnemo-private/nemo-vfs-directory.c M libnemo-private/nemo-vfs-file.c M nemo-sendto-extension/nemo-nste.c M src/nemo-application.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-connect-server-dialog.c M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-main.c M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-pathbar.c M src/nemo-places-sidebar.c M src/nemo-properties-window.c M src/nemo-query-editor.c M src/nemo-tree-sidebar-model.c M src/nemo-tree-sidebar.c M src/nemo-view.c M src/nemo-window-manage-views.c M src/nemo-window.c commit 155cc03271fd7db1da4af7d60dcedfe8acdc2900 Author: Funda Wang Date: 2011-01-23 Updated zh_CN translation. M po/zh_CN.po commit 7e47ccdee2c8be8b16fad0da3320141f27596bfa Author: Piotr Eljasiak Date: 2011-01-22 Fix typo (G_TYPE_INSTANCE_CHECK_TYPE -> G_TYPE_CHECK_INSTANCE_TYPE) M libnemo-private/nemo-mime-application-chooser.h M libnemo-private/nemo-module.c M libnemo-private/nemo-tree-view-drag-dest.h M src/nemo-connect-server-dialog.h M src/nemo-connect-server-operation.h M src/nemo-location-dialog.h commit 0b4bb326cae5d8df888192f4c763211dff9e7f97 Author: Kristjan SCHMIDT Date: 2011-01-22 Updated Esperanto translation M po/eo.po commit 9f539e6fa5d2832b9b4788c338bbce66f81971f9 Author: Alexander Shopov Date: 2011-01-21 Updated Bulgarian translation M po/bg.po commit 187dc50c76da193f46aa7cb856a4ce1ea964b023 Author: Chao-Hsiung Liao Date: 2011-01-20 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 484c9a1bacd254795703c014a170b5801a1f3104 Author: Cosimo Cecchi Date: 2011-01-20 eel: remove eel-gdk-pixbuf-extensions M eel/Makefile.am D eel/eel-gdk-pixbuf-extensions.c D eel/eel-gdk-pixbuf-extensions.h commit 129d90ebcd83efd7d7f2ebc75c77922bd9771b9d Author: Cosimo Cecchi Date: 2011-01-20 all: remove unused includes of eel-gdk-pixbuf-extensions M eel/eel-gtk-extensions.c M eel/eel.h M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-thumbnails.c M src/nemo-properties-window.c commit 83a83e3a2200127889c9979240049124b7e9a182 Author: Cosimo Cecchi Date: 2011-01-20 icon-info: use gdk_pixbuf_new_from_stream_at_scale() M libnemo-private/nemo-icon-info.c commit 2103a49026fd1c406f2607ef7d070b3081835982 Author: Cosimo Cecchi Date: 2011-01-20 icon-canvas-item: simplify the code a bit M libnemo-private/nemo-icon-canvas-item.c commit f58a70a92a83f8979f43ed84fd79d9b764e6d7c6 Author: Cosimo Cecchi Date: 2011-01-20 eel: remove unused eel_pixbuf_render() M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h commit 8b13a044cc226cf1347831ef566938a24aa5f9a1 Author: Cosimo Cecchi Date: 2011-01-20 general: use eel_create_spotlight_pixbuf() M src/nemo-list-model.c M src/nemo-places-sidebar.c M src/nemo-tree-sidebar-model.c commit 09f0b79d854b00469410e2466897df6db5b4d51d Author: Cosimo Cecchi Date: 2011-01-20 icon-canvas-item: remove an useless snippet of drawing code M libnemo-private/nemo-icon-canvas-item.c commit a083fa0d0bbd99f1b74d28af305efeb71859e775 Author: Cosimo Cecchi Date: 2011-01-20 icon-container: hook to style_updated instead of style_set M libnemo-private/nemo-icon-container.c commit e652eb079514451313a67408c1cc3c8188ae0161 Author: Cosimo Cecchi Date: 2011-01-20 icon-container: remove unused style properties M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-private.h commit a1fa4eaa03493d6b69c5e79db296a83532974f63 Author: Cosimo Cecchi Date: 2011-01-20 icon-canvas-item: use eel_create_spotlight_pixbuf() Instead of passing eel_pixbuf_render() always the same values M libnemo-private/nemo-icon-canvas-item.c commit 207a2499a3f19b194acb93925084bbd7800fe0bc Author: Cosimo Cecchi Date: 2011-01-20 css: move the style properties from adwaita here M data/nemo.css commit 2a1fbaf839fc7eaae505e3534acd317e9dd47b1b Author: Cosimo Cecchi Date: 2011-01-19 canvas: fix an ACTIVE -> NORMAL typo from GtkStyleContext conversion M eel/eel-canvas.c commit d0d90599476e4f21d3e07fd670b6c18b6ba06794 Author: Cosimo Cecchi Date: 2011-01-19 icon-container: fix a couple of ACTIVE -> NORMAL typos M libnemo-private/nemo-icon-container.c commit e2ca42cac78cb0287a1bbb73030e7bba8b171970 Author: Cosimo Cecchi Date: 2011-01-19 icon-container: remove useless theming properties M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c commit 5bfc3e50c91c4c6fc129e9383e3f2f20a87be0cf Author: Cosimo Cecchi Date: 2011-01-19 views: use proper background color for inactive panes M libnemo-private/nemo-icon-container.c M src/nemo-list-view.c commit d55ca5df614a56f3d9750df1fbcfcca155dce0b4 Author: Marios Zindilis Date: 2011-01-19 Updated Greek translation M po/el.po commit bd179dad12aa8175ed7e02f9421c0d1ed125bd2a Author: Maxim V. Dziumanenko Date: 2011-01-18 Updated Ukrainian translation M po/uk.po commit 9eee9ff6ca3e93d5d363725282d8ba393a1e6d01 Author: Markus T. Vartiainen Date: 2011-01-18 list-view: jump to parent with left key on collapsed rows (#639688) M src/nemo-list-view.c commit c6fa6b2062a1adf3e4945824048b3771edb35ebe Author: Cosimo Cecchi Date: 2011-01-18 places-sidebar: plug a leak and cleanup code a bit M src/nemo-places-sidebar.c commit f394ce8c052dd65c8343106964ba4431d97d261c Author: Cosimo Cecchi Date: 2011-01-18 icon-container: plug a memory leak M libnemo-private/nemo-icon-container.c commit 8f15b28dd7afdd1a5c5b9c0d54c05d978a10461a Author: Cosimo Cecchi Date: 2011-01-18 eel: plug some leaks in gsettings helpers M eel/eel-glib-extensions.c commit 04d3aa67294f300f3b0bd927be5f45666260c5d3 Author: Nicolò Chieffo <84yelo3@gmail.com> Date: 2011-01-17 progress-info: use a symbolic icon for the notification area (#596568) M libnemo-private/nemo-progress-info.c commit 12c3841911b47e1496d8c8fea2429cf3ca4bf8d0 Author: Ivar Smolin Date: 2011-01-17 [l10n] Updated Estonian translation M po/et.po commit 9e016ee923a2625ebd4d66cf18f3a6d2c903e6c8 Author: Cosimo Cecchi Date: 2011-01-17 progress-info: tie the application life to the whole file operation And not to the progress widget only, as that - starts hidden for the first seconds - is not destroyed when the operation finishes, but only hidden Using g_application_hold/release with the progress operation lifetime seems like a better way to deal with the app lifecycle. M libnemo-private/nemo-progress-info.c commit a11b54d5752d9792f9af05942901396330688cf7 Author: Ivar Smolin Date: 2011-01-16 [l10n] Updated Estonian translation M po/et.po commit 7cbc6f2ee4f85f6923bf56b4891f91c04edaae31 Author: Daniel Mustieles Date: 2011-01-16 Updated Spanish translation M po/es.po commit 8efb55bc266f8b471059b9bc83de19f4085fef48 Author: Xan Lopez Date: 2011-01-16 places-sidebar: remove unused variable It was being freed uninitialized, which caused a warning (and a build failure with -Werror). M src/nemo-places-sidebar.c commit fcd8981ef68dd351910539302965476a66f0218f Author: Ivar Smolin Date: 2011-01-14 [l10n] Updated Estonian translation M po/et.po commit bf5d259288868a70258e63960ddc0eabe96bf9c8 Author: Cosimo Cecchi Date: 2011-01-14 application: don't quit if there are pending file operations Now that we're a single-window application, this has become much more relevant. M libnemo-private/nemo-progress-info.c M libnemo-private/nemo-ui-utilities.c M libnemo-private/nemo-ui-utilities.h M src/nemo-application.c commit f4637ff4481ee6d7d1e0453a5bd3ec4ac9dca17d Author: Cosimo Cecchi Date: 2011-01-14 bookmark: don't call into nemo_file methods unconditionally As NemoBookmark's file might be NULL in some cases. M libnemo-private/nemo-bookmark.c commit c55ddd80f16e56a366fe9e746c3632521d10f042 Author: Cosimo Cecchi Date: 2011-01-14 bookmark-list: avoid setting the bookmark icon by hand When creating a bookmark from the GTK+ list, otherwise we end up overriding NemoBookmark's special casing when reloading the list M src/nemo-bookmark-list.c commit c637811c268abdecae3a3720b1f77fc7fe5bcd6a Author: Cosimo Cecchi Date: 2011-01-14 bookmark: add debug messages M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h commit ce44fecb484ff1d6ae069446e3296f223b247c87 Author: Fran Diéguez Date: 2011-01-14 Updated Galician translations M po/gl.po commit 35a9e17696c0ff126a327f61046ab9e662a1738d Author: Ivar Smolin Date: 2011-01-13 [l10n] Updated Estonian translation M po/et.po commit ae1e300376b3479e14045892caa720dd3903a89c Author: Cosimo Cecchi Date: 2011-01-12 window-manage-views: re-add an accidentally removed snipped of code M src/nemo-window-manage-views.c commit d4df96c1e5c6bde62fd55dab1cbaae8a57f2b92e Author: Cosimo Cecchi Date: 2011-01-12 all: use new NemoBookmark API M src/nemo-bookmark-list.c M src/nemo-bookmark-list.h M src/nemo-bookmarks-window.c M src/nemo-places-sidebar.c M src/nemo-window-bookmarks.c M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-slot.c commit 3aa0396da2014b35f0ef21dffd29e4953667ceb2 Author: Cosimo Cecchi Date: 2011-01-12 all: use nemo_bookmark_get_gicon() M libnemo-private/nemo-ui-utilities.c M src/nemo-bookmarks-window.c M src/nemo-window-menus.c commit f6850158283858aae24ed3f1982341bc1b587d28 Author: Cosimo Cecchi Date: 2011-01-12 file-utilities: make compute_title_for_location() return the basename As a last-resort fallback. M libnemo-private/nemo-file-utilities.c commit 7cbd07aa15a3c099dfd69ab7cdcfd3dcbea38b51 Author: Cosimo Cecchi Date: 2011-01-12 file: remove unused code M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M src/nemo-pathbar.c commit f1c782c13dd675bafffb2a4d85900da52be88f3f Author: Cosimo Cecchi Date: 2011-01-12 file: make nemo_file_get_gicon() return custom icons too M libnemo-private/nemo-file.c commit ef5ebfe5db767a2f703e1f5cc57f6ab829d5499a Author: Cosimo Cecchi Date: 2011-01-12 bookmark: refactor the object - add properties for location, name, custom name and icon - make the code less convoluted, removing the appearance-changed signal - remove _get_pixbuf(), _get_icon() should be used instead M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-bookmark.h commit 8057f745fe1e741c8f2a3756efebc7c7e15cbf68 Author: Khaled Hosny Date: 2011-01-12 Updated Arabic translation M po/ar.po commit 906cea0bc4b2deac177e417551109b8319ee78cd Author: Yaron Shahrabani Date: 2011-01-11 Updated Hebrew translation. M po/he.po commit 31461f9f4782b0df89a14812c252addaa7d6e983 Author: Cosimo Cecchi Date: 2011-01-11 mime-actions: update the filtered out desktop files for folders M src/nemo-mime-actions.c commit a22f2501c8c00f16150d1de98d7039063a4e002a Author: Cosimo Cecchi Date: 2011-01-11 desktop-files: cleanup desktop files installed by nemo In the 3.0 world, nemo doesn't have to install a hundred of desktop files, as it's just a regular application. Tweak the default desktop file to make it suitable for being the only one, and remove the others. M configure.in M data/Makefile.am D data/nemo-browser.desktop.in.in D data/nemo-computer.desktop.in.in D data/nemo-folder-handler.desktop.in.in D data/nemo-home.desktop.in.in M data/nemo.desktop.in.in M po/POTFILES.in M src/Makefile.am D src/network-scheme.desktop.in commit f2533adf30822d3839b67c5f81e410b5e212f7a7 Author: Maciej Piechotka Date: 2011-01-11 Fix handling of AM_CONDITIONAL M configure.in commit 395ba0fd8f679e6e2674eb0ce5976638edb9d979 Author: Cosimo Cecchi Date: 2011-01-11 window: remove unused and confusing code M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 48ac967bff48e7e4a38c96859ebfd2f522179fa3 Author: Cosimo Cecchi Date: 2011-01-11 desktop-window: implement the right method for setting window title https://bugzilla.gnome.org/show_bug.cgi?id=555425 M src/nemo-desktop-window.c commit f9cb9e158b365ef3d1ed27cfa0ae138f367bd42a Author: Cosimo Cecchi Date: 2011-01-11 i18n: update POTFILES.in M po/POTFILES.in commit 9367d11d3a00d5192174f744eeea9e395fcd501a Merge: 6430fd4 b13efe1 Author: Cosimo Cecchi Date: 2011-01-11 Merge branch 'refactor' commit b13efe1653ea1932bba8c3f3555729d34a21412c Author: Cosimo Cecchi Date: 2011-01-11 empty-view: fix it to make it work again with current architecture M src/Makefile.am M src/nemo-application.c M src/nemo-empty-view.c M src/nemo-empty-view.h commit d5c9bae1381cb1f322d5ee3e0efbb27e06154574 Author: Cosimo Cecchi Date: 2011-01-11 Move other files away from src/file-manager M configure.in M src/Makefile.am D src/file-manager/Makefile.am R100 src/file-manager/nemo-desktop-icon-view-ui.xml src/nemo-desktop-icon-view-ui.xml R100 src/file-manager/nemo-directory-view-ui.xml src/nemo-directory-view-ui.xml R100 src/file-manager/fm-empty-view.c src/nemo-empty-view.c R100 src/file-manager/fm-empty-view.h src/nemo-empty-view.h R100 src/file-manager/nemo-icon-view-ui.xml src/nemo-icon-view-ui.xml R100 src/file-manager/nemo-list-view-ui.xml src/nemo-list-view-ui.xml commit 70b1acf6b0d4ef68903445d4198e78c5ea4807e5 Author: Cosimo Cecchi Date: 2011-01-11 Finish renaming fm_* -> nemo_* M src/nemo-actions.h M src/nemo-desktop-icon-view.c M src/nemo-desktop-item-properties.c M src/nemo-desktop-item-properties.h M src/nemo-error-reporting.c M src/nemo-error-reporting.h M src/nemo-icon-view.c M src/nemo-list-view.c M src/nemo-properties-window.c M src/nemo-view.c commit e0538b42e65601d9ebee5beffaefebb3e425672e Author: Cosimo Cecchi Date: 2011-01-11 properties-window: move FMPropertiesWindow to NemoPropertiesWindow M src/Makefile.am M src/file-manager/Makefile.am D src/file-manager/fm-properties-window.h R099 src/file-manager/fm-ditem-page.c src/nemo-desktop-item-properties.c R100 src/file-manager/fm-ditem-page.h src/nemo-desktop-item-properties.h R093 src/file-manager/fm-properties-window.c src/nemo-properties-window.c A src/nemo-properties-window.h M src/nemo-tree-sidebar.c M src/nemo-view.c commit 690909b8eb0b346d76b28da03c9228494e700db6 Author: Cosimo Cecchi Date: 2011-01-11 Rename FMListModel/View -> NemoListModel/View And move them outside of src/file-manager M src/Makefile.am M src/file-manager/Makefile.am D src/file-manager/fm-list-model.h M src/nemo-application.c R072 src/file-manager/fm-list-model.c src/nemo-list-model.c A src/nemo-list-model.h R100 src/file-manager/fm-list-view-private.h src/nemo-list-view-private.h R080 src/file-manager/fm-list-view.c src/nemo-list-view.c R052 src/file-manager/fm-list-view.h src/nemo-list-view.h M src/nemo-view.c commit 757a5acffc9e4ac7bdbd0dcfb5eaa1f64da8a471 Author: Cosimo Cecchi Date: 2011-01-11 icon-view-container: rename FMIconContainer -> NemoIconViewContainer M src/nemo-desktop-icon-view.c M src/nemo-icon-view-container.c M src/nemo-icon-view-container.h M src/nemo-icon-view.c commit ba4c8ef658f4f3e9e46d6cae12d84f06cf0a14b2 Author: Cosimo Cecchi Date: 2011-01-11 desktop-icon-view: rename FMDesktopIconView -> NemoDesktopIconView M src/nemo-application.c M src/nemo-desktop-icon-view.c M src/nemo-desktop-icon-view.h M src/nemo-icon-view.c M src/nemo-view-dnd.c M src/nemo-view.c commit bb124418d4c131b03772acc64be3acf91903e9fb Author: Cosimo Cecchi Date: 2011-01-11 icon-view: rename FMIconView -> NemoIconView M src/nemo-application.c M src/nemo-desktop-icon-view.c M src/nemo-desktop-icon-view.h M src/nemo-icon-view-container.c M src/nemo-icon-view-container.h M src/nemo-icon-view.c M src/nemo-icon-view.h commit b20ff7a5cd1d9304c5716433de1958faedccefde Author: Cosimo Cecchi Date: 2011-01-11 Move icon views outside of src/file-manager Part of the final step towards removing src/file-manager completely; only code shuffling around, not any real code change. M src/Makefile.am M src/file-manager/Makefile.am D src/file-manager/fm-actions.h M src/file-manager/fm-list-view.c M src/file-manager/fm-properties-window.c M src/nemo-actions.h M src/nemo-application.c R100 src/file-manager/nemo-audio-mime-types.h src/nemo-audio-mime-types.h R099 src/file-manager/fm-desktop-icon-view.c src/nemo-desktop-icon-view.c R098 src/file-manager/fm-desktop-icon-view.h src/nemo-desktop-icon-view.h R099 src/file-manager/fm-error-reporting.c src/nemo-error-reporting.c R100 src/file-manager/fm-error-reporting.h src/nemo-error-reporting.h R099 src/file-manager/fm-icon-container.c src/nemo-icon-view-container.c R098 src/file-manager/fm-icon-container.h src/nemo-icon-view-container.h R099 src/file-manager/fm-icon-view.c src/nemo-icon-view.c R100 src/file-manager/fm-icon-view.h src/nemo-icon-view.h M src/nemo-view-dnd.c M src/nemo-view.c commit e1ca0591f0588d114249361c624f467126b323c9 Author: Cosimo Cecchi Date: 2011-01-11 view: drop FMDirectoryView name Big code rename/indent fix, no actual code change here. M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-container.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-icon-view.h M src/file-manager/fm-list-view.c M src/file-manager/fm-list-view.h M src/nemo-view-dnd.c M src/nemo-view.c M src/nemo-view.h commit 00578e62066c1c5dadf4a0080dcb56c215334619 Author: Cosimo Cecchi Date: 2011-01-01 view: remove useless virtual method M src/nemo-view.c M src/nemo-view.h commit 8d726bab91c50d42edcb7e9a0e4107b6b0277ade Author: Cosimo Cecchi Date: 2011-01-01 view: move icon-view-only preferences to FMIconView Instead of using virtual methods M src/file-manager/fm-icon-view.c M src/nemo-view.c M src/nemo-view.h commit 9ab314c1dd30dc2d30fc46a62e2d31059c4c340a Author: Cosimo Cecchi Date: 2010-12-31 view: remove emblems_changed code This hack should not be required anymore now that we don't have user emblems. Other emblems should be taken care of by the normal NemoFile's changed signal. M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-view.c M src/nemo-view.h commit d7de8e23fbe75e4a6ecbaf729affc9cbab9e08a3 Author: Cosimo Cecchi Date: 2010-12-31 signaller: remove unused emblems-changed signal M libnemo-private/nemo-signaller.c commit 5e57025a405e4ccbdd7a4ff51fa48d7eb4fb3671 Author: Cosimo Cecchi Date: 2010-12-31 view: remove useless virtual methods No need for some internal methods to be virtual if they're never overridden. Also, some of this code does nothing. M src/file-manager/fm-icon-container.c M src/nemo-view.c M src/nemo-view.h commit 9b29835c04fcaae84760a328a6cc70705c214506 Author: Cosimo Cecchi Date: 2010-12-31 places-sidebar: remove "Format..." action code M src/nemo-places-sidebar.c commit e4975471d233f1217bca48fae17519a285336645 Author: Cosimo Cecchi Date: 2010-12-31 view: remove commented out "Format..." action code M src/file-manager/fm-actions.h M src/file-manager/nemo-directory-view-ui.xml M src/nemo-view.c commit d0985e6d5ed7f6732bb4ee4b836192852adface2 Author: Cosimo Cecchi Date: 2010-12-31 view: remove unused flush_added_files signal M src/file-manager/fm-icon-view.c M src/nemo-view.c M src/nemo-view.h commit 7a4af383a2cb0e0257213e0e21f62e6cc82a7e58 Author: Cosimo Cecchi Date: 2010-12-31 view: don't check for allow_moves in the view superclass The property is only used by the icon view, so it's better to move the check there. M src/file-manager/fm-icon-view.c M src/nemo-view.c M src/nemo-view.h commit be2d9bba9864f2834a57b608d47140f1e20eca66 Author: Cosimo Cecchi Date: 2010-12-29 view: make nemo_view_load_location() consistent with its name M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c commit 69c2c9f8c5855a7993f23998cff3ce3eab87fd45 Author: Cosimo Cecchi Date: 2010-12-29 view: use NemoFile objects for the view selection Use them in a consistent way, so to cleanup the previous GFile/NemoFile confusion. M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-spatial-window.c M src/nemo-trash-bar.c M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit eb178062ec31bf6a877e5bc61f697f85a3f927fe Author: Cosimo Cecchi Date: 2010-12-29 spatial-window: don't unref the main loop we're about to destroy M src/nemo-spatial-window.c commit ac1fbbba66c61d61c4469949b925862fa3c6600b Author: Cosimo Cecchi Date: 2010-12-29 window: remove unused code M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 57c8b0416135ee3b5c1315b3419269d20ced233c Author: Cosimo Cecchi Date: 2010-12-29 view: split DnD code into its own module And use new method names in other classes M src/Makefile.am M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c A src/nemo-view-dnd.c A src/nemo-view-dnd.h M src/nemo-view.c M src/nemo-view.h M src/nemo-window-slot-dnd.c commit 1f734cce8b243e2c1c1fd40491ab4e38c0eb65cd Author: Cosimo Cecchi Date: 2010-12-29 view: reduce visibility of some methods No need for them to stay public. Remove some useless prototypes and reorder virtual methods, while we're at it. M src/file-manager/fm-icon-view.c M src/nemo-view.c M src/nemo-view.h commit 4c20fa07d8a587ebe8de820a0206aa8a75edc5d8 Author: Cosimo Cecchi Date: 2010-12-29 window: remove nemo_window_get_selection[_count] No need to duplicate selection handling between view and window. M src/nemo-trash-bar.c M src/nemo-trash-bar.h M src/nemo-view.c M src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window.c M src/nemo-window.h commit dedd9e11ec6ff499b82bdb7a9b9bde7927066560 Author: Cosimo Cecchi Date: 2010-12-29 Rework architecture of NemoView/FMDirectoryView As a second step after ff5c759b3784db2d0cd71e1cde613dda007c3985, this removes the NemoView/FMDirectoryView interface split, changing FMDirectoryView to be NemoView directly. Left to do: complete renaming the public fm_directory_view methods to nemo_view, and get rid of src/file-manager entirely. M libnemo-private/Makefile.am M libnemo-private/nemo-dnd.c D libnemo-private/nemo-view.c D libnemo-private/nemo-view.h M src/Makefile.am M src/file-manager/Makefile.am M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-icon-view.h M src/file-manager/fm-list-view.c M src/file-manager/fm-list-view.h M src/nemo-trash-bar.c M src/nemo-view-factory.h R098 src/file-manager/fm-directory-view.c src/nemo-view.c R087 src/file-manager/fm-directory-view.h src/nemo-view.h M src/nemo-window-manage-views.c M src/nemo-window-pane.h M src/nemo-window-slot.c M src/nemo-window-slot.h A src/nemo-window-types.h M src/nemo-window.h M src/nemo-x-content-bar.c commit 10998fbf14029163d3669f1e2a9f1676b02e7d09 Author: Cosimo Cecchi Date: 2010-12-28 main: remove unneeded code M src/nemo-main.c commit 79ef5be141a55ccce67daf42b73aa0a4affa7a13 Author: Cosimo Cecchi Date: 2010-12-28 window-slot: trivial cleanups M src/nemo-window-manage-views.c M src/nemo-window-slot.c commit acf3e032099dc2f7a156e755edb23a3dd8305fc8 Author: Cosimo Cecchi Date: 2010-12-28 window-slot: rename get_current_location -> get_current_uri M src/file-manager/fm-directory-view.c M src/nemo-places-sidebar.c M src/nemo-tree-sidebar.c M src/nemo-window-slot-dnd.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit 977fc6383dc74a320ce951d4d0b2f81f31e9cdcf Author: Cosimo Cecchi Date: 2010-12-27 window: cleanup nemo_window_reload() M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window.c M src/nemo-window.h commit ab75e5447ca5a5a5d7054c907d008816ad911c20 Author: Cosimo Cecchi Date: 2010-12-26 navigation-action: cleanup M src/nemo-navigation-action.c commit 2807b8884acab27de359a4ab51b9b57e8fb86a0f Author: Cosimo Cecchi Date: 2010-12-26 window: remove useless snippets M src/nemo-navigation-window.c commit b1011eced7e561b05dca2aa6345d3c5b3225610e Author: Cosimo Cecchi Date: 2010-12-23 window: remove useless method calls nemo_window_slot_set_content_view_widget() is called afterwards, which in turn calls again _disconnect_view() M src/nemo-window-manage-views.c commit d166f04b8886687df6f03d0e03ec16c887f9842b Author: Cosimo Cecchi Date: 2010-12-23 window: remove non existent function declaration M src/nemo-window.h commit 6ff03b33b724d882cfabb67b1f1fb4e8287e932f Author: Cosimo Cecchi Date: 2010-12-22 window: cleanup nemo_window_allow_reload() M src/nemo-window.c M src/nemo-window.h commit 553edbfbaf7e4fc171453634aa41006d49533da2 Author: Cosimo Cecchi Date: 2010-12-21 window: cleanup nemo_window_go_up() M src/nemo-window-manage-views.c M src/nemo-window-menus.c M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 558e394a8dfba5f1c92423ac45c6462461720199 Author: Cosimo Cecchi Date: 2010-12-21 window: cleanup nemo_window_go_home() M src/nemo-navigation-window-menus.c M src/nemo-window.c M src/nemo-window.h commit d9ce97b0501cb3006013080ed688aa25649a31f6 Author: Cosimo Cecchi Date: 2010-12-21 window-slot: remove commented out code M src/nemo-window-manage-views.c M src/nemo-window-slot.h commit a8d0c04c154ee8458fd5fd24091de1a8c92a6da4 Author: Cosimo Cecchi Date: 2010-12-21 window-slot: cleanup connect/disconnect_view() M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c commit 307e0edbe7457a70f4a61acdfecb1ae38d8c243b Author: Cosimo Cecchi Date: 2010-12-21 window-slot: cleanup of window_slot_open_location() functions M src/file-manager/fm-directory-view.c M src/nemo-mime-actions.c M src/nemo-navigation-window-pane.c M src/nemo-places-sidebar.c M src/nemo-spatial-window.c M src/nemo-tree-sidebar.c M src/nemo-window-manage-views.c M src/nemo-window-slot.h M src/nemo-window.c commit cfdf80763ef3f7f3f88239fdba27ce01b642ab32 Author: Cosimo Cecchi Date: 2010-12-21 window-slot: remove nemo_window_slot_open_location() It's unused. M src/nemo-window-manage-views.c M src/nemo-window-slot.h commit ad0d377ac236392a9ccaeae789e07e1af4a796e5 Author: Cosimo Cecchi Date: 2010-12-21 Rework architecture of NemoWindow/NemoWindowSlotInfo In the past, nemo was designed keeping in mind the concept that it might not just be a file browser, but a sort of platform to embed various kind of views in it. - libnemo-private: general lowlevel items, such as the icon container, NemoFile, I/O and so on - src: general widgets and UI items - src/file-manager: file manager views, agnostic of what's in src/, for the sake of being pluggable enough This is really not applicable anymore, as nemo won't go in any direction other than being a file manager; at the same time, this complicates code and architecture quite a lot. In this commit, as a first step towards a more clean codebase, we remove the NemoWindowInfo and NemoWindowSlotInfo interfaces, using NemoWindow and NemoWindowSlot directly. Note that there should be no actual code changes, only moving of pieces around. M libnemo-private/Makefile.am M libnemo-private/nemo-dnd.c M libnemo-private/nemo-dnd.h D libnemo-private/nemo-window-info.c D libnemo-private/nemo-window-info.h D libnemo-private/nemo-window-slot-info.c D libnemo-private/nemo-window-slot-info.h M src/Makefile.am M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-application.h M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog-main.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-connect-server-dialog.c M src/nemo-connect-server-dialog.h M src/nemo-location-bar.c M src/nemo-mime-actions.c M src/nemo-mime-actions.h M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-places-sidebar.c M src/nemo-places-sidebar.h M src/nemo-query-editor.h M src/nemo-spatial-window.c M src/nemo-trash-bar.c M src/nemo-tree-sidebar.c M src/nemo-tree-sidebar.h M src/nemo-view-as-action.c R098 libnemo-private/nemo-view-factory.c src/nemo-view-factory.c R094 libnemo-private/nemo-view-factory.h src/nemo-view-factory.h M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window-slot-dnd.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 4c031a4794126af08cea1774dd7ec3904d0ad25e Author: Cosimo Cecchi Date: 2010-12-21 mime-actions: move nemo-mime-actions to src/ M libnemo-private/Makefile.am M libnemo-private/nemo-program-choosing.c M src/Makefile.am M src/file-manager/Makefile.am M src/file-manager/fm-directory-view.c M src/file-manager/fm-properties-window.c R099 libnemo-private/nemo-mime-actions.c src/nemo-mime-actions.c R100 libnemo-private/nemo-mime-actions.h src/nemo-mime-actions.h M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-manage-views.c M src/nemo-window.c commit 97e67f49279ad87737541249ef09b99c4bc1d9fe Author: Cosimo Cecchi Date: 2010-12-21 dnd: move DnD slot proxying code to src/ M libnemo-private/nemo-dnd.c M libnemo-private/nemo-dnd.h M src/Makefile.am M src/nemo-notebook.c M src/nemo-pathbar.c A src/nemo-window-slot-dnd.c A src/nemo-window-slot-dnd.h commit 6430fd4a7435336a61000e2255621fb0023252d1 Author: Ivar Smolin Date: 2011-01-11 [l10n] Updated Estonian translation M po/et.po commit 63724239779c6f5f4dcb76ebde7f66f691a75786 Author: Andika Triwidada Date: 2011-01-11 Updated Indonesian translation M po/id.po commit 9022942dce517bc0fe52fdb769f6950c0aa5c444 Author: Ivar Smolin Date: 2011-01-10 [l10n] Updated Estonian translation M po/et.po commit cd976fa26099fb8c1f2084a6bae7ac0b05f5e29e Author: Cosimo Cecchi Date: 2011-01-10 Release 2.91.7 M NEWS M configure.in M po/POTFILES.in commit f6d4eed031e94570151cb4599e93d92b4612d53b Author: Cosimo Cecchi Date: 2011-01-10 debug: fix build without debugging support (#639107) M configure.in M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h M src/nemo-main.c commit ac168820fbb4db7fbdf243a0d6b118ce445cdf37 Author: Cosimo Cecchi Date: 2011-01-10 file-operations: make Create Document/Folder use the right template Make Create Document/Folder use "Untitled Document/Template/Folder %d" filename format. Based on a patch by Marcus Husar . M libnemo-private/nemo-file-operations.c commit 5846b33c5cd26ec3fe50255c628954d129c8ffc0 Author: Marcus Husar Date: 2011-01-10 Clean context menu and "File" menu (#618469) Also use "Create New Folder/Document". Part of https://bugzilla.gnome.org/show_bug.cgi?id=618469 M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml M src/nemo-tree-sidebar.c commit 0ff4fdb4c8228a358d3a0bc87b63b02751624716 Author: Fran Diéguez Date: 2011-01-10 Updated Galician translations M po/gl.po commit 8f9bb67e39a9d32be051416a474c3142539f7c3f Author: Sjoerd Simons Date: 2010-12-05 Add base libraries so building with --as-needed works M nemo-sendto-extension/Makefile.am commit 179b688c5938ba12e101a0231ba46199d2de4a5e Author: Cosimo Cecchi Date: 2011-01-10 window: remove unused code M src/nemo-window-private.h M src/nemo-window.c commit b12aeed547664d44b0b552db06a5ec7b6d9b200b Author: Cosimo Cecchi Date: 2011-01-10 bookmark: compare URIs before names M libnemo-private/nemo-bookmark.c commit 120797cec00929dac58ac4ac838719dc67e9cae0 Author: Cosimo Cecchi Date: 2011-01-10 Use a consistent name for the Home folder (#341894) Based on a patchset by Marcus Husar M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-desktop-link.c M src/file-manager/fm-directory-view.c M src/nemo-places-sidebar.c M src/nemo-tree-sidebar.c M src/nemo-window-menus.c M src/nemo-window-slot.c commit 50e0c03f67072e374f8202ba7a25221fa7f88b99 Author: Fran Diéguez Date: 2011-01-09 Updated Galician translations M po/gl.po commit 598ede33ab781b46120d2149c37f47fcb7615ca2 Author: Yuri Myasoedov Date: 2011-01-09 Updated Russian translation M po/ru.po commit cd2a6e35c5757c7ca817aeef415873d2d4d8baee Author: Matej UrbanÄiÄ Date: 2011-01-07 Updated Slovenian translation M po/sl.po commit d51bc0c99b0ca6e8bc402b7ae5848e9ced2dab46 Author: Ivar Smolin Date: 2011-01-06 [l10n] Updated Estonian translation M po/et.po commit 3ff059dcc1b76a7cde6d7111b9620d373c18b9a8 Author: Yaron Shahrabani Date: 2011-01-04 Updated Hebrew translation. M po/he.po commit f8f87d8cca0a9aa54d5a1290576eb0855098ffda Author: Ivar Smolin Date: 2011-01-02 [l10n] Updated Estonian translation M po/et.po commit 61476e9e0a776e1db74f73db1b3fa9291d997a83 Author: Daniel Nylander Date: 2010-12-29 Updated Swedish translation M po/sv.po commit 09cb61a5cc2b9e5f7b85ae619d2cc2d06bf5ef06 Author: Daniel Mustieles Date: 2010-12-29 Updated Spanish translation M po/es.po commit 811f49d1e0981f7414a57004a7fd0df95f64dfd8 Author: A S Alam Date: 2010-12-29 update Punjabi Translation M po/pa.po commit ddd507228a8a7a89c0398411f44d30e6ee9d73ed Author: Cosimo Cecchi Date: 2010-12-28 pathbar: remove buttons only if the gone file is below the current This should fix once and for all the crashers when ejecting devices. M src/nemo-pathbar.c commit 70df8fad8b1ddf470e8600f6e8e9bc953853b419 Author: Cosimo Cecchi Date: 2010-12-26 desktop-icon-view: don't use deprecated GDK grab API M src/file-manager/fm-desktop-icon-view.c commit bd151c8174796c1c5b0b6466ef8a0e3a0e214054 Author: Cosimo Cecchi Date: 2010-12-26 general: don't use deprecated gdk_app_launch_context_new() M eel/eel-gnome-extensions.c M eel/eel-gnome-extensions.h M libnemo-private/nemo-program-choosing.c M src/nemo-connect-server-dialog-main.c commit 2ff006dd583f58ff2dd687f538e59757a8bd70c4 Author: Cosimo Cecchi Date: 2010-12-26 canvas: don't use deprecated GDK grab API M eel/eel-canvas.c M eel/eel-canvas.h commit 7fa4d2202358940ef5a0dd70eb88996ac371cffd Author: Gheyret T.Kenji Date: 2010-12-23 Added UG translation M po/ug.po commit aac9a486cb310c62d1167cfe37118a70d772d41e Author: Erdal Ronahi Date: 2010-12-23 Updated Kurdish translations M po/ku.po commit 318a9bd653fb02a7c94e42139377cef5ed254dd2 Author: Cosimo Cecchi Date: 2010-12-22 Release 2.91.6 M NEWS M configure.in commit b569d2cfa31951f67229e3aab00cd7f33c1ff3db Author: Cosimo Cecchi Date: 2010-12-22 general: use nemo_launch_application instead of gdk_spawn API M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/nemo-tree-sidebar.c M src/nemo-window-menus.c commit 77ecdd69b023a16fc4d6d2895dd470c628679168 Author: Cosimo Cecchi Date: 2010-12-22 program-choosing: don't use gdk_spawn_ API M libnemo-private/nemo-program-choosing.c M libnemo-private/nemo-program-choosing.h commit 13b6a5a50db8dd35dbcbbf1d318ba747609dfb70 Author: Cosimo Cecchi Date: 2010-12-22 eel: don't use gdk_spawn_ API M eel/eel-gnome-extensions.c commit 74a8f78e2a5b06485c7daf830372a5f7b15a87b8 Author: Cosimo Cecchi Date: 2010-12-22 general: don't use gdk_cursor_unref() M eel/eel-editable-label.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M src/file-manager/fm-list-view.c M src/file-manager/fm-properties-window.c M src/nemo-window.c commit 2737d431e44e3e4dc12e9098b6e17881ca28c1f7 Author: Wouter Bolsterlee Date: 2010-12-22 Updated Dutch translation by Wouter Bolsterlee M po/nl.po commit 08462d0f0235274f1b6c2b12df47e27932b343ee Author: Cosimo Cecchi Date: 2010-12-20 Release 2.91.5 M NEWS M configure.in commit f42d5aa97de09de7052fa80abda62fabe17dfb13 Author: Cosimo Cecchi Date: 2010-12-20 smclient: remove XSMP support EggSmClient is not well-maintained, and it doesn't seem like it will ever hit GTK+, and the overall implementation seems to be poorly tested and buggy. Moreover, moving to 3.0 with nemo being an application, it makes less sense to have it save opened windows state, as it might not be always running at all. M cut-n-paste-code/libegg/Makefile.am D cut-n-paste-code/libegg/eggdesktopfile.c D cut-n-paste-code/libegg/eggdesktopfile.h D cut-n-paste-code/libegg/eggsmclient-private.h D cut-n-paste-code/libegg/eggsmclient-xsmp.c D cut-n-paste-code/libegg/eggsmclient.c D cut-n-paste-code/libegg/eggsmclient.h M po/POTFILES.in M src/Makefile.am D src/nemo-application-smclient.c D src/nemo-application-smclient.h M src/nemo-application.c M src/nemo-application.h M src/nemo-main.c commit ee06a67a632476b9758cc00eaa573e12cc3cfc91 Author: Cosimo Cecchi Date: 2010-12-20 mime-app-chooser: use g_app_info_set_as_last_used_for_content_type() Instead of add_supports_for_content_type(), which does not save the order in which custom apps have been used. M configure.in M libnemo-private/nemo-mime-application-chooser.c commit b31222dae4c63479e0fe226a761f9c78bf08b6df Author: Cosimo Cecchi Date: 2010-12-20 mime: remove some useless code As GtkAppChooserDialog already takes care of calling g_app_info_set_as_last_used_for_content_type() M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-directory-view.c commit 2c279a4a6b3480bfd3581a3a35c53eac3e996653 Author: Ivar Smolin Date: 2010-12-20 [l10n] Updated Estonian translation M po/et.po commit 3fa0ed2ca3e35719422fbc526337b52393d860d2 Author: Kjartan Maraas Date: 2010-12-19 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 9dc65e44c9f8e6c41079c0dc01220fe87fdfcecc Author: Nguyá»…n Thái Ngá»c Duy Date: 2010-12-19 po/vi.po: import some translations from Ubuntu/Maverick M po/vi.po commit dd4cecdf8071552f80ba08fdb613a88090719e59 Author: Yaron Shahrabani Date: 2010-12-19 Updated Hebrew translation. M po/he.po commit fcfe53d5bd2121e4707e70345f18faa244c2dd75 Author: Cosimo Cecchi Date: 2010-12-18 Remove reference to a non-existing old trademark notice file. https://bugzilla.gnome.org/show_bug.cgi?id=463173 M COPYING commit 196c8390fcc671ef8399c00936ac7242b118de08 Author: Jorge González Date: 2010-12-18 Updated Spanish translation M po/es.po commit 83aeec725d0d3829a54cd700329864a2cab7a21b Author: Marcus Carlson Date: 2009-10-11 Handle G_IO_ERROR_FILENAME_TOO_LONG errors nicely when renaming files https://bugzilla.gnome.org/show_bug.cgi?id=548844 M src/file-manager/fm-error-reporting.c commit 9403df1b54b442737ed96739aeacf6b6c9b58889 Author: Colin Walters Date: 2010-12-17 Fix cairo-gobject.h include $ pkg-config --cflags cairo-gobject -pthread -I/src/build/jhbuild/include/cairo $ ls /src/build/jhbuild/include/cairo/cairo-gobject.h /src/build/jhbuild/include/cairo/cairo-gobject.h M eel/eel-canvas.c commit b2d4ac40205e22e63e598ab742b56283acbc8901 Author: Colin Walters Date: 2010-12-17 nemo.desktop: Remove NoDisplay=true For GNOME 3, File Manager is moving towards being an application, and therefore, we want it to show up in the appliactions list. M data/nemo.desktop.in.in commit 67d0cbaf0ed7a8f25b3a47abbbaf0feba990e404 Author: Cosimo Cecchi Date: 2010-12-17 location-entry: don't treat '~' as a relative path Based on a patch by Reed Lipman https://bugzilla.gnome.org/show_bug.cgi?id=628802 M src/nemo-location-entry.c commit 184096f912b119edde1f538e8cdd5ea593d753ca Author: Cosimo Cecchi Date: 2010-12-17 icon-canvas-item: attempt to fix up a11y for NemoIconCanvasItem Based on an initial patch by Alban Browaeys . https://bugzilla.gnome.org/show_bug.cgi?id=637425 M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c commit 42865d5e82160ccb60fd9a890a22019dcb832527 Author: Alban Browaeys Date: 2010-10-27 icon-container: remove spurious call to gtk_adjustment_changed() https://bugzilla.gnome.org/show_bug.cgi?id=637424 M libnemo-private/nemo-icon-container.c commit bc5b8bde3070a4fe6071c9a428d38fa93be19314 Author: Jorge González Date: 2010-12-15 Updated Spanish translation M po/es.po commit 1746a53cbbd450822ff857c3e1eadf5358b22cfa Author: Cosimo Cecchi Date: 2010-12-15 application: fix a copy-paste typo M src/nemo-application.c commit 08f71aa76cd5f250613f4a2833b43a72831974fc Author: Cosimo Cecchi Date: 2010-12-15 theming: cleanup previous manually parsed CSS It's not required anymore, now that we have a proper stylesheet. M src/nemo-notebook.c M src/nemo-window.c commit 786ba61680bfaee136b4b72a53f220edb96a7db9 Author: Cosimo Cecchi Date: 2010-12-15 sidebar: set the NemoSidebar class on the sidebar treeviews So they can get the proper background. M src/nemo-places-sidebar.c M src/nemo-tree-sidebar.c commit dad5d12770817aa739ab9980faa66972144008a7 Author: Cosimo Cecchi Date: 2010-12-15 theming: add a CSS file for nemo, and initialize it at startup M data/Makefile.am A data/nemo.css M src/nemo-application.c commit 1c79bf9809b208a57661aaccadd9eb7e78874bcc Author: Cosimo Cecchi Date: 2010-12-15 connect-server-dialog: properly align labels and entries https://bugzilla.gnome.org/show_bug.cgi?id=637326 M src/nemo-connect-server-dialog.c commit 0a43cee107e20d07667fc2eabf8321898ce80fb7 Author: Luca Ferretti Date: 2010-12-15 application: fix a typo in user message M src/nemo-application.c commit 4c026bf53253715251abf076badc4c979cc073c3 Author: Cosimo Cecchi Date: 2010-12-15 icon-container: don't malloc() GdkRGBA colors manually As GdkRGBA might or might not use internally a different allocator, like g_slice. This should fix some memory corruption issues, thanks to Alban Browaeys for tracking down the bug. M libnemo-private/nemo-icon-container.c commit c1d9376601223e5dcca0a4ee47e95a8b93841d68 Author: Cosimo Cecchi Date: 2010-12-14 spatial-window: don't hook to unrealize for saving geometry M src/nemo-spatial-window.c commit e4750d78c6be4f935625a3511dbb9c3bc532aa0d Author: Cosimo Cecchi Date: 2010-12-14 desktop-icon-view: call the gnome-c-c executable to change background gnome-appearance-properties does not exist anymore. M src/file-manager/fm-desktop-icon-view.c commit 5d811bb37ef4a05edd7fa4c5868a9b68f717e056 Author: Cosimo Cecchi Date: 2010-12-14 icon-dnd: set the right style class, and use GdkRGBA M libnemo-private/nemo-icon-dnd.c commit 18e3369f02c4ff6a3eb01048e623fff8eb9aded4 Author: Cosimo Cecchi Date: 2010-12-14 tree-drag-dest: set the right style class M libnemo-private/nemo-tree-view-drag-dest.c commit 066896047e8d53076913994f9975ee1cb22fbd9d Author: Cosimo Cecchi Date: 2010-12-14 icon-canvas-item: set the right style class M libnemo-private/nemo-icon-canvas-item.c commit ef8544bec8437502f2f58c7a9e07bc9e1ecf91a4 Author: Cosimo Cecchi Date: 2010-12-13 editable-label: use gtk_style_context_get() to query standard props Also, fix a leak. M eel/eel-editable-label.c commit dccf76a36441332e96c40305373876ca32a1b110 Author: Cosimo Cecchi Date: 2010-12-13 preferences: remove exit-with-last-window preference entirely It makes no sense now that nemo doesn't do session services, such as autorun, anymore. M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo.convert M libnemo-private/org.gnome.nemo.gschema.xml.in commit 9ef4ac9ee428e7f7952efe33d0784d547ca7bdc6 Author: Cosimo Cecchi Date: 2010-12-13 application: remove 'exit-with-last-window' preference It makes no sense now that nemo doesn't do session services such as autorun anymore. M src/nemo-application.c commit 00e0ae826765aeca4c203b77a5caec4ce2be2fd7 Author: Cosimo Cecchi Date: 2010-12-13 application: destroy all the widgets when quitting Instead of calling _release(). M src/nemo-application.c commit caa55b7e757a49fb323450152e6a37e1d63eb9fb Author: Cosimo Cecchi Date: 2010-12-13 editable-label: rename copy/pasted fill renderer to 'eel' prefix To avoid library clashes with the GTK+ internal one. M eel/eel-editable-label.c commit f27c50fb25fee58b9eee6c9edfd26101684eec52 Author: Jorge González Date: 2010-12-11 Updated Spanish translation M po/es.po commit f5acdfefc39b235fd1eb9b3bdd3a724cdaa1a7fe Author: Fran Diéguez Date: 2010-12-11 Updated Galician translations M po/gl.po commit c0645b53892c1f65b9258e5cc63b701dbcbacfe7 Author: Fran Diéguez Date: 2010-12-10 Updated Galician translations M po/gl.po commit eea53d2f740ac25a13eea13baa83ecb493fa24cc Author: Cosimo Cecchi Date: 2010-12-07 file: initialize variables to stop complaints from compilers (#636643) M libnemo-private/nemo-file.c commit def31cd34118e4a3daf53819f81a5d7325b8efcb Author: Cosimo Cecchi Date: 2010-12-07 Release 2.91.4 M NEWS M configure.in commit bb68641adf3306675f3b259d0197ef74ecc9ccc0 Author: Cosimo Cecchi Date: 2010-12-07 dbus-manager: plug a leak M libnemo-private/nemo-dbus-manager.c commit 7686ba98e4283383f4e0b0146cbc693d041c5697 Author: Cosimo Cecchi Date: 2010-12-07 icon-container: plug a leak M src/file-manager/fm-icon-container.c commit 705d8144e5509d7926adec8af3d638b2e88fd837 Author: Cosimo Cecchi Date: 2010-12-07 icon-info: plug a leak M libnemo-private/nemo-icon-info.c commit 55869c3c65217f1c4386cf489f391eeb519e797d Author: Yaron Shahrabani Date: 2010-12-07 Updated Hebrew translation. M po/he.po commit ee0c6327eeaeaa0a924007cf3b56d2cd63dbe36b Author: Daniel Șerbănescu Date: 2010-12-06 Updated Romanian translation M po/ro.po commit 68a3a22297875118797eacb03ff5278024642366 Author: Daniel Șerbănescu Date: 2010-12-06 Updated Romanian translation M po/ro.po commit cb70787275e2e44cc2f3b394d1065313998fd1a3 Author: Cosimo Cecchi Date: 2010-12-06 file-operations: remove duplicate code Probably a leftover from NemoFileConflictDialog branch. M libnemo-private/nemo-file-operations.c commit c739fd781c355e47e4ef3f59e9e4008c230e83ad Author: Cosimo Cecchi Date: 2010-12-06 dbus-manager: add a 'CopyFile' remote method The interface mimics the nemo_file_operations_copy_file() I just committed. M libnemo-private/nemo-dbus-manager.c commit 4be5d548a438b2b3c02f3e7e7e0265f4c8b641fe Author: Cosimo Cecchi Date: 2010-12-06 file-operations: add nemo_file_operations_copy_file Copies a single file to a target directory, allowing to specify a custom target display name, and a custom source display name, which will be shown in the FileOperations dialog instead of the actual file name. M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-operations.h commit 52b8185908725ba9842f3d2ce8c29d7b7e3d520f Author: Cosimo Cecchi Date: 2010-12-06 file-conflict-dialog: don't use override_font Set the PangoAttributeList on the GtkLabel instead. M libnemo-private/nemo-file-conflict-dialog.c commit e3feaf8d6848a92e3d077d04177e7a637b6e628b Author: Cosimo Cecchi Date: 2010-12-06 editable-label: make the rename rectangle look a bit better Still not perfect, but still... M eel/eel-editable-label.c commit 2e5f7a23350016c67bb9e9cca86a9fb2360d79e2 Author: Cosimo Cecchi Date: 2010-12-06 icon-container: fix rendering of text on the desktop M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c commit ca9f8d8906b85a4f806d713030d02efc34fd7170 Author: Cosimo Cecchi Date: 2010-12-06 editable-label: copy-paste code from GTK+ to sync drawing with GtkLabel M eel/eel-editable-label.c commit 465f576edaf1c8b952ec152884d55db985f10778 Author: Cosimo Cecchi Date: 2010-12-06 window: pkug a leak M src/nemo-window.c commit 1ee7fc84fe8232bfc57ba832642185b2829dcc8e Merge: 1c31b7a b5302eb Author: Cosimo Cecchi Date: 2010-12-06 Merge branch 'style-context' commit b5302ebfc104aec7cc480931ede752efe9cc4325 Author: Cosimo Cecchi Date: 2010-12-06 eel: remove unused code M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h M eel/eel-gtk-extensions.c M eel/eel-lib-self-check-functions.h commit 1d3dd9693de26d91d60ed7a11f6f14df8478f6a6 Author: Cosimo Cecchi Date: 2010-12-06 eel-gdk-extensions: port to GtkStyleContext M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 076886e9a45e8dce101f1d98eb5c4168c8ded311 Author: Cosimo Cecchi Date: 2010-12-06 window: port to GtkStyleContext M src/nemo-window.c commit 507b56e3a527e28117b259dbf0dce48f1656dd7d Author: Cosimo Cecchi Date: 2010-12-06 spatial-window: port to GtkStyleContext M src/nemo-spatial-window.c commit bc5d2904fd3338455579c77781c357fe85a86913 Author: Cosimo Cecchi Date: 2010-12-06 notebook: port to GtkStyleContext M src/nemo-notebook.c commit 5fc40adf98a384f4638401d7b7ced79da6ce2b87 Author: Cosimo Cecchi Date: 2010-12-06 location-bar: port to GtkStyleContext M src/nemo-location-bar.c commit 8e5689b5ff9fb1fedf2a1102f429f4f67e811e09 Author: Cosimo Cecchi Date: 2010-12-06 properties-window: port to GtkStyleContext M src/file-manager/fm-properties-window.c commit d7c576dbc1116139a29b7d263070283c47726ba2 Author: Cosimo Cecchi Date: 2010-12-06 list-view: port to GtkStyleContext Setting inactive pane doesn't work here yet, probably due to a bug in GTK+. M src/file-manager/fm-list-view.c commit f8bdf9c68ae156506d04f198e054e9488845c173 Author: Cosimo Cecchi Date: 2010-12-06 tree-view-drag-dest: port to GtkStyleContext M libnemo-private/nemo-tree-view-drag-dest.c commit 4f23a0a89b14757dc86459c399ff6a9719bb4e01 Author: Cosimo Cecchi Date: 2010-12-06 icon-container: port to GtkStyleContext M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-icon-private.h commit fc74332e3bbcc20094ab58631666b477640e2aeb Author: Cosimo Cecchi Date: 2010-12-06 icon-canvas-item: port to GtkStyleContext M libnemo-private/nemo-icon-canvas-item.c commit 5da941e338b159c42a4b4f2581573635e3d68b11 Author: Cosimo Cecchi Date: 2010-12-06 file-conflict-dialog: port to GtkStyleContext M libnemo-private/nemo-file-conflict-dialog.c commit 020adaf997cc63a2b78ccb21c34b7f7f5244008e Author: Cosimo Cecchi Date: 2010-12-06 eel-gdk-pixbuf: use GdkRGBA everywhere M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h M eel/eel-graphic-effects.c M eel/eel-graphic-effects.h commit d6e07c7803b3d70968e7a37bcf1ef730b8ca4bac Author: Cosimo Cecchi Date: 2010-12-06 editable-label: port to GtkStyleContext There are still some rendering artifacts, but we will fix them later. M eel/eel-editable-label.c commit 5cf60d2aa1e8fd9856aed886cce6bd746f4a8074 Author: Cosimo Cecchi Date: 2010-12-06 eel-canvas: build fix for gdk_window_get_geometry API change M eel/eel-canvas.c commit 0a3aff84fececf1cfce0969ac173a736d2014130 Author: Cosimo Cecchi Date: 2010-12-06 eel-canvas: port to GtkStyleContext M eel/eel-canvas.c M eel/eel-canvas.h commit f0691e71c58bba402d896f0a236e4bd10b6e5760 Author: Cosimo Cecchi Date: 2010-12-06 eel-canvas-re: use RGBA colors only M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas-rect-ellipse.h commit 1c31b7ab0d8ed7122f385395f6844006aa4a41e2 Author: Andre Klapper Date: 2010-12-06 Fix POTFILES.in to make intltool-update work again M po/POTFILES.in commit a68bf9c76a9073db3247e8dd1e92c0c1b3b98727 Author: Fran Diéguez Date: 2010-12-05 Updated Galician translations M po/gl.po commit 59670a59c9b53a59ef587767c3e7be247b0f11cf Author: Cosimo Cecchi Date: 2010-12-04 icon-container: apply emblems from FmIconContainer This simplifies the code a bit, and also fixes emblem sizes for thumbnails. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M src/file-manager/fm-icon-container.c commit 1004a7df4357fb2772ad4289b997b16ef799fc34 Author: Cosimo Cecchi Date: 2010-12-04 file: add some debug messages for getting icons M libnemo-private/nemo-file.c commit 55098c48a050a226fdb7168440fdbeb1a1fd5da0 Author: Cosimo Cecchi Date: 2010-12-04 debug: add a flag for NemoFile M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h commit b97bad42e62d7d13d257a7785fa1b91943a0758f Author: Cosimo Cecchi Date: 2010-12-04 file-management-properties: open only one preferences window (#442263) M src/nemo-file-management-properties.c M src/nemo-file-management-properties.h M src/nemo-window-menus.c commit 1c5794a5a520ea9bdfa3865b9db702f484cabfe0 Author: Cosimo Cecchi Date: 2010-12-04 settings: remove notes and history sidebar from GSettings schemas M libnemo-private/org.gnome.nemo.gschema.xml.in commit 69e432cf94d31f07cf1d193e1fd25a693cfdc173 Author: Cosimo Cecchi Date: 2010-12-03 navigation-window: plug a leak M src/nemo-navigation-window.c commit 1eac9e307787d773ac1598d79df965d5be684f38 Merge: 2a20b38 7bce748 Author: Cosimo Cecchi Date: 2010-12-03 Merge branch 'ui-polish' commit 7bce7484e9cf5389582fd70c509abd2541ac04e5 Author: Cosimo Cecchi Date: 2010-12-03 tree-sidebar: rename and move to src/ M src/Makefile.am M src/file-manager/Makefile.am M src/nemo-navigation-window.c R099 src/file-manager/fm-tree-model.c src/nemo-tree-sidebar-model.c R100 src/file-manager/fm-tree-model.h src/nemo-tree-sidebar-model.h R099 src/file-manager/fm-tree-view.c src/nemo-tree-sidebar.c R100 src/file-manager/fm-tree-view.h src/nemo-tree-sidebar.h commit b37e7b126e70b623e86b09c69f3f7839368e0604 Author: Cosimo Cecchi Date: 2010-12-03 notes-sidebar: remove NemoNotesViewer An ancient almost-hidden feature that just doesn't fit with the current design. M po/POTFILES.in M src/Makefile.am D src/nemo-notes-viewer.c D src/nemo-notes-viewer.h commit 8bba34a56ca1fd9ae70b7821ed7b7be48d6cc8f1 Author: Cosimo Cecchi Date: 2010-12-03 side-pane: remove NemoSidePane It's an useless container now that we changed our sidebar handling. M po/POTFILES.in M src/Makefile.am D src/nemo-side-pane.c D src/nemo-side-pane.h commit 369f2490308b615d3d9b2c86b428f18d721dff33 Author: Cosimo Cecchi Date: 2010-12-03 window: update for the removal of sidebar interfaces The window now just creates one of the two sidebars, and listens to GSettings changes for toggling between the two. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window-private.h M src/nemo-window.h commit 24ba7de3289225145faf2f85f05faef67370d447 Author: Cosimo Cecchi Date: 2010-12-03 places-sidebar: don't implement NemoSidebar/Provider anymore M src/nemo-places-sidebar.c M src/nemo-places-sidebar.h commit 1fe934a9955579103b72cd86c5ba83b9c7b4966a Author: Cosimo Cecchi Date: 2010-12-03 tree-sidebar: don't implement NemoSidebar/Provider anymore M src/file-manager/fm-tree-view.c M src/file-manager/fm-tree-view.h commit 3905444bd00e45cfbbe897c1da9de7f2d2c393e2 Author: Cosimo Cecchi Date: 2010-12-03 sidebar: remove NemoSidebar and NemoSidebarProvider We'll hardcode two sidebars (Places and Tree) from now on, so there's no need for these generic interfaces now. M libnemo-private/Makefile.am D libnemo-private/nemo-sidebar-provider.c D libnemo-private/nemo-sidebar-provider.h D libnemo-private/nemo-sidebar.c D libnemo-private/nemo-sidebar.h commit bc8c0f2fb18365f84045d0bfd6107d8541fbba59 Author: Cosimo Cecchi Date: 2010-12-03 application: don't register sidebars anymore M src/nemo-application.c commit 0bfd0a8d7d69058d486ab30580e2623166a5a555 Author: Cosimo Cecchi Date: 2010-12-03 sidebar: remove NemoHistorySidebar This is part of the 3.0 redesign plans. M po/POTFILES.in M src/Makefile.am M src/nemo-application.c D src/nemo-history-sidebar.c D src/nemo-history-sidebar.h commit 2a20b38c4dc870d8f3a85dae222c125a77f40229 Author: Michael Terry Date: 2010-11-26 Add --print-uri option M src/nemo-connect-server-dialog-main.c commit 7e794ed30195f15e78b6d96a9064681a128e41d6 Author: Cosimo Cecchi Date: 2010-12-03 search-engine: remove Beagle support M libnemo-private/Makefile.am D libnemo-private/nemo-search-engine-beagle.c D libnemo-private/nemo-search-engine-beagle.h M libnemo-private/nemo-search-engine.c commit fdae502d65f3c40dee4d418bd9d21270940aa93d Author: Cosimo Cecchi Date: 2010-12-03 libnemo-extension: use a different directory for 3.0 So that old extensions do not pull in GTK+2 code. https://bugzilla.gnome.org/show_bug.cgi?id=624244 M configure.in M libnemo-extension/Makefile.am M libnemo-extension/libnemo-extension-uninstalled.pc.in M libnemo-extension/libnemo-extension.pc.in M libnemo-private/Makefile.am M nemo-sendto-extension/Makefile.am commit d9331ae959593cd81f59b39d61597278162ac7eb Author: Matthias Clasen Date: 2010-12-02 Fix the build with latest GTK+ Various GdkDrawable APIs have been replaced by GdkWindow ones, and GtkFunction is no more, use GSourceFunc instead. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-tree-view-drag-dest.c M src/nemo-desktop-window.c commit 8ee6c67b5fe1b12999c2e2f4c7f42d85a497c233 Author: Cosimo Cecchi Date: 2010-12-02 dbus-manager: add DEBUG messages for NemoDBusManager M libnemo-private/nemo-dbus-manager.c M libnemo-private/nemo-debug.c M libnemo-private/nemo-debug.h commit 5433f57cec515bce9bddecc8a569aa02b597a75e Author: Cosimo Cecchi Date: 2010-12-02 debug: fix a stupid typo M libnemo-private/nemo-debug.c commit 46d6bbb1208c409b8507dc31ef6aaf895b55ba92 Author: Cosimo Cecchi Date: 2010-12-02 debug: check for flags in DEBUG_FILES M libnemo-private/nemo-debug.c commit a440c05ceebdbfc21c8e585087574c7827e5f1f2 Author: Cosimo Cecchi Date: 2010-12-02 eel-debug: remove unused code M eel/eel-debug.c M eel/eel-debug.h commit 2f90dc16bc0a9b9fb5e862ad5759aed04b98872c Author: Cosimo Cecchi Date: 2010-12-02 debug-log: nuke nemo-debug-log M libnemo-private/Makefile.am D libnemo-private/nemo-debug-log.c D libnemo-private/nemo-debug-log.h commit 2c9da31ce8252d32eae502b584379d53631f1a91 Author: Cosimo Cecchi Date: 2010-12-02 main: don't hook up with nemo-debug-log M src/nemo-main.c commit 218670bd1f1f9d8f980460c9f2ed721ff57c04a7 Author: Cosimo Cecchi Date: 2010-12-02 general: use new DEBUG macros instead of nemo_debug_log M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-tree-view-drag-dest.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-error-reporting.c M src/file-manager/fm-list-view.c M src/file-manager/fm-tree-view.c M src/nemo-application-smclient.c M src/nemo-application.c M src/nemo-places-sidebar.c M src/nemo-window-manage-views.c commit 695b2d933406b039fb46592b90b5f844d381490c Author: Cosimo Cecchi Date: 2010-12-02 debug: add a new, simpler nemo-debug module, based on Empathy's We lose dumping the log to a file automatically, but we gain a lot in flexibility. M configure.in A libnemo-private/nemo-debug.c A libnemo-private/nemo-debug.h commit b2edace4164fbec353bba497ebb34914864bcd1a Author: Cosimo Cecchi Date: 2010-12-02 dbus-manager: add an EmptyTrash operation M libnemo-private/nemo-dbus-manager.c commit 2e210578261c9060111efba1a705c78ff2c369b9 Author: Cosimo Cecchi Date: 2010-12-02 dbus-manager: implement the CopyURIs method M libnemo-private/nemo-dbus-manager.c M libnemo-private/nemo-dbus-manager.h commit 5c9f1adb43052b19499f6ff1ad403f2222f0e091 Author: Cosimo Cecchi Date: 2010-12-02 application: make the application-id not clash with the dbus interface M src/nemo-application.c commit b238be002e446e102e056b8484666f21feb6b6f2 Author: Cosimo Cecchi Date: 2010-12-01 dbus-manager: add a skeleton of NemoDBusManager M libnemo-private/Makefile.am A libnemo-private/nemo-dbus-manager.c A libnemo-private/nemo-dbus-manager.h M src/nemo-application.c commit 41b91ea64d9731a48ffab621e293f7ff05d88acd Author: Cosimo Cecchi Date: 2010-12-01 icon-canvas-item: tweak the resize bounding box color according to style M libnemo-private/nemo-icon-canvas-item.c commit 7bd06fab98c2c61a170535b6ebd94da1a4db7466 Author: Cosimo Cecchi Date: 2010-12-01 icon-dnd: fix DnD highlighting regression M libnemo-private/nemo-icon-dnd.c commit 8cb07ccf2ddcf0cb8557c763f8905558d67736de Author: Benjamin Otte Date: 2010-12-01 eel: Use future-safe macro to query the X display M eel/eel-canvas-rect-ellipse.c commit c2c4076ceb2216ff5e696b4e78aeb63e0f86c437 Author: Benjamin Otte Date: 2010-12-01 Remove unnecessary drawable cast M libnemo-private/nemo-icon-dnd.c commit 1cfc56563e6cf867af5e3a98cfb9c87281b5f4c2 Author: Cosimo Cecchi Date: 2010-12-01 build: bump required GTK+ version M configure.in commit de8cb567358f658c167b9413a077b681123ab056 Author: Cosimo Cecchi Date: 2010-12-01 mime-application-chooser: plug a leak M libnemo-private/nemo-mime-application-chooser.c commit 466fe29b2d1790b8f61d854b0294205a9f437fd2 Author: Cosimo Cecchi Date: 2010-12-01 mime-actions: remove unused code M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-mime-actions.h commit fe8ffd8635abfcf280e06c9385bfae4dd01621a4 Author: Cosimo Cecchi Date: 2010-12-01 program-choosing: remove commented out code M libnemo-private/nemo-program-choosing.c commit c0b34d1f07b2b1b1f11f1dbab75f8b3303543078 Author: Cosimo Cecchi Date: 2010-12-01 i18n: update POTFILES.in M po/POTFILES.in commit c745b5c50ea9e103861cafb4ce210b375034dd8d Author: Cosimo Cecchi Date: 2010-12-01 mime-application-chooser: add a 'Show other applications' button Similar to GtkAppChooserDialog; the 'Add' button now adds the currently selected application, and it becomes insensitive when necessary. M libnemo-private/nemo-mime-application-chooser.c commit 677c52173a1f5ba1a8e3db8c70cd96f27fb90200 Author: Cosimo Cecchi Date: 2010-11-30 mime-application-chooser: tweak buttons ordering M libnemo-private/nemo-mime-application-chooser.c commit 2d58f04289c31c4a7de9318327e3edd111d8735d Author: Cosimo Cecchi Date: 2010-11-30 mime-application-chooser: use populate-popup for removing apps Instead of having yet another button. M libnemo-private/nemo-mime-application-chooser.c commit 3e5dcec59709514b2998963b539ec77ed9d5c46f Author: Cosimo Cecchi Date: 2010-11-23 open-with-dialog: remove NemoOpenWithDialog It's useless now that we ported everything to GtkAppChooser. M libnemo-private/Makefile.am D libnemo-private/nemo-open-with-dialog.c D libnemo-private/nemo-open-with-dialog.h commit f83be2507361b337fb7eaf59a50cdca7f49ca53c Author: Cosimo Cecchi Date: 2010-11-23 properties-window: use new NemoMimeApplicationChooser API M src/file-manager/fm-properties-window.c commit e86ded0eb9842eb9d4a0ac6c83333e9ce3ffcd0e Author: Cosimo Cecchi Date: 2010-11-23 mime-application-chooser: rewrite to make it use GtkAppChooserWidget M libnemo-private/nemo-mime-application-chooser.c M libnemo-private/nemo-mime-application-chooser.h commit 7734204774ab87e07ddec50acbb62e3f9acd1120 Author: Cosimo Cecchi Date: 2010-11-23 mime-actions: port to GtkAppChooserDialog M libnemo-private/nemo-mime-actions.c commit 34a18d5b19df317bf19e4fdc67ea0c4007ed0375 Author: Cosimo Cecchi Date: 2010-11-23 directory-view: port to GtkAppChooserDialog M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-directory-view.c commit d7acbb0c1d58205f5c97d7c80fde034088feef9f Author: Jorge González Date: 2010-11-30 Updated Spanish translation M po/es.po commit 20c94e66a20a9d2d4643ce58b2696bbf5e5334b8 Author: Cosimo Cecchi Date: 2010-11-30 build: remove old X_LIBS variable M eel/Makefile.am commit fd03f393a55ea377583b821f578951b3ace237a5 Author: Cosimo Cecchi Date: 2010-11-30 docs: remove manual for nemo-file-management-properties The binary is not installed anymore. M docs/Makefile.am D docs/nemo-file-management-properties.1 commit 41059f897c33f981ce03c1dd62bcbbd20a53c52d Author: Cosimo Cecchi Date: 2010-11-29 Release 2.91.3 M NEWS M configure.in commit b83c479d40b86d8a4e537a1c30d2375a1277898c Author: Cosimo Cecchi Date: 2010-11-29 i18n: update POTFILES.in M po/POTFILES.in commit b088cc0bcf36bcbf4551de2e972b44423c92fb4f Author: Cosimo Cecchi Date: 2010-11-29 gsettings: remove org.gnome.media-handling gschemas from nemo They don't belong here anymore now that the media preferences have been moved elsewhere. M libnemo-private/Makefile.am M libnemo-private/nemo.convert D libnemo-private/org.gnome.media-handling.gschema.xml.in commit 6cb06b98d4c492ec774b9335565994190857c82d Author: Daniel Nylander Date: 2010-11-28 Updated Swedish translation M po/sv.po commit 92706c7ce3bd9dd703d7ad118e6bb95723e6cdd8 Author: Victor Osadci Date: 2010-11-27 query-editor: identify ogg/vorbis files as music (#365095) M src/nemo-query-editor.c commit aa9b6675d8a92329a7cba69c9bdb53fa30f87858 Author: Cosimo Cecchi Date: 2010-11-26 connect-dialog: use the correct string for gvfs (#635431) M src/nemo-connect-server-dialog.c commit 9d2d96fd2968e8f8a9b1f3a46660f27d6377f145 Author: Cosimo Cecchi Date: 2010-11-25 autorun: remove nemo-autorun.[ch] M libnemo-private/Makefile.am D libnemo-private/nemo-autorun.c D libnemo-private/nemo-autorun.h M po/POTFILES.in commit 912320008beae418d71a74361c1a0d9bcdae6f60 Author: Cosimo Cecchi Date: 2010-11-25 autorun: move get_x_content_types_for_mount () to file-utilities So that we can remove nemo-autorun.[ch] M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file-utilities.h M src/file-manager/fm-directory-view.c M src/nemo-window-manage-views.c commit 9281506c5b264e81a4610a4f6a20f2a42eab207b Author: Cosimo Cecchi Date: 2010-11-25 autorun: move nemo_launch_application_for_mount () Also add the parent window parameter to it, so that we get startup notification. M libnemo-private/nemo-autorun.c M libnemo-private/nemo-autorun.h M libnemo-private/nemo-program-choosing.c M libnemo-private/nemo-program-choosing.h M src/nemo-x-content-bar.c commit 7c71b7f383ece8ad9be39fcb28b9377364a35cb3 Author: Tomas Bzatek Date: 2010-11-23 Prevent showing asserts when GFile is no longer valid after unmount M src/nemo-application.c commit 36965ee18ed890f6899588df730345986213d7d1 Author: Tomas Bzatek Date: 2010-11-23 Includes cleanup M libnemo-private/nemo-autorun.c M libnemo-private/nemo-autorun.h commit e4fb850f0fb43a08ebca016c31fece6211073cb7 Author: Tomas Bzatek Date: 2010-11-23 Remove media preferences GSettings stuff M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h commit 33df383a2692dd8d8aba802710da28a6063f3bbc Author: Tomas Bzatek Date: 2010-11-23 Remove unused autorun code M libnemo-private/nemo-autorun.c M libnemo-private/nemo-autorun.h commit 9729357aa457bbc78e6e2370015b6ccb3e73cbf6 Author: Tomas Bzatek Date: 2010-11-23 Don't autorun on nemo_file_operations_mount_volume() M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-operations.h M src/nemo-places-sidebar.c commit ab7d5069f1658edbf6516f441801d0d2599f658b Author: Tomas Bzatek Date: 2010-11-23 Drop obsolete eject-button signal watch M src/nemo-application.c commit 045224ee72d896499fc0b04ced7dccb3e135e177 Author: Tomas Bzatek Date: 2010-11-23 Includes cleanup M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-vfs-file.c M src/nemo-file-management-properties.c M src/nemo-places-sidebar.c commit 8e0a51410a116ce875d04d205d3e89398bfae970 Author: Tomas Bzatek Date: 2010-11-23 Remove autorun after mount This way we lose ability to focus already open windows after mount. Since gnome-settings-daemon uses default folder handler to show freshly mounted folder, there's little we can do. M src/nemo-application.c commit cdae5fea2a466bf09ef236499e9c442888516cb1 Author: Tomas Bzatek Date: 2010-11-23 Don't automount volumes on nemo startup M src/nemo-application.c M src/nemo-application.h commit 36831040af2e262ee8e66768152d2057139af8b8 Author: Cosimo Cecchi Date: 2010-11-15 file-management-properties: remove the properties binary We are moving the Media preferences to a separate control-center panel, as they're desktop-wide settings. The actual autorun/automount will be handled by gnome-settings-daemon. The result is that we don't need to install our old gnome-control-center capplet anymore, so we can remove all this code. M configure.in M data/Makefile.am D data/nemo-file-management-properties.desktop.in.in M src/Makefile.am D src/nemo-file-management-properties-main.c M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit a6f4e065a66eeb5d74322bfb5cfd4320135a61d1 Author: Kjartan Maraas Date: 2010-11-20 Updated Norwegian bokmÃ¥l translation M po/nb.po commit b28340da1b97026938035fdb8544c4b8722ecdc9 Author: Gheyret T.Kenji Date: 2010-11-20 Added UG translation M po/ug.po commit df382f58d0ec2a1b779cf80048ad70944c8859df Author: Tomas Bzatek Date: 2010-11-16 Use G_SETTINGS_BIND_INVERT_BOOLEAN where appropriate M src/nemo-file-management-properties.c commit a5caa0e98c844a23656cafaa9b6f985dada7bc51 Author: Javier Jardón Date: 2010-11-16 Use GSourceFunc instead GtkFunction M libnemo-private/nemo-dnd.c M libnemo-private/nemo-dnd.h M libnemo-private/nemo-icon-container.c commit 812fcf2fbf4da7c97a6fc9eca1c64f9c9c225c90 Author: Daniel Șerbănescu Date: 2010-11-14 Updated Romanian translation M po/ro.po commit d9d2ed6cde69ce2ffb2fdd6028e36a0e760672a8 Author: Lucian Adrian Grijincu Date: 2010-11-14 Updated Romanian translation M po/ro.po commit e7d2c7468f0b04e6ee87981c291d6f2ed1aa87bb Author: Theppitak Karoonboonyanan Date: 2010-11-14 Updated Thai translation. M po/th.po commit f7b5d4b653317f080547c7b18649fd45531772a4 Author: Gheyret T.Kenji Date: 2010-11-13 Added UG translation M po/ug.po commit 5afa93854e2bde4f89910cff3a98546a66d880d2 Author: Baptiste Mille-Mathias Date: 2010-11-12 libgnome-desktop build fixes More porting from libgnome* to libgnome-desktop to fix build breakage M eel/eel-gnome-extensions.c M libnemo-private/nemo-thumbnails.c M src/file-manager/fm-properties-window.c commit 7c042f64ee59d9f149252f7e78e11ca6ad7d9dbe Author: Cosimo Cecchi Date: 2010-11-12 application: fix interaction with the session manager The porting to GApplication broke the session management code that took care of saving and loading existing windows if the session saving is active. We now fix it by changing a bit our startup process, so that the EggSMClient object is actually created at the right time. M src/nemo-application-smclient.c M src/nemo-application-smclient.h M src/nemo-application.c M src/nemo-application.h commit fb574c106185e773449a6d92bd54512b2074dd01 Author: Florian Müllner Date: 2010-11-11 desktop-background: Fix include The file gnome-bg.h was moved from libgnomeui to libgnome-desktop. M configure.in M libnemo-private/nemo-desktop-background.c commit a2eb813e14be86168173e4f95385934feddf2937 Author: Javier Jardón Date: 2010-11-11 Use gtk_separator_new() instead gtk_[h|v]separator_new() M libnemo-private/nemo-column-chooser.c M src/file-manager/fm-properties-window.c commit 3b586c5e61ce80a527f2abdc6d3e45189fee6985 Author: Tomas Bzatek Date: 2010-11-10 Bump gnome-desktop requirement for new gnome-bg M configure.in commit 87d8e557c13f3d51098cfe03cf2727102e8a8937 Author: Cosimo Cecchi Date: 2010-11-10 Release 2.91.2 M NEWS M configure.in commit 7b1c3ddd655977e3a26365942d21d83abed1f75d Author: Cosimo Cecchi Date: 2010-11-09 file: remove nemo_file_get_emblem_pixbufs() It's not used anymore. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 6a276d59af54413c59188ffb0143ffa6e1fe94a1 Author: Cosimo Cecchi Date: 2010-11-09 icon-container: don't care about the emblem size Use only GIcons for emblems, not pixbufs. We used to rely on pixbufs to get emblems at a specific size, but that's not important anymore now that GTK+ takes care of it internally. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M src/file-manager/fm-icon-container.c commit b118093fbc2b5a236a4502ac6e053ab9e64a9db1 Author: Tomas Bzatek Date: 2010-11-09 Port desktop background handling to GSettings See bug 626018 for details. M libnemo-private/nemo-desktop-background.c commit 36f64c7f85e305939ec9d5ddb7bb7a6a121c0c08 Author: Matej UrbanÄiÄ Date: 2010-11-06 Updated Slovenian translation M po/sl.po commit 8fd2694ee06fbbfc0cc9452b6ce5cc0a27ff160b Author: Cosimo Cecchi Date: 2010-11-05 icon-canvas-item: remove the emblem layouting code We can directly use GTK+ for this now. M libnemo-private/nemo-icon-canvas-item.c commit 79a9c6a36256d430459b4d2a7bc37e0d691c8e5a Author: Cosimo Cecchi Date: 2010-11-05 sq M libnemo-private/nemo-icon-container.c commit a728e7b830ebeccfba6d851a5b005033ba07189b Author: Cosimo Cecchi Date: 2010-11-05 icon-container: apply emblems directly on the pixbuf Do that before setting the pixbuf to the NemoIconCanvasItem, so the logic in there can be removed. M libnemo-private/nemo-icon-container.c commit e72391a9cecd0fe11458a6633edde3e800a797aa Author: Cosimo Cecchi Date: 2010-11-05 general: use GdkPixbuf/GIcon interface to set emblems in treeviews So that emblems get composited for us also on pixbufs such as thumbnails. M configure.in M src/file-manager/fm-list-model.c M src/file-manager/fm-tree-model.c commit 4882f2ac24dfcf33e06e5e9a06dd2cd0368069ec Author: Cosimo Cecchi Date: 2010-11-04 application: fix some bad interactions with GApplication M src/nemo-application.c M src/nemo-application.h commit e038864cdaf728b1a8407dfb8e5949cf467b72b7 Author: Ivar Smolin Date: 2010-11-03 [l10n] Updated Estonian translation M po/et.po commit 72b34f160a49edc40dccfb435330e30cd14feb9c Author: Yaron Shahrabani Date: 2010-11-03 Updated Hebrew translation. M po/he.po commit a0c3d8e339625eb1f84b769a4f81fd73785556bc Author: Takayuki KUSANO Date: 2010-11-03 Updated Japanese translation M po/ja.po commit 805a147bac55d38464f97ce933b33b8e7e42432d Author: Fran Diéguez Date: 2010-11-03 Updated Galician translations M po/gl.po commit 373683da693e6f4a768c7eb6f1fc793315c23db7 Author: Cosimo Cecchi Date: 2010-11-02 pathbar: fix crasher when unmounting volumes (#627901) M src/nemo-pathbar.c commit 57f92209189de791904b014f49b8a383ca1a5bd2 Author: Cosimo Cecchi Date: 2010-11-02 build: use X11 pkg-config files instead of homebrew checks M configure.in commit 64640897a2357e6fc442e14372ca3950e4b54090 Author: Ahmed Noor Kader Mustajir Md Eusoff Date: 2010-11-02 Partial update of Malay translation M po/ms.po commit efe7e4727d56bc8872557674aa90037b255229d5 Author: Jorge González Date: 2010-11-01 Updated Spanish translation M po/es.po commit d61097230c3b77931b7fc6212f70104f1fcdab04 Author: Cosimo Cecchi Date: 2010-11-01 Release 2.91.1 M NEWS M configure.in M po/POTFILES.in commit 2b99456d621c08bd097b87726704e671c76be1a1 Author: Cosimo Cecchi Date: 2010-11-01 [eel] remove eel_gtk_adjustment* functions They should not be needed now. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 8b4271f5ad62d00b76d7e34a594c9b1819eb495e Author: Cosimo Cecchi Date: 2010-11-01 desktop-icon-view: don't use eel helper to set adjustment values M src/file-manager/fm-desktop-icon-view.c commit 3a9c6cd783507cc2fbd0a838cd6710f74e7f17dd Author: Cosimo Cecchi Date: 2010-11-01 icon-container: don't use eel helper to set adjustment values M libnemo-private/nemo-icon-container.c commit 7029d317446f26f829a794884abe07d6ce980a5f Author: Cosimo Cecchi Date: 2010-11-01 canvas: remove commented out code M eel/eel-canvas.c commit 27f14a83ca6b656c20f6f7851b11dee12bfd4540 Author: Holger Berndt Date: 2010-10-05 Add possibility to register an external bulk rename tool If the new setting "bulk-rename-tool" in org.gnome.nemo.preferences is set to a non-empty string, it is treated as a bulk renamer and gets invoked on a Rename action if multiple files are selected. Nemo appends a space separated list of URIs of all selected files to the command string. https://bugzilla.gnome.org/show_bug.cgi?id=306489 M libnemo-private/nemo-global-preferences.h M libnemo-private/org.gnome.nemo.gschema.xml.in M src/file-manager/fm-directory-view.c commit b4aa3c083ab7616f321df4ade75e4d850142eff6 Author: Bastien Nocera Date: 2010-10-29 Move nemo-sendto extension to nemo And add a check for the presence of nemo-sendto to the initialisation of the object. Building the extension is optional, though on by default. https://bugzilla.gnome.org/show_bug.cgi?id=633485 M Makefile.am M configure.in A nemo-sendto-extension/Makefile.am A nemo-sendto-extension/nemo-nste.c A nemo-sendto-extension/nemo-nste.h A nemo-sendto-extension/nemo-sendto-module.c commit 0609431a5cb3803d0b98bd333f90e3c7796f86b7 Author: Paolo Borelli Date: 2010-11-01 Use gtk_paned_new instead gtk_[h|v]paned_new M src/nemo-navigation-window.c commit 059d9a384aedcc6dcc1e249a9979922278a90f60 Author: Yaron Shahrabani Date: 2010-11-01 Updated Hebrew translation. M po/he.po commit 802e1967cdf301a50b8403cfe820097561c60033 Author: Cosimo Cecchi Date: 2010-11-01 [eel] remove unused eel_gradient code M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 7dee3226ad6b3aa1c782cc3d2969e32c5eeae3f3 Author: Cosimo Cecchi Date: 2010-11-01 [eel] remove eel_gdk_pixbuf_list_ref() M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h M libnemo-private/nemo-icon-canvas-item.c commit 00c0b9daa2053a110e17c64fb79ce4884290dc76 Author: Cosimo Cecchi Date: 2010-11-01 [eel] remove unused eel_get_filename_charset() M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit 31dfbdc19075ddf92b4f04a2f84e3111c3fb429b Author: Cosimo Cecchi Date: 2010-11-01 [eel] remove eel_gtk_widget_set_shown() It's not used anymore. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit bb145a018a9d66b748971e40be4e09a7f843b2be Author: Cosimo Cecchi Date: 2010-11-01 places-sidebar: use gtk_widget_set_visible() instead of the eel helper M src/nemo-places-sidebar.c commit 654b8f8a52d2343293c03eec304d20b7904867a1 Author: Jorge González Date: 2010-10-31 Updated Spanish translation M po/es.po commit 5e669515fd7f760382e6b7aa1449734a35a2d7f4 Author: Cosimo Cecchi Date: 2010-10-31 general: use g_list_free_full() instead of eel functions M configure.in M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h M libnemo-private/nemo-autorun.c M libnemo-private/nemo-clipboard.c M libnemo-private/nemo-debug-log.c M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-dnd.c M libnemo-private/nemo-file-changes-queue.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-merged-directory.c M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-mime-application-chooser.c M libnemo-private/nemo-open-with-dialog.c M libnemo-private/nemo-program-choosing.c M libnemo-private/nemo-query.c M libnemo-private/nemo-search-engine-beagle.c M libnemo-private/nemo-search-engine-simple.c M libnemo-private/nemo-search-engine-tracker.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-list-model.c M src/file-manager/fm-list-view.c M src/file-manager/fm-properties-window.c M src/file-manager/fm-tree-model.c M src/file-manager/fm-tree-view.c M src/nemo-application.c M src/nemo-bookmark-list.c M src/nemo-history-sidebar.c M src/nemo-navigation-window-slot.c M src/nemo-pathbar.c M src/nemo-places-sidebar.c M src/nemo-query-editor.c M src/nemo-spatial-window.c M src/nemo-trash-bar.c M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window.c commit 7d05f8804f044ef13b4f89a49a1a7b7730f3a279 Author: Cosimo Cecchi Date: 2010-10-30 build: bump GLib and GTK+ requirements M configure.in commit d8ad1ab61cdb9929a8cb4f7d393e8b501e054289 Author: Cosimo Cecchi Date: 2010-10-30 application: use prettier format strings M src/nemo-application.c commit f48796637854ca784f7458a387e3607917ef5990 Author: Cosimo Cecchi Date: 2010-10-30 application: fix interaction with SMCLient Use late-initialization, otherwise we and up locked while reading session information. Also, don't try to use that information more than once in the app lifetime. M src/nemo-application-smclient.c M src/nemo-application.c M src/nemo-application.h commit d09b45c72bb1c3573b8f1c0bc83f1d8448ba5309 Author: Cosimo Cecchi Date: 2010-10-30 smclient: backport and tweak a patch for late SMClient initialization This is a tweak of a patch bt Vincent Untz, see libegg commit dc8db697dfaf8e57fbc9fe5251675a27e8c54f44 M cut-n-paste-code/libegg/eggsmclient.c commit 2260005986d8c620669e56c4b9f2fba12e8e0625 Author: Cosimo Cecchi Date: 2010-10-30 canvas: use GTK_LAYOUT casts instead of going through the parent struct That's just confusing. M eel/eel-canvas.c commit ebee13eef39824ebe536d0e42a35337097a33942 Author: Cosimo Cecchi Date: 2010-10-30 desktop-icon-view: don't unconditionally unref the desktop background M src/file-manager/fm-desktop-icon-view.c commit e383af25948a9b93915b1c39ae379bf0eace06ac Author: Cosimo Cecchi Date: 2010-10-30 application: close desktop windows on quit M src/nemo-application.c commit 12c7a03bfe3c49078cb5b44ff2651eb9ce1edce4 Author: Matthias Clasen Date: 2010-10-28 editable-label: don't use deprecated size_request vfunc M eel/eel-editable-label.c commit b532d0d9290d1731203d971e7c679979265f0a43 Author: Cosimo Cecchi Date: 2010-10-28 window: don't use deprecated size_request vfunc Also, cleanup the size_request code a bit. M src/nemo-window.c commit 1cdd0b41bf9de69a93cb166636d7eccff9f5355f Author: Cosimo Cecchi Date: 2010-10-28 icon-container: remove size_request vfunc impl It doesn't seem to do anything useful. M libnemo-private/nemo-icon-container.c commit 22cb1accd98c1ae10938eac10cc6beda8fb6b145 Author: Cosimo Cecchi Date: 2010-10-28 pathbar: don't use deprecated size_request vfunc M src/nemo-pathbar.c commit 305d1b05896e39a5e3181247d9d4e837b4c35067 Author: Cosimo Cecchi Date: 2010-10-27 image-properties-page: don't special-case old EXIF/XMP APIs M src/nemo-image-properties-page.c commit 393df7a83c0a779784095a993db238867daeaa7a Author: Cosimo Cecchi Date: 2010-10-27 build: simplify configure script Also, don't support old exif/exempi APIs anymore. D acconfig.h M check-headers-in-Makefile.pl M configure.in M cut-n-paste-code/libegg/Makefile.am M docs/reference/libnemo-extension/Makefile.am M eel/Makefile.am M libnemo-extension/Makefile.am M libnemo-private/Makefile.am M src/Makefile.am M src/file-manager/Makefile.am M test/Makefile.am commit 8d9d6128b69e641c2b77322e8832be8ae0b9bf93 Author: Cosimo Cecchi Date: 2010-10-27 application: properly handle --no-default-window M src/nemo-application.c M src/nemo-main.c commit 13630f0b4d58e3b2be6781f3049d13c1095b0dca Author: Cosimo Cecchi Date: 2010-10-27 application: perform checks in NemoApplication if requested so M src/nemo-application.c M src/nemo-main.c commit 48f17e3726bc0e37d35714d5f18ce56498508d79 Author: Cosimo Cecchi Date: 2010-10-27 application: respect the 'exit-with-last-window' setting. If it's set, we quit immediately. M src/nemo-application.c commit df8bdf21cffc1b2370b34173487219ee3568d040 Author: Cosimo Cecchi Date: 2010-10-27 application: cleanup M src/nemo-application.c commit e0f68583d47d23738afd7695f6137e2d2552b45d Author: Cosimo Cecchi Date: 2010-10-27 application: don't unref unconditionally As we're building the NemoUndoManager in _startup() now, which might not have been called if the application is remote. M src/nemo-application.c commit e297d4108760e701b3cd276e9d4612b1933efee0 Author: Cosimo Cecchi Date: 2010-10-27 application: add the desktop windows to the application window list So that we don't quit immediately when we close the browser window. M src/nemo-application.c commit 248339e40908fc58a5edad462c77b667d5cb8315 Author: Cosimo Cecchi Date: 2010-10-27 application: remove get_n_windows() M src/nemo-application.c M src/nemo-application.h M src/nemo-window-manage-views.c commit 56dd8bb3d5594d9caffda23400f7bd64c94e5a4c Author: Cosimo Cecchi Date: 2010-10-27 application: move other init/cleanup functions in the app class Instead of mixing them between nemo-main and nemo-application M src/nemo-application.c M src/nemo-application.h M src/nemo-main.c commit 2d702e1eeb7f9a8ad1286db39f5088bf39f1229c Author: Cosimo Cecchi Date: 2010-10-27 application: make sure to initialize GTK+ during _startup() M src/nemo-application.c commit 0712652a5f3730d10bca4040b68f3dda1e98c0bf Author: Cosimo Cecchi Date: 2010-10-27 desktop-window: monitor the desktop dir key from NemoDesktopWindow Remove that code from NemoApplication, it doesn't belong there. M src/nemo-desktop-window.c commit 7500dd445df5a0cf082464f099169666727f6ec2 Author: Cosimo Cecchi Date: 2010-10-27 [src] use new GtkApplication API to handle windows Instead of old nemo-main/NemoApplication functions to register windows within the mainloop. M src/nemo-application-smclient.c M src/nemo-navigation-window-menus.c M src/nemo-window-manage-views.c M src/nemo-window.c commit a8481ee4bd8d34e792d63598fa5efb47736f9de4 Author: Cosimo Cecchi Date: 2010-10-27 main: adapt to GtkApplication changes This code should be much easier now that window lifecycle is handled by GtkApplication itself. M src/Makefile.am M src/nemo-application-smclient.c M src/nemo-application.c M src/nemo-main.c D src/nemo-main.h M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-manage-views.c M src/nemo-window.c commit b03b081e91d376140e4fc94fd885bf7d13fc57c5 Author: Cosimo Cecchi Date: 2010-10-27 application: make NemoApplication a GtkApplication subclass M src/nemo-application.c M src/nemo-application.h commit bb52a77678b732626693869e315bb78c77635a0b Author: Cosimo Cecchi Date: 2010-10-26 application: replace custom GIcon custom load/save code with GIO one M src/nemo-application-smclient.c commit dc0b129436d5c9eb712a80852768387fc2b8cd7c Author: Cosimo Cecchi Date: 2010-10-26 application: split SmClient code in its own module. M src/Makefile.am A src/nemo-application-smclient.c A src/nemo-application-smclient.h M src/nemo-application.c commit d811553a4e74106efdf8bf6c91c6d29944ed6df7 Author: Cosimo Cecchi Date: 2010-10-22 general: use new GtkScrollable interface M eel/eel-canvas.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-tree-view-drag-dest.c M src/file-manager/fm-desktop-icon-view.c commit f9aa5d9442ae918bb1e583d1543b8da0b51fb959 Author: Cosimo Cecchi Date: 2010-10-22 application: go back to libunique for now While GApplication API settles. Also, porting to the new GApplication would require quite some refactoring. M configure.in M src/nemo-application.c M src/nemo-application.h M src/nemo-main.c commit 0e755165bc561b2c61628519c090cd826f7609c6 Author: Cosimo Cecchi Date: 2010-10-22 build: bump GTK+ required version M configure.in commit 6669f155734c320617bcf79f3b5d8f315f4886f9 Author: Cosimo Cecchi Date: 2010-10-22 preferences: cleanup expand/fill flags Probably a change in GTK+ requires fixing this flags, so that the dialog doesn't look odd. M src/nemo-file-management-properties.ui commit 18fc6dd2516f9091570902640032e68b263cfddf Author: Cosimo Cecchi Date: 2010-10-22 preferences: use GtkComboBoxText in the GtkBuilder file M src/nemo-file-management-properties.ui commit f123f99bee1005cd279783f9d441f538fcf85542 Author: Cosimo Cecchi Date: 2010-10-21 [src] don't use GtkComboBox text APIs (#632651) They got replaced by GtkComboBoxText. Thanks to Mathias Clasen and Flo Gravo. M src/file-manager/fm-properties-window.c M src/nemo-file-management-properties.c M src/nemo-query-editor.c M src/nemo-view-as-action.c commit d5ad28bff6c1ebcd6e1560d2036655ffa9562e8b Author: Andrej ŽnidarÅ¡iÄ Date: 2010-10-30 Updated Slovenian translation M po/sl.po commit 9c97179025ca98641737b44bf0a6409757ee2f18 Author: Carles Ferrando Date: 2010-10-29 Updated Catalan (Valencian) translation M po/ca@valencia.po commit 716ad3f41eae1773cc260427ccf87c959a2bc3a3 Author: Jorge González Date: 2010-10-28 Updated Spanish translation M po/es.po commit 4d1464f859439b12b8c79bac919da333caea28a3 Author: Mattias Põldaru Date: 2010-10-28 [l10n] Updated Estonian translation M po/et.po commit bbd7d86fc4ef27f4df3537844fc5998e4c29949e Author: Yaron Shahrabani Date: 2010-10-26 Updated Hebrew translation. M po/he.po commit 540dc54229fee2e5e5d53453c61d4dd48537545c Author: Aron Xu Date: 2010-10-25 Update Simplified Chinese translation. M po/zh_CN.po commit 87ccfbf66ebed490eb8c921a712d8cb94e4ad817 Author: Gheyret T.Kenji Date: 2010-10-21 Added UG translation M po/ug.po commit c30f0785727ebad08f3891d594831596d16598e0 Author: Fran Diéguez Date: 2010-10-20 Updated Galician translations M po/gl.po commit 18e74876421fd38584c9dd105914d7a626aed3b7 Author: Mario Blättermann Date: 2010-10-19 [i18n] Updated German translation M po/de.po commit 1f135b5da410b7a0052d22322d740037036b39b0 Author: Tomas Bzatek Date: 2010-10-19 Use gnome global 'show-desktop-icons' settings See bug 632225 for details. M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo.convert M libnemo-private/org.gnome.nemo.gschema.xml.in M src/nemo-application.c commit c0e91e6a53dc3d920a25be1cf836c28730e193d8 Author: Милош Поповић Date: 2010-10-18 Updated Serbian Translation M po/sr.po M po/sr@latin.po commit 2c04203ef9c3be3fd209589e8ec7007889323991 Author: Mattias Põldaru Date: 2010-10-16 [l10n] Updated Estonian translation M po/et.po commit d3ab8e137ae957e5afef54bf0ec1e275b96caab5 Author: Marcus Carlson Date: 2010-07-23 image-properties-page: call gdk_pixbuf_loader_close() earlier (#558267) This helps smaller images (>8192 bytes) to signal size_prepared before reading image geometry. M src/nemo-image-properties-page.c commit 49ff3247d17e57afc3612de2f709997c8bb92408 Author: Jorge González Date: 2010-10-14 Updated Spanish translation M po/es.po commit 1cb6ea5dcb0cd384f49aac063e56d24203683602 Author: Cosimo Cecchi Date: 2010-10-14 icon-container: use the right signature for the 'preedit-changed' cb This should fix bug #629159. Thanks to Fumihito YOSHIDA to notice this. M libnemo-private/nemo-icon-container.c commit 5e383c3377ef2c2333f97102826880e86fdddef2 Author: Yaron Shahrabani Date: 2010-10-14 Updated Hebrew translation. M po/he.po commit 0f8dcf2ac394121c488afdf0fecc2b7afeb673b6 Author: Cosimo Cecchi Date: 2010-10-13 column-utilities: fix a TODO about a missing description string M libnemo-private/nemo-column-utilities.c commit b0550951f461c2033f4d1aaa4404078c7a70f220 Author: Antoine Jacoutot Date: 2010-10-13 column-utilities: disable SELinux column if !HAVE_SELINUX (#631093) M libnemo-private/nemo-column-utilities.c commit ebcbb167876f8b4491af0bc86bc29015c211b3af Author: Olivier Tilloy Date: 2010-08-17 icon-view: if possible, use the local path for the preview (#624841) This solves issues where the audio previewer is not capable of understanding some GVfs URIs. M src/file-manager/fm-icon-view.c commit 01f39f471005e788281c18da30563c0184434fff Author: Cosimo Cecchi Date: 2010-10-13 background: make the fading effect optional (#623174) This is implemented with a GSettings key. Thanks to Brian Cameron for the initial patch. M libnemo-private/nemo-desktop-background.c M libnemo-private/nemo-global-preferences.h M libnemo-private/org.gnome.nemo.gschema.xml.in commit 4cd72a64d67cdfd1d9351c52b2cf8463efd0c141 Author: Cosimo Cecchi Date: 2010-10-13 background: fix the indentation modeline M libnemo-private/nemo-desktop-background.c commit e676a40dcef267c312e27c4191adc0d22eaf1554 Author: Cosimo Cecchi Date: 2010-10-13 preferences: remove obsolete background preferences M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo.convert M libnemo-private/org.gnome.nemo.gschema.xml.in commit d26ae7b60c07057c6fbf926a3a805c29a5cfc3b2 Author: A S Alam Date: 2010-10-13 update typo in translation: Punjabi M po/pa.po commit 1620bd8a4e4ab1760c5c518dd954a4471645ce87 Author: Cosimo Cecchi Date: 2010-10-12 horizontal-splitter: remove, and use a regular GtkPaned instead The feature it was bringing in (shrink when the paned handle is double-clicked) is even confusing. M libnemo-private/Makefile.am D libnemo-private/nemo-horizontal-splitter.c D libnemo-private/nemo-horizontal-splitter.h M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window.c commit c05e2d7cdf8a5da4b9a353529ed214e7b36de8ca Author: Mattias Põldaru Date: 2010-10-11 [l10n] Updated Estonian translation M po/et.po commit 62690ab70e62ae108d1a03c0d19510c58dd882c0 Author: Jorge González Date: 2010-10-10 Updated Spanish translation M po/es.po commit 5653060d93db2686997faa8f6a10b87659d09c0a Author: Cosimo Cecchi Date: 2010-10-10 background: assume the widget is an IconContainer M libnemo-private/nemo-desktop-background.c M libnemo-private/nemo-desktop-background.h M libnemo-private/nemo-icon-dnd.c M src/file-manager/fm-desktop-icon-view.c commit 7e7691f0332a9b708217432a692cdf27e536cbcc Author: Cosimo Cecchi Date: 2010-10-10 icon-dnd: use new background API M libnemo-private/nemo-icon-dnd.c commit 843e6a9b9331a3e7a318df03b4074deb1163e386 Author: Cosimo Cecchi Date: 2010-10-10 background: make NemoDesktopBackground a singleton This avoids the need of using g_object_set_data() hacks to get the background from the desktop icon container. M libnemo-private/nemo-desktop-background.c M libnemo-private/nemo-desktop-background.h commit d4342547ebc2e26547cf8f1449bfd2e8fe4c443f Merge: eda5d36 66cd22c Author: Cosimo Cecchi Date: 2010-10-09 Merge branch 'background-untangling' commit eda5d36cadf299cf62429c1e29763b5dd3d53c40 Author: Jorge González Date: 2010-10-09 Updated Spanish translation M po/es.po commit 66cd22c908cc73954fad3e261d28ae6a05ea1bc2 Author: Cosimo Cecchi Date: 2010-10-09 background: refactor code into NemoDesktopBackground Remove the DirectoryBackground->EelBackground->GnomeBG abstraction and add a new object, NemoDesktopBackground, which is a thin wrapper around GnomeBG, which takes care of handling background changes. M eel/Makefile.am D eel/eel-background.c D eel/eel-background.h M eel/eel-lib-self-check-functions.h M eel/eel.h M libnemo-private/Makefile.am M libnemo-private/nemo-autorun.h A libnemo-private/nemo-desktop-background.c A libnemo-private/nemo-desktop-background.h D libnemo-private/nemo-directory-background.c D libnemo-private/nemo-directory-background.h M libnemo-private/nemo-icon-dnd.c M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/fm-list-view.c M test/Makefile.am M test/test.c commit 3bcd8464bcc9bdc44086275df8f6d1d29829bd8d Author: Cosimo Cecchi Date: 2010-10-08 icon-dnd: adapt to EelBackground changes. M libnemo-private/nemo-icon-dnd.c commit b6b2d222a4fc5150370589fd70811707139d3bbd Author: Cosimo Cecchi Date: 2010-10-08 directory-background: update to simplified EelBackground API EelBackground doesn't have any signals anymore, so don't try to connect to them. M libnemo-private/nemo-directory-background.c commit b137867bfaf9d1175b883d31baf18ae7e21d8549 Author: Cosimo Cecchi Date: 2010-10-08 eel-background: cleanup code not related to desktop background Remove all the EelBackground code that's not related to desktop background handling. M eel/eel-background.c M eel/eel-background.h commit c185321ed28d8aba69734039211946c739d32467 Author: Cosimo Cecchi Date: 2010-10-07 views: don't use EelBackground to set sensitive/insensitive bg Use an implementation for each view, don't relying on EelBackground. M src/file-manager/fm-empty-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c commit c31c5e360b0726788af93f6e404e1686d46b1f61 Author: Cosimo Cecchi Date: 2010-10-07 directory-view: call set_active() on subclasses to set insensitive bg Don't have a default implementation relying on EelBackground here. M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h commit ef74d171892ed7189b4a52695ae8de575d2dac1a Author: Cosimo Cecchi Date: 2010-10-07 icon-container: add set_active() This internally replaces EelBackground usage to set the non-sensitive background on non-active panes. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M libnemo-private/nemo-icon-private.h commit 42e726853157e561dc99d61180cae036f751fef8 Author: Cosimo Cecchi Date: 2010-10-07 eel-gdk-extensions: add eel_make_color_inactive() to public API M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 11c0ce912f2c6d5c933968780a53f5261f125fec Author: A S Alam Date: 2010-10-09 updating translation for Punjabi M po/pa.po commit 9e35d0ca6f10650f4d86963a3b5e986e3ec17681 Author: Changwoo Ryu Date: 2010-09-24 Updated Korean translation M po/ko.po commit 407666719856127547f5c2f3f03f6a050858239a Author: Cosimo Cecchi Date: 2010-10-06 editable-label: fix cairo drawing regressions M eel/eel-editable-label.c commit 75e101268198ce92e8165c7adda55cac69d1f93a Author: Fran Diéguez Date: 2010-10-07 Updated galician translations M po/gl.po commit a0c3ff8742e2f877b73678cff6d1a2950296e0ba Author: Yaron Shahrabani Date: 2010-10-06 Updated Hebrew translation. M po/he.po commit 31fac990215a99a034b62e626fb86e02ad751a31 Author: Cosimo Cecchi Date: 2010-10-05 Release 2.91.0.1 M NEWS M configure.in commit 33c9b6d24a60079fe6c4c1be281c76f43def6fee Author: Cosimo Cecchi Date: 2010-10-05 cell-renderer-text-ellipsized: use new GtkSizeRequest vfunctions This fixes the 'Name' column being too thin in list view. M libnemo-private/nemo-cell-renderer-text-ellipsized.c commit 61906b05ec90d5d4759ae7ff7fc7aca40fb18f15 Author: Cosimo Cecchi Date: 2010-10-05 window-toolbars: show/hide the spinner in the right order Apparently calling them in the wrong order makes new GTK+ crash. M src/nemo-window-toolbars.c commit ca6e8b6d59caa79e1095d02f107df1779107a565 Author: Cosimo Cecchi Date: 2010-10-04 Release 2.91.0 M NEWS M configure.in commit 74a0311e65f2c9fc2d03967b0607633dcb652f88 Author: Cosimo Cecchi Date: 2010-10-04 build: fix distcheck M eel/Makefile.am M src/Makefile.am commit 2053c267a79231aeb82a24adfe8f4e7da442cdb7 Author: Cosimo Cecchi Date: 2010-10-04 build: depend on 2.91.0 GTK+ and gnome-desktop M configure.in commit 64819695a13eb636df535e08e0eed6e896a8821c Author: Cosimo Cecchi Date: 2010-10-04 properties-window: split some long lines M src/file-manager/fm-properties-window.c commit 5ece5d67163e30a91e600d2f2bcf0d657d365dc4 Author: Cosimo Cecchi Date: 2010-10-04 properties-window: don't use expose-event to draw the pie chart Use GtkWidget::draw instead M src/file-manager/fm-properties-window.c commit d72087b74c871ef82b1f6a13bb5bb72b38670a52 Author: Cosimo Cecchi Date: 2010-10-04 window-toolbars: show/hide the spinner when changing its state M src/nemo-window-toolbars.c commit 3745195087a21bb46ed42925ff1d877562dbf36e Author: Cosimo Cecchi Date: 2010-09-30 build: bump GTK+ and gnome-desktop required versions M configure.in commit 098057414b38aeeddd3fcd81942324336628d341 Author: Cosimo Cecchi Date: 2010-09-30 icon-dnd: cleanup useless code M libnemo-private/nemo-icon-dnd.c commit f38bad2536faf497fe56c9a491ab852cb00514c0 Author: Cosimo Cecchi Date: 2010-09-30 icon-dnd: use negative device offsets to set the drag surface M libnemo-private/nemo-icon-dnd.c commit a136af0a01c160cdfb513c531b910b49a4a62973 Author: Cosimo Cecchi Date: 2010-09-30 icon-canvas-item: use cairo directly instead of gdk_pixbuf_composite() M libnemo-private/nemo-icon-canvas-item.c commit c6860491c432e311d585a6d92443ef821afd46d2 Author: Cosimo Cecchi Date: 2010-09-30 icon-canvas-item: set transparent background for highlight M libnemo-private/nemo-icon-canvas-item.c commit 426079ef07d5f902911f30b0a9d7de95f3020374 Author: Benjamin Otte Date: 2010-09-29 background: cope with renamings of gnome-bg APIs M eel/eel-background.c commit b1aac113ef867846fb39ee4187378c6f1a13f33e Author: Cosimo Cecchi Date: 2010-09-29 desktop-icon-view: don't use gdk_drawable_get_screen M src/file-manager/fm-desktop-icon-view.c commit 0b664aae4090704fa2e44d42f213da2cea8bd828 Author: Cosimo Cecchi Date: 2010-09-29 background: port to rendering-cleanup Based on patches from Benjamin Otte and Christian Persch. M eel/eel-background.c commit c47d18f566fa9518ca7750922da7da66d3211f3e Author: Cosimo Cecchi Date: 2010-09-29 [src] use gtk_widget_get_preferred_size() M src/nemo-pathbar.c M src/nemo-side-pane.c M src/nemo-spatial-window.c M src/nemo-zoom-control.c commit e56241830bfd2ca470ec2b1da53313c2230bc2b9 Author: Cosimo Cecchi Date: 2010-09-29 icon-container: use gtk_widget_get_preferred_size() M libnemo-private/nemo-icon-container.c commit f5192b6990cd9240d126974dd587b7b7525ae714 Author: Cosimo Cecchi Date: 2010-09-29 [libnemo-private] use eel_canvas_item_destroy Instead of gtk_object_destroy() M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c commit 910191ea13e5647e1b8c793e7585530c6ae4c9b1 Author: Christian Persch Date: 2010-09-16 [libnemo-private] Port to rendering-cleanup-next M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-canvas-item.h M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-tree-view-drag-dest.c commit 44171abea01a0c110aa029dddfb5d5afe018d086 Author: Christian Persch Date: 2010-09-16 [libnemo-private] Use gtk_widget_get_preferred_size() ... instead of the deprecated gtk_widget_get_child_requisition(). M libnemo-private/nemo-horizontal-splitter.c commit 2b7659ac4fcaa8b93ad8f409e1560aaa60dcdc12 Author: Christian Persch Date: 2010-09-16 [eel] Port EelEditableLabel to rendering-cleanup-next M eel/eel-editable-label.c commit 4963a3c9e5526ffd139b1b0b5bff18b6ea91a717 Author: Cosimo Cecchi Date: 2010-09-29 editable-label: use gtk_widget_get_preferred_size() M eel/eel-editable-label.c commit 58832e54b6a4e596693527d577e4f8fa2f3e4ccf Author: Christian Persch Date: 2010-09-16 [eel] Port the eel canvas to rendering-cleanup-next M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas.c M eel/eel-canvas.h commit d2f141f4a5435b10b43abea0822e3d0569b67886 Author: Christian Persch Date: 2010-09-16 [eel] Add eel_cairo_draw_layout_with_drop_shadow Renamed from eel_gdk_draw_layout_with_drop_shadow. M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 93e1cdfd387c47f73e51eeff924f8e2c9fad2bda Author: Cosimo Cecchi Date: 2010-09-29 undo-transaction: remove obsolete commented code M libnemo-private/nemo-undo-transaction.c M src/nemo-bookmarks-window.c commit f616fee30fb153c9f71d79b2568d2e0e5a23fd39 Author: Cosimo Cecchi Date: 2010-09-29 undo-signal-handlers: remove commented out obsolete code M libnemo-private/nemo-undo-signal-handlers.c M libnemo-private/nemo-undo-signal-handlers.h commit c5eba3314c99059aa1fff13aedcb1004966fdd55 Author: Cosimo Cecchi Date: 2010-09-29 icon-dnd: remove commented out obsolete code M libnemo-private/nemo-icon-dnd.c commit cc6cb51e827c0b15d4ef09f12d37b9f331ddcef8 Author: Cosimo Cecchi Date: 2010-09-29 [src] don't use GtkObject M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-properties-window.c M src/nemo-application.c M src/nemo-bookmarks-window.c M src/nemo-location-bar.c M src/nemo-location-dialog.c M src/nemo-location-entry.c M src/nemo-main.c M src/nemo-main.h M src/nemo-navigation-bar.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-pathbar.c M src/nemo-window-bookmarks.c M src/nemo-window-manage-views.c M src/nemo-window.c commit aef4cfcf93ef34a0b2d4c87b40fcec2b7a66dd06 Author: Cosimo Cecchi Date: 2010-09-29 [libnemo-private] don't use GtkObject M libnemo-private/nemo-autorun.c M libnemo-private/nemo-clipboard.c M libnemo-private/nemo-entry.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-mime-application-chooser.c M libnemo-private/nemo-open-with-dialog.c M libnemo-private/nemo-program-choosing.c M libnemo-private/nemo-undo-transaction.c commit b5f9acb9029c015558ab678e01fc2c8dcc8c6c82 Author: Cosimo Cecchi Date: 2010-09-29 editable-label: don't use GtkObject M eel/eel-editable-label.c commit 1f615321613751a5dbc84d5ef7f20edd104b8dc4 Author: Cosimo Cecchi Date: 2010-09-29 canvas: don't use GtkObject This implies adding a 'destroy' signal to EelCanvasItem, with similar semantics to gtk_object_destroy() M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas.c M eel/eel-canvas.h commit 5edcd42e503623c11bf55c6afba437b3013c7f45 Author: Cosimo Cecchi Date: 2010-09-29 stock-dialogs: don't use GtkObject M eel/eel-stock-dialogs.c commit 510d5fba10058535b8d8a3bb05f564122b798abd Author: Cosimo Cecchi Date: 2010-09-30 window-menus: fix a typo in the about dialog (#630624). M src/nemo-window-menus.c commit 2e59a60800a9bc837af9132b0ac234d9d14668c6 Author: Cosimo Cecchi Date: 2010-09-29 background: remove leftover GtkObject M eel/eel-background.h commit 87eb53a0701252607b494f34c677b6506f82278c Author: Cosimo Cecchi Date: 2010-09-29 background: cleanup unused code M eel/eel-background.c M eel/eel-background.h commit fbb6b024128e3c35aeb1d74f8e287e8870c9999f Author: Cosimo Cecchi Date: 2010-09-29 directory-background: don't user the 'destroy' signal of EelBackground M libnemo-private/nemo-directory-background.c commit 60044f8ef457036560fb94ad6b20cdf7bedb4f77 Author: Cosimo Cecchi Date: 2010-09-29 background: don't use GtkObject M eel/eel-background.c commit ab1229476f949fef5cd51545088c91c649be2ef1 Author: Cosimo Cecchi Date: 2010-09-28 icon-dnd: don't set 'Set as Background' sensitive outside the desktop M libnemo-private/nemo-icon-dnd.c commit 895830af57277c7fd542f3fd21f71c4cde1ea231 Author: Cosimo Cecchi Date: 2010-09-28 dnd: remove support for property/bgimage as DND type. That was used for tiled backgrounds in the 'Backgrounds and Emblems' dialog. M libnemo-private/nemo-dnd.c M libnemo-private/nemo-dnd.h M libnemo-private/nemo-file-dnd.c M libnemo-private/nemo-icon-dnd.c commit c9be35b3ee6c468a9a102b317b82b8b639637d0f Author: Cosimo Cecchi Date: 2010-09-28 directory-background: remove code for setting non-desktop window backgrounds Remove all the code that sets non-desktop window backgrounds, as we don't do that anymore. This includes avoid listening to metadata and GSettings changes. M libnemo-private/nemo-directory-background.c M libnemo-private/nemo-directory-background.h commit ab0616de55f6f817a745caac26fd2b38ae41b71b Author: Cosimo Cecchi Date: 2010-09-28 icon-view: move background setting code to FMDesktopIconView So that we avoid setting backgrounds on regular nemo windows. M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-view.c commit ecc583092aa333081205470c7cca7fb1aa68cb81 Author: Petr Kovar Date: 2010-09-29 Update Czech translation by Marek Cernocky M po/cs.po commit d2a41707084726ebdf882c8c6ec82ef46e29dcb0 Author: Damyan Ivanov Date: 2010-09-27 Updated Bulgarian translation M po/bg.po commit c0b28726fc05c7eac004ebaf4f81bb5e753285aa Author: Joan Duran Date: 2010-09-26 Updated Catalan translation M po/ca.po commit 1839f9abf3fa7ce88574649d531c88c9e3ac4bf7 Author: Mattias Põldaru Date: 2010-09-24 [l10n] Updated Estonian translation M po/et.po commit 74630527a03b3492913d0611b221ebdc5e1e76ba Author: Takayuki KUSANO Date: 2010-09-24 Updated Japanese translation M po/ja.po commit be665613c0e9233042e6e1f97b8cdb8708fdd782 Author: Khaled Hosny Date: 2010-09-23 Updated Arabic translation M po/ar.po commit f3bbee79b915276068e0a0d6ed9590c212e11a0a Author: Cosimo Cecchi Date: 2010-09-20 connect-dialog: add a missing gtk_widget_show() M src/nemo-connect-server-dialog.c commit 24100d075f747e8fc9ca3cc43a32489177f35459 Author: Cosimo Cecchi Date: 2010-09-20 connect-dialog: make the code more readable Move bits around and rename methods; no actual code change. M src/nemo-connect-server-dialog.c commit 1b79a8666fee56cdb704e8757f28acf486f7dc54 Author: Cosimo Cecchi Date: 2010-09-20 connect-dialog: display a fatal error if GVfs doesn't have methods I.e. when GVfs is not installed. M src/nemo-connect-server-dialog.c commit 1c826ed78bde5f34fd4a0f72d788b8d0824d6099 Author: Cosimo Cecchi Date: 2010-09-11 connect-dialog: fixes for the handling of iconized entries M src/nemo-connect-server-dialog.c commit 7d004452f333b7b8b804d87de49c858e8743a115 Author: Cosimo Cecchi Date: 2010-09-01 connect-dialog: integrate password handling Also, use the info bar to display warnings/errors, and tweak the UI details. M src/nemo-connect-server-dialog-main.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-connect-server-dialog.c M src/nemo-connect-server-dialog.h commit c1bebe3a29bc2dc3b01ad2277a9802d9d0bc25cd Author: Cosimo Cecchi Date: 2010-08-31 connect-operation: add NemoConnectServerOperation This is a GtkMountOperation subclass to handle password/username/domain requests directly from inside of the 'Connect to Server' dialog. M src/Makefile.am A src/nemo-connect-server-operation.c A src/nemo-connect-server-operation.h commit 156615f8d9f8b99dea3459cdd76392d01b9d80df Author: Cosimo Cecchi Date: 2010-09-20 window-menus: use new connect dialog API M src/nemo-window-menus.c commit 7848e74d812c22299962a8ae22b01dbd403929c0 Author: Cosimo Cecchi Date: 2010-09-20 connect-dialog: redesign the dialog According to Allan Day's mockups. M src/nemo-connect-server-dialog-main.c M src/nemo-connect-server-dialog.c M src/nemo-connect-server-dialog.h commit d5350003ac927bd683d4e18f7c0513b94f9220d7 Author: Cosimo Cecchi Date: 2010-08-31 navigation-window-menus: use new NemoApplication API M src/nemo-navigation-window-menus.c commit a3ce22ec6e8fcb39dafb35e04e445f4a94b8c394 Author: Cosimo Cecchi Date: 2010-08-31 bk-window: use new NemoApplication API M src/nemo-bookmarks-window.c commit adedf859ec47296106f0f0d938e70b32f0120f7c Author: Cosimo Cecchi Date: 2010-08-31 window: call the callback during the location change M src/nemo-window-manage-views.c M src/nemo-window-slot.h commit d070d631545aac9114bc271481da603587c07c7c Author: Cosimo Cecchi Date: 2010-08-31 application: change the way spatial windows are created Use a _get() function + the standard nemo_window_go_to() instead of using _present(). The new functions in nemo-window-manage-views are smart enough to take care of re-using an existent window. M src/nemo-application.c M src/nemo-application.h commit 1936e668c73b932f8cb018e278f8b7f46442fda2 Author: Cosimo Cecchi Date: 2010-08-31 spatial-window: remove affect_location_on_next_change hack M src/nemo-spatial-window.c M src/nemo-spatial-window.h commit f95927360079b1c05efb9cea0de62457eea307ab Author: Cosimo Cecchi Date: 2010-08-31 desktop-window: add a 'loaded' flag M src/nemo-desktop-window.c M src/nemo-desktop-window.h commit 54e0a1f21513babc89f980b5b02af2bf7a6ebe85 Author: Cosimo Cecchi Date: 2010-08-31 window: rewrite window-opening policies The code there was very hackish and convoluted. Rewrite it to make it at least cleaner. This will allow further cleanup later. M src/nemo-window-manage-views.c commit 24515b87a91afd32885e07e32e2b4080584673a4 Author: Cosimo Cecchi Date: 2010-08-31 window: add _full() versions of _go_to and _open() methods These also have a callback to get the result of the operation. M libnemo-private/nemo-window-info.h M libnemo-private/nemo-window-slot-info.c M libnemo-private/nemo-window-slot-info.h M src/nemo-window-manage-views.c M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 42cc7bd181d2f57dbc008bea54a40f02be40ce39 Author: Cosimo Cecchi Date: 2010-08-31 window-info: move include to nemo-window-private M libnemo-private/nemo-window-info.h M src/nemo-window-private.h commit 8d07a73b28767b7c866fe403e9ac706b8affb8a2 Author: Cosimo Cecchi Date: 2010-09-01 build: don't include marshals we don't own M libnemo-private/nemo-directory.c M libnemo-private/nemo-icon-container.c M src/file-manager/fm-directory-view.c M src/nemo-pathbar.c M src/nemo-window.c M src/nemo-zoom-control.c commit 6d3398968d9f2520a4b6f4a08e0f4ae65e2207ab Author: Cosimo Cecchi Date: 2010-09-20 list-view: check for model != NULL before unsetting the highlight The model could be NULL there as a result of the view being previously disposed. M src/file-manager/fm-list-view.c commit 7723f508ca8c9bd837a531cb018de16d627f8bd9 Author: Cosimo Cecchi Date: 2010-09-20 Revert "Clear the list model in _finalize() instead of _dispose()" This reverts commit bfe278cbf84a441a951d48dc528f20226127e1f3. M src/file-manager/fm-list-view.c commit 2e32fc01537bb2c86d9d9bbb6cc5ab2713bd723e Author: Timo Jyrinki Date: 2010-09-20 Updated Finnish translation. M po/fi.po commit 8deeb8471034b90b83ecb0e4bde0cf852e275d24 Author: Cosimo Cecchi Date: 2010-09-19 build: require GLib 2.27.0 Due to GApplication, which has been removed from 2.25.x M configure.in commit a4f454825861c1fb65e8d52979a67a81c5133974 Author: Cosimo Cecchi Date: 2010-09-19 desktop-icon-view: initialize allocation before setting it This probably fixes a number of stack-corruption crashes on 2.31.x M src/file-manager/fm-desktop-icon-view.c commit 00df45be2c133f849267f1ae485d95f672744690 Author: Cosimo Cecchi Date: 2010-09-19 build: require GTK+ 2.90.7 for GDK_KEY names M configure.in commit 78e37ae9a18925d75cf90424d92c8d3ba502848a Author: Cosimo Cecchi Date: 2010-09-19 [ui] remove 'has_separator' properties from Glade files M src/nemo-bookmarks-window.ui M src/nemo-file-management-properties.ui commit 71fa1a50145a6f06da3b805a29e75c1295fd546b Author: Cosimo Cecchi Date: 2010-09-19 [src] convert to new GDK_KEY prefix M src/file-manager/fm-directory-view.c M src/file-manager/fm-list-view.c M src/file-manager/fm-properties-window.c M src/nemo-bookmarks-window.c M src/nemo-location-entry.c M src/nemo-navigation-bar.c M src/nemo-places-sidebar.c M src/nemo-query-editor.c M src/nemo-search-bar.c M src/nemo-side-pane.c M src/nemo-spatial-window.c M src/nemo-window.c M src/nemo-zoom-control.c commit 8ee5d37f2b4776730247af75a6ce4cebcba4c550 Author: Cosimo Cecchi Date: 2010-09-19 thumbnails: don't use GDK_THREADS_* macros M libnemo-private/nemo-thumbnails.c commit 8dd87483bd187bfac80a606233b769c230343980 Author: Cosimo Cecchi Date: 2010-09-19 autorun: use gdk_error_trap_pop_ignored() M libnemo-private/nemo-autorun.c commit aeb53075ed55dc2a2ef3228917ded1b8029bfdff Author: Cosimo Cecchi Date: 2010-09-19 entry: rename GtkEditableClass->GtkEditableInterface M libnemo-private/nemo-entry.c commit 64dcbea2a005e4ed8bb4945d06a943058b8c7ba8 Author: Cosimo Cecchi Date: 2010-09-19 [ln-p] convert to new GDK_KEY prefix M libnemo-private/nemo-autorun.c M libnemo-private/nemo-entry.c M libnemo-private/nemo-icon-container.c commit 499c54a20b64051e427ff5746fc7c8dd1a1885c2 Author: Cosimo Cecchi Date: 2010-09-19 [eel] convert to new GDK_KEY prefix M eel/eel-editable-label.c commit a58bbde4ca6b11eeb1bca5fa4e62e60c0b26271b Author: Cosimo Cecchi Date: 2010-09-19 editable-label: rename GtkEditableClass->GtkEditableInterface M eel/eel-editable-label.c commit 73e2941f9b837d5d0326e6e88caa7a1e3fdcabeb Author: Cosimo Cecchi Date: 2010-09-19 Don't use gtk_dialog_set_has_separator() M libnemo-private/nemo-autorun.c M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-open-with-dialog.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-properties-window.c M src/nemo-connect-server-dialog.c M src/nemo-location-dialog.c M src/nemo-query-editor.c commit b66ce0fd23500f9727c1aac93366430285575697 Author: Cosimo Cecchi Date: 2010-09-19 Don't use GDK_DISPLAY () M libnemo-private/nemo-autorun.c M src/file-manager/fm-desktop-icon-view.c commit 36836b7dc517a588b34117e05a45bc4026e77f71 Author: Cosimo Cecchi Date: 2010-09-19 Use gtk_size_request_get_size() M eel/eel-editable-label.c M libnemo-private/nemo-horizontal-splitter.c M libnemo-private/nemo-icon-container.c M src/nemo-pathbar.c M src/nemo-side-pane.c M src/nemo-spatial-window.c M src/nemo-zoom-control.c commit 93022eda89f650a82f8a17e332973ab88b2318a8 Author: Žygimantas BeruÄka Date: 2010-09-18 Updated Lithuanian translation M po/lt.po commit cfada2b36dd274b2d2835753fc87c69affbbba58 Author: Cosimo Cecchi Date: 2010-09-17 pathbar: use another way to remove buttons (#627901) This fixes a crasher in _size_allocate() where the list of buttons did not contain valid data anymore. M src/nemo-pathbar.c commit 476d45bfd1dd71595e7d38f4d18c761fe2a85b78 Author: Cosimo Cecchi Date: 2010-09-17 Don't check for the eject button if the row doesn't have it (#628347) This sometimes caused false positives in the click-on-eject-button detection method. M src/nemo-places-sidebar.c commit bfe278cbf84a441a951d48dc528f20226127e1f3 Author: Cosimo Cecchi Date: 2010-09-17 Clear the list model in _finalize() instead of _dispose() We have the only reference to the model anyway. This fixes a crash when _end_loading() is called for a windiow before it finished loading. M src/file-manager/fm-list-view.c commit 46544c9885b7064c216f1a9401d42bdb9816bdd2 Author: Cosimo Cecchi Date: 2010-09-17 preferences: use right link for the 'Media' help page (#564866). M src/nemo-file-management-properties.c commit 31ebe40c4a68db4a1fc57e1c942b2d94efce5a42 Author: Kenneth Nielsen Date: 2010-09-16 Updated Danish translation M po/da.po commit f9a85779d9ac73f280358bd96417ea69f2694361 Author: Ivar Smolin Date: 2010-09-14 [l10n] Updated Estonian translation M po/et.po commit 72a4af08ca5139d5ad6511667dbe5631e5962ae7 Author: Ivar Smolin Date: 2010-09-13 [l10n] Updated Estonian translation M po/et.po commit 2c5a174abaeb3ce79bde382617289e358a59b102 Author: Takayuki KUSANO Date: 2010-09-13 Updated Japanese translation. M po/ja.po commit a3213bb051bb1843e7a0c1a2d47d865219b47dcd Author: Luca Ferretti Date: 2010-09-12 Updated Italian translation M po/it.po commit 802146d70642abf27a4f7dde398f775545da3794 Author: Duarte Loreto Date: 2010-09-12 Updated Portuguese translation M po/pt.po commit 4dd8de5b24c7c9774b62207cbc067b715af6942d Author: Mario Blättermann Date: 2010-09-12 [i18n] Updated German translation M po/de.po commit 8962e6db60a335e72046e2444d9c02e7d3e1182f Author: Wouter Bolsterlee Date: 2010-09-12 Updated Dutch translation by Wouter Bolsterlee M po/nl.po commit 60af1701491afbf686d1610ef7aad253f2904432 Author: Wouter Bolsterlee Date: 2010-09-12 Updated Dutch translation by Hannie Dumoleyn M po/nl.po commit f9ccf920434ba6795e4e62f3c95f927532f023c6 Author: Christian Kirbach Date: 2010-09-12 [i18n] Updated German translation M po/de.po commit e20fd8287c710dd5fcd15ed6a46efe3e5dea1b8a Author: Bruce Cowan Date: 2010-09-11 Updated British English translation M po/en_GB.po commit 1dc64c6c1ebba6a5434be80babc78e40c9dacdd7 Author: Fran Diéguez Date: 2010-09-11 Updated Galician translations M po/gl.po commit d37b72c14326182e51e797fc3af5ab9d5f310fb8 Author: Ask H. Larsen Date: 2010-09-11 Updated Danish translation M po/da.po commit adba30e6655ddf85edb179fff6626aec43520894 Author: Cosimo Cecchi Date: 2010-09-11 list-view: properly setup the editable widget (#627076) M src/file-manager/fm-list-view.c commit 265e669b9380eb11ef8ac928cce597d05dd70c7b Author: Cosimo Cecchi Date: 2010-09-10 Make file conflict strings i18n-friendly Thanks to Wouter Bolsterlee for the initial patch. M libnemo-private/nemo-file-conflict-dialog.c commit af61c416ffc291032bb2e199a03b7b071f0a77eb Author: Jorge González Date: 2010-09-09 Updated Spanish translation M po/es.po commit 2cab30a8acdca5d63937d129bdff12118a8b5cb3 Author: Jorge González Date: 2010-09-09 Updated Spanish translation M po/es.po commit fa28706c9878e0123fa4ce5576d4e4f37a91f23a Author: Takayuki KUSANO Date: 2010-09-10 Updated Japanese translation. M po/ja.po commit 94275d4a786eba1dd51d020912fa74d9b19d91ad Author: Piotr DrÄ…g Date: 2010-09-07 Updated Polish translation M po/pl.po commit 51f313e623c282d4540728e0adedbb7b0e6a21ec Author: Daniel Nylander Date: 2010-09-05 Updated Swedish translation M po/sv.po commit e3519b6a8a22d9d9b6e7b421ec5ead1654f456db Author: Matej UrbanÄiÄ Date: 2010-09-04 Updated Slovenian translation M po/sl.po commit 459216c23d064f7e2f194251a787f8f6365c29e2 Author: drtv Date: 2010-09-03 Updated Tamil translation M po/ta.po commit 9d98055c4547b0e2e7cb8920d5d1436178277a16 Author: drtv Date: 2010-09-03 Updated Tamil translation M po/ta.po commit 5a74a9e3ebab733a25afb7f73940757c698ed850 Author: Wouter Bolsterlee Date: 2010-09-02 Fix small error in Dutch translation M po/nl.po commit 430980aca7f1231df970c980e03847c02485ed34 Author: Michael Kotsarinis Date: 2010-08-31 l10n: Updated Greek translation M po/el.po commit 4f579bcdf37b188853ec1076954680bc91e175f6 Author: Bruce Cowan Date: 2010-08-31 Updated British English translation M po/en_GB.po commit 1989b4be7d56d120c8fc57e40cba6155dcbae905 Author: Mattias Põldaru Date: 2010-08-31 [l10n] Updated Estonian translation M po/et.po commit d0086feb65c640926066dcc9d263153227e1a3c1 Author: Gabor Kelemen Date: 2010-08-30 Updated Hungarian translation M po/hu.po commit da6cdb1d2e2ddea2b46a78a4ea57f496bca6a995 Author: Gabor Kelemen Date: 2010-08-29 Updated Hungarian translation M po/hu.po commit 67c01533ab809e751ec2ceb3a81fd50c9c85ef2b Author: Ivar Smolin Date: 2010-08-29 [l10n] Updated Estonian translation M po/et.po commit ff83456b73cd2f6340fd0da57788f3c7c48b455b Author: Dirgita Date: 2010-08-29 Updated Indonesian translation M po/id.po commit e3c8b309386f4040b4c8853d78b8709e12fb4de8 Author: Mattias Põldaru Date: 2010-08-27 [l10n] Updated Estonian translation M po/et.po commit e6feba5047dc17decbda673d8df2de0dbb089140 Author: Bruno Brouard Date: 2010-08-26 Updated French translation M po/fr.po commit f233f2aeb78e5fd14c0b18f7a3c5e80b5e7c84c5 Author: Cosimo Cecchi Date: 2010-08-26 connect-dialog: don't use EEL boilerplate M src/nemo-connect-server-dialog.c commit 0f70ac4bb782b3c3fb0f5e8a24032cb344fdb2cc Author: Cosimo Cecchi Date: 2010-08-26 sidebar: don't try to add non-existing special dirs M src/nemo-places-sidebar.c commit 8277ddc798fc78793364b54444fa53e9a287b5cc Author: Cosimo Cecchi Date: 2010-08-26 sidebar: don't allow selecting headers M src/nemo-places-sidebar.c commit 0f7e56b5e0ae5134ed1d8caeadcb3c684ae7f661 Author: Cosimo Cecchi Date: 2010-08-26 sidebar: add myself to the authors M src/nemo-places-sidebar.c commit 1fdfa522da3e7c672fe4202c591a928c8796bb06 Author: Cosimo Cecchi Date: 2010-08-26 sidebar: fix bookmark renaming Regression of the new sidebar. M src/nemo-places-sidebar.c commit 2f847f37f429062d58df3927d10bc52c67a4524f Author: Cosimo Cecchi Date: 2010-08-26 icon-names: fix a typo M libnemo-private/nemo-icon-names.h commit 0dc6f5ddf472ba2033cdee0ba41cf78696e4017f Merge: ce419d9 a59e586 Author: Cosimo Cecchi Date: 2010-08-25 Merge branch 'sidebar_revamp' commit a59e586adf32eea64c9c4ae08a5482d2a9c37fb1 Author: Cosimo Cecchi Date: 2010-08-25 sidebar: redesign the Places sidebar According to http://live.gnome.org/Nemo/UIRoadmap/Places M src/nemo-places-sidebar.c commit 2d9d47254908533d1eb20e16e091f91310052e93 Author: Cosimo Cecchi Date: 2010-08-25 sidebar: fix eject button highlighting M src/nemo-places-sidebar.c commit 1df83c6586560a8ae5efc96037e673e52b4b119b Author: Cosimo Cecchi Date: 2010-08-25 icon-info: add a method to fetch GIcons for user special dirs M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-icon-info.h M libnemo-private/nemo-icon-names.h commit ce419d9bc7536af2e5e4f0c6122b79070cadddca Author: Aurimas ÄŒernius Date: 2010-08-23 Updated Lithuanian translation M po/lt.po commit 1346a15744ce3aa7f8f52aade250d6a303b33bf2 Author: Aron Xu Date: 2010-08-23 Update Simplified Chinese translation. M po/zh_CN.po commit fd75e8f5e8b160eaba22ca4ed7efc852dba612a0 Author: Cosimo Cecchi Date: 2010-08-22 pathbar: release the highlight path on dispose M src/nemo-places-sidebar.c commit 6f5777b81958ce6f3dbc6bac3323d423d3dcc20b Author: Cosimo Cecchi Date: 2010-08-22 sidebar: don't update the icon if it's not visible This greatly reduces the number of times we have to create a pixbuf (only once-per-highlight now). M src/nemo-places-sidebar.c commit a43bc7def3976947b9624113d18167211e76f9b8 Author: Cosimo Cecchi Date: 2010-08-22 pathbar: make sure |path| is always valid and memory released M src/nemo-places-sidebar.c commit f4ae07c8741d2e8cc6b96450c8bb86e532b59137 Author: Cosimo Cecchi Date: 2010-08-22 sidebar: use _icon_info_lookup_from_name () M src/nemo-places-sidebar.c commit 63b2cac301970847f76f7bdbd12835117958d9be Author: Marcus Carlson Date: 2010-08-06 Add highlight to eject icon in places sidebar (#544103) M src/nemo-places-sidebar.c commit 3abe144501fcff60a65ebd621a51b45ffa5d113d Author: Cosimo Cecchi Date: 2010-08-22 Release 2.90.1 M NEWS M po/POTFILES.in commit 1f64e4b0dd9729976a16d2cf14a6b7c6691ded1e Author: Cosimo Cecchi Date: 2010-08-21 [ln-p] remove unused NemoKeepLastVerticalBox M libnemo-private/Makefile.am D libnemo-private/nemo-keep-last-vertical-box.c D libnemo-private/nemo-keep-last-vertical-box.h commit ad5e896e1ce04485a115ee684a695b42ea0378a5 Author: Cosimo Cecchi Date: 2010-08-21 [eel] reorganize Makefile.am M eel/Makefile.am commit 7e8d1dfa6a17fe9189bf2489b735cd6462f03571 Author: Cosimo Cecchi Date: 2010-08-21 [eel] remove eel_gdk_window_focus M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 6b06e0e27ca1cf29afd4fac716c58e15928a8ff8 Author: Cosimo Cecchi Date: 2010-08-21 icon-container: use gdk_window_focus M libnemo-private/nemo-icon-container.c commit fe94a33657d55a2463fa066e09a8ecbfc637c4bd Author: Cosimo Cecchi Date: 2010-08-21 [eel] remove EelAlertDialog This is unused now. M eel/Makefile.am D eel/eel-alert-dialog.c D eel/eel-alert-dialog.h commit 82c5b6c0d82ebd8a705d542fcc9aa58e6e9b0da4 Author: Cosimo Cecchi Date: 2010-08-21 [eel] use GtkMessageDialog for stock dialogs Instead of EelAlertDialog, which is going away. M eel/eel-stock-dialogs.c commit 930af7f3058eed256a42c0c1558c7307bb93f411 Author: Cosimo Cecchi Date: 2010-08-21 tree-view: don't include eel-alert-dialog.h M src/file-manager/fm-tree-view.c commit 7a3dcdd4bf667aac271be74988770e18575a7df2 Author: Cosimo Cecchi Date: 2010-08-21 mime-actions: use GtkMessageDialog Instead of EelAlertDialog, which is going away. M libnemo-private/nemo-mime-actions.c commit 51ec5861ca0697e802e8c003053211ac12f2fd54 Author: Cosimo Cecchi Date: 2010-08-21 file-operations: use GtkMessageDialog Instead of EelAlertDialog, which is going away. M libnemo-private/nemo-file-operations.c commit a2b4de80a94b4e049f1d2a7ef00a174865b5c9ec Author: Cosimo Cecchi Date: 2010-08-21 [eel] add an utility to pack details into a message dialog So that we can remove EelAlertDialog. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 394cb741c3e59df66f924771d4ef68866e602faa Author: Cosimo Cecchi Date: 2010-08-21 [eel] remove eel_gtk_signal* utilities These are unused now. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 57b66862a53298468755e12ca3712569274f0a32 Author: Cosimo Cecchi Date: 2010-08-21 [eel] remove functions to set widget backgrounds These are unused now. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 472f3e1433ecb3d5e1a7fc8707975f45dd8d0469 Author: Cosimo Cecchi Date: 2010-08-21 [eel] remove functions to handle accelerators These are unused now. M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit cab696f7d760f5ee63f0a623b13d27b76d2f2d00 Author: Cosimo Cecchi Date: 2010-08-21 bk-window: don't use _event_is_close_accelerator() M src/nemo-bookmarks-window.c commit f4432dfba1e8f545d3aeeed5989bd30bba52d160 Author: Cosimo Cecchi Date: 2010-08-21 slot: cleanup previous commit There was an unused variable left M src/nemo-window-slot.c M src/nemo-window-slot.h commit 712cf85b9c44fc93b8f506bfb03ea06cb58eb5e6 Author: Cosimo Cecchi Date: 2010-08-21 Add a border around info bars (#621366). M src/file-manager/fm-directory-view.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit 93798c75a1ae3cbd3a85a4ce79b5521b562a7074 Author: Cosimo Cecchi Date: 2010-08-21 spatial-window: cleanups - Don't do anything else than checking/scheduling a source in the conifigure-event callback - Avoid useless roundtrips through GFile - Avoid some casts, so we don't do useless type-checking in a row on the same object M src/nemo-spatial-window.c commit 5973bc50618d1fe69247e3e2ec6eb8cf3213000b Author: Cosimo Cecchi Date: 2010-08-21 window: remove dead prototypes M src/nemo-window-private.h M src/nemo-window.h commit ef13366e667f848adc6b96509612e3321554d188 Author: Cosimo Cecchi Date: 2010-08-21 desktop-window: cleanups M src/nemo-desktop-window.c commit eb88f44bd27e11607cb5466c943b9caad0202110 Author: Cosimo Cecchi Date: 2010-08-21 window: remove dead function M src/nemo-window.c M src/nemo-window.h commit cf152f9ec75714af2b14be2750f9ea84daab361a Author: Cosimo Cecchi Date: 2010-08-21 undo-manager: remove dead code M libnemo-private/nemo-undo-manager.c M libnemo-private/nemo-undo-manager.h commit 90eb723490ab0338d3d2f1acd02ae5af5fdea819 Author: Cosimo Cecchi Date: 2010-08-20 about: add some authors and update year M src/nemo-window-menus.c commit 21e75511d2466bd814a31031472323d3cd8ae6c1 Author: Cosimo Cecchi Date: 2010-08-20 [file-manager] autogenerate marshallers M src/file-manager/Makefile.am M src/file-manager/fm-directory-view.c commit 608918449f548b0d3ea3e7916c944b077ac43e87 Author: Cosimo Cecchi Date: 2010-08-20 [src] autogenerate marshallers M src/Makefile.am M src/nemo-query-editor.c M src/nemo-window.c commit 6509c91b48f52c72c868f2ca7a9b47c46b9e0bc6 Author: Cosimo Cecchi Date: 2010-08-20 [ln-p] autogenerate marshallers M libnemo-private/Makefile.am M libnemo-private/nemo-icon-container.c D libnemo-private/nemo-marshal.c D libnemo-private/nemo-marshal.list commit 75a03a440ebff23ccbf8674ca4a0e9f6475ebbb8 Author: Cosimo Cecchi Date: 2010-08-20 [eel] simplify build system We don't need the enumtypes anymore, and the marshallers can easily be autogenerated. M eel/Makefile.am M eel/eel-background.c D eel/eel-types.c D eel/eel-types.h M eel/eel.h D eel/eelmarshal.list D eel/makeenums.pl D eel/maketypes.awk D eel/update-from-egg.sh commit 52a37d6e46fc34cef6061bc91aa02847652f3c9d Author: Cosimo Cecchi Date: 2010-08-20 [ln-p] remove unused nemo-iso9660.h M libnemo-private/Makefile.am D libnemo-private/nemo-iso9660.h commit 1d660252b408f3628a2d3d5943abcf6bfdd9091b Author: Cosimo Cecchi Date: 2010-08-20 tree-model: only display the first emblem Only display the first emblem we can render. M src/file-manager/fm-tree-model.c commit 5c08250adf30f2e24b4455fd3c08e81dc3ff4987 Author: Cosimo Cecchi Date: 2010-08-20 list-model: display only the first emblem Only display the first emblem we can render. M src/file-manager/fm-list-model.c commit 110a0e8f2b9ec96b34e4b76390e3f78adc9cda30 Author: Cosimo Cecchi Date: 2010-08-20 icon-info: add nemo_icon_theme_can_render() M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-icon-info.h commit 25b48e9d1f4c847e2fc95b9b9893e63ba7081658 Author: Cosimo Cecchi Date: 2010-08-19 [ln-p] remove NemoCellRendererPixbufEmblem It's useless now. M libnemo-private/Makefile.am D libnemo-private/nemo-cell-renderer-pixbuf-emblem.c D libnemo-private/nemo-cell-renderer-pixbuf-emblem.h commit d2cbf993766d7b63f50431ab483035d01c267cdb Author: Cosimo Cecchi Date: 2010-08-19 tree-view: don't use NemoCellRendererPixbufEmblem M src/file-manager/fm-tree-view.c commit 1694d7141bbe4a29e54cff77def697a6c9b4e118 Author: Cosimo Cecchi Date: 2010-08-19 tree-model: use GEmblemedIcon Use GEmblemedIcon instead of a separate column to render emblems. M src/file-manager/fm-tree-model.c M src/file-manager/fm-tree-model.h commit 69740a3c7fd3a2e1cea99c0dc61b3c735993e4bb Author: Cosimo Cecchi Date: 2010-08-19 list-view: don't use NemoCellRendererPixbufEmblem M src/file-manager/fm-list-view.c commit a187f8a4cdcc46f56c0cb03c31b9b7c92c747a88 Author: Cosimo Cecchi Date: 2010-08-19 list-model: use GEmblemedIcon Use GEmblemedIcon instead of other columns to render emblems. M src/file-manager/fm-list-model.c M src/file-manager/fm-list-model.h commit e42ddad5109f193bf8a5b3c0c6cd7cf4b1408300 Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove eel-pango-extensions M eel/Makefile.am M eel/eel-lib-self-check-functions.h D eel/eel-pango-extensions.c D eel/eel-pango-extensions.h M eel/eel.h commit f080b86daeb571def4c092e1524e9adfc7700699 Author: Cosimo Cecchi Date: 2010-08-19 Don't include eel-pango-extensions.h M eel/eel-gtk-extensions.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-icon-canvas-item.c commit 931644a649175b1886dce5cc8e50c21380f8b8b0 Author: Cosimo Cecchi Date: 2010-08-19 [test] remove test-eel-image-scrolled It only increases compilation time M test/Makefile.am D test/test-eel-image-scrolled.c commit 2f202206fee4e1917494e3f4652e22648097c765 Author: Cosimo Cecchi Date: 2010-08-19 [eel] cleanup eel-vfs-extensions M eel/eel-vfs-extensions.c M eel/eel-vfs-extensions.h commit 230581b5d58650c1f50f7d9fda9ab3a1f211361a Author: Cosimo Cecchi Date: 2010-08-19 [eel] cleanup eel-glib-extensions M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit fbccd9bfaa9c983dccc60d040b63b86521306788 Author: Cosimo Cecchi Date: 2010-08-19 [eel] cleanup eel-gnome-extensions M eel/eel-gnome-extensions.c M eel/eel-gnome-extensions.h commit 48c6012e89fb1362e418d4bf56c05614f1515eab Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove unused eel_make_semitransparent() M eel/eel-graphic-effects.c M eel/eel-graphic-effects.h commit 9c9c619ae2d4e9dbdc9be175679abad3a174ca32 Author: Cosimo Cecchi Date: 2010-08-19 [test] remove eel-pixbuf-scale test M test/Makefile.am D test/test-eel-pixbuf-scale.c commit 7ed8e2d7b90489f41ad674aa4758728dce62fa77 Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove unused code from eel-gdk-pixbuf-extensions M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h M eel/eel-lib-self-check-functions.h commit 6b2a053985b8c37aa1038e7a01ab05d7dd15aa2e Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove unused code from eel-gdk-extensions M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit d2fb7d661a639633473c9339ea2004f18ad3fcf2 Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove eel-art-gtk-extensions M eel/Makefile.am D eel/eel-art-gtk-extensions.c D eel/eel-art-gtk-extensions.h M eel/eel.h commit 2bfd4e3694e2f726592bae5341d7e4c7464ec415 Author: Cosimo Cecchi Date: 2010-08-19 [eel] don't include eel-art-gtk-extensions.h M eel/eel-gdk-pixbuf-extensions.c commit 940dddbb6ce26138a5325f8a1352b6be6dc6b4ff Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove eel-debug-drawing M eel/Makefile.am D eel/eel-debug-drawing.c D eel/eel-debug-drawing.h commit 8447fd3670021530b6340829f27f1d689b633d3a Author: Cosimo Cecchi Date: 2010-08-19 [eel] use glib's i18n API instead of eel's M eel/eel-alert-dialog.c M eel/eel-canvas.c M eel/eel-editable-label.c M eel/eel-glib-extensions.c M eel/eel-gnome-extensions.c M eel/eel-stock-dialogs.c M eel/eel-vfs-extensions.c commit 742b9fb1550ceec9284f581c3741c0a864ca82fd Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove eel-i18n.[ch] M eel/Makefile.am D eel/eel-i18n.c D eel/eel-i18n.h commit 296efa481c76046e60481eec119da749fad15ba8 Author: Cosimo Cecchi Date: 2010-08-19 [eel] remove EelGtkContainer M eel/Makefile.am D eel/eel-gtk-container.c D eel/eel-gtk-container.h M eel/eel.h commit 3f68e342205f4446a99c1c18d34f23e33e11cae2 Author: Cosimo Cecchi Date: 2010-08-18 Revert "Add a border around info bars (#621366)." This reverts commit 48c0e19e60eee88f38a6e9c7a51211376a4c90f9. M src/file-manager/fm-directory-view.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit f5e2ed4c8a54340d26097c08eebd0b4d5f7c7cb7 Author: Baurzhan Muftakhidinov Date: 2010-08-18 l10n: Added Kazakh translation for nemo A po/kk.po commit e3b6eaf2a5c251014e9df40ff5d880ce92647db5 Author: Baurzhan Muftakhidinov Date: 2010-08-18 l10n: Added Kazakh (kk) to po/LINGUAS M po/LINGUAS commit 7397d9967125b8ef5ac39d8ad331ed22498d53cd Author: Милош Поповић Date: 2010-08-16 Updated Serbian translation M po/sr.po M po/sr@latin.po commit d433ee1280fd7fa821de5941db1c972124633c29 Author: Cosimo Cecchi Date: 2010-08-14 pathbar: walk the buttons in the right order When a file is gone, walk the button items in the right order, i.e. the reversed one, otherwise we end up removing the entire pathbar. M src/nemo-pathbar.c commit d8cfb36f697bdf9130e36cdb60c375a9b363fbbe Author: Cosimo Cecchi Date: 2010-08-14 pathbar: use g_list_free_1 where appropriate M src/nemo-pathbar.c commit 76ab7b6266b3fd050c11f6365981d21f8c22b364 Author: Cosimo Cecchi Date: 2010-08-14 pathbar: add missing modeline M src/nemo-pathbar.c commit aa43821e73d60804a3f0f2ebafb66aab53b440e1 Author: Cosimo Cecchi Date: 2010-08-13 [ln-p] use the 'outline-stippling' property on DnD M libnemo-private/nemo-icon-dnd.c commit b453aaacb0b17392eacacd8a9e378b7227da6413 Author: Cosimo Cecchi Date: 2010-08-13 [eel] add an 'outline-stippling' property to the rect item M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas-rect-ellipse.h commit b10d8c00395026719dc0840e9d82e682c7c4e436 Author: Cosimo Cecchi Date: 2010-08-13 [ln-p] properly dash the icon when resizing it M libnemo-private/nemo-icon-canvas-item.c commit 29d7b86087f6ab86f6abd6c3c08c4e1d94b92b36 Author: Cosimo Cecchi Date: 2010-08-13 [ln-p] make drawing of resize knobs work again M libnemo-private/nemo-icon-canvas-item.c commit cbdf5829637093c0a5c0a4ff4d303ad184847627 Author: Benjamin Otte Date: 2010-08-13 [ln-p] port nemo-icon-private to cairo drawing M libnemo-private/nemo-icon-private.h commit 34a376c97717cb05187b3d880e991c2d23511109 Author: Benjamin Otte Date: 2010-08-13 [ln-p] port nemo-icon-dnd to cairo drawing M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-icon-dnd.h commit 8eab39c06628da7cf919be77d922024198105f0a Author: Benjamin Otte Date: 2010-08-13 [ln-p] port NemoIconContainer to cairo drawing M libnemo-private/nemo-icon-container.c commit 89bd44de6bb11450b88d9d160593b65d62467579 Author: Benjamin Otte Date: 2010-08-13 [ln-p] port NemoIconCanvasItem to cairo drawing M libnemo-private/nemo-icon-canvas-item.c commit 6c691075c09ec23620484da00ffd43d3dfe0b75b Author: Benjamin Otte Date: 2010-08-13 [ln-p] port NemoDirectoryBackground to cairo drawing M libnemo-private/nemo-directory-background.c commit dfbf8b9b5636dceb3d6291c980d2c349afc849d7 Author: Benjamin Otte Date: 2010-08-13 [ln-p] port NemoCellRendererPixbufEmblem to cairo drawing M libnemo-private/nemo-cell-renderer-pixbuf-emblem.c commit a904f4acd546151ab37ee03bcce87869a805c323 Author: Cosimo Cecchi Date: 2010-08-13 [eel] remove dead code from eel-gtk-extensions M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h commit 172af77cfbdc4910034a100a99aa1ec2cb843495 Author: Benjamin Otte Date: 2010-08-13 [eel] port eel-gdk-pixbuf-extensions to cairo drawing M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h commit 917a27a6f69509720fadd0d50e40dbc87ae9f5d2 Author: Benjamin Otte Date: 2010-08-13 [eel] port eel-gdk-extensions to cairo drawing M eel/eel-gdk-extensions.c M eel/eel-gdk-extensions.h commit 6cb78fb15c89e53e60ee54dc8b773db6ca0def73 Author: Benjamin Otte Date: 2010-08-13 [eel] port EelEditableLabel to cairo drawing M eel/eel-editable-label.c M eel/eel-editable-label.h commit e716f82eea847e5298d773e2689642813db3d36e Author: Benjamin Otte Date: 2010-08-13 [eel] port eel-debug-drawing to cairo drawing M eel/eel-debug-drawing.c commit 759f3401bee333caf6d0ae6ae9820cdadda440e4 Author: Benjamin Otte Date: 2010-08-13 [eel] port EelCanvas to cairo drawing M eel/eel-canvas.c M eel/eel-canvas.h commit 820d4088a4d1768cf7e16de3c8ec0d7ff383f473 Author: Benjamin Otte Date: 2010-08-13 [eel] port EelCanvasRE to cairo drawing M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas-rect-ellipse.h commit 28b6813b77c4776b789231d3c64be3be01748608 Author: Benjamin Otte Date: 2010-08-13 [eel] port EelBackground to cairo drawing M eel/eel-background.c commit a9fece4d5cc759ee5d7c1f1761bbebc597a3d912 Author: Cosimo Cecchi Date: 2010-08-12 Actually check for gsettings-desktop-schemas M configure.in commit 7aca581c68aa1174f635cb79f24ba394f5ae1d3a Author: Cosimo Cecchi Date: 2010-08-12 Bump to 2.90.1 on master. M configure.in commit 8973b8b20308ae6bb24881385597294e1209a2b0 Author: Fran Diéguez Date: 2010-08-11 Updated galician translations M po/gl.po commit c938ed5839ddba4654818dacf437633d168865eb Author: Gheyret T.Kenji Date: 2010-08-11 Added UG translation M po/LINGUAS A po/ug.po commit 8ceed8e258c83975c1a7d4de71884505d64bb572 Author: Daniel Nylander Date: 2010-08-10 Updated Swedish translation M po/sv.po commit d24a302fbaad263c207cd2fded2719cf17753699 Author: Yaron Shahrabani Date: 2010-08-10 Updated Hebrew translation. M po/he.po commit 9db6cf3ed43eebf0ded2aacaaed883eface75e92 Author: Marcus Carlson Date: 2010-08-04 Better (shorter) text when emptying trash (#304336) M libnemo-private/nemo-file-operations.c commit 8598d769993843e1e6529a661fea034785ca0091 Author: Marcus Carlson Date: 2010-08-02 Adds option to open new tab in tab bar context menu (#590714) M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-window.c M src/nemo-window.h commit 489a146546100d6429fb1705c99a23e959838b2c Author: Marcus Carlson Date: 2010-08-09 Removes doublespacing strings (#577535) M libnemo-private/nemo-program-choosing.c commit 69c7b1850cf7125a3289c9a57c8335eb29a7053d Author: Marcus Carlson Date: 2010-08-04 Adds "Free space: " to the end of the current status string (#588641) M src/file-manager/fm-directory-view.c commit 19dc1d9dbf2c1be17d7ad502ba0710e76f5de9ff Author: Marcus Carlson Date: 2010-08-09 Open current folder properties on Alt+Enter and Ctrl+I (#569694) M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml commit 2b107d37a85ff03f84ecb63bb0b356dac43261f0 Author: Marcus Carlson Date: 2010-08-09 Enable scaling of icons on desktop only (#589295) M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-icon-view.h commit 5319feba3457213b656575893eeb973bde37a722 Author: Marcus Carlson Date: 2010-07-31 Hide all windows before closing when closing all windows (#441095) M src/nemo-application.c commit 59799e3e26476382ddd45d311e22db164474bbb2 Author: Marcus Carlson Date: 2010-07-05 Ellipseze bookmarks editing window renderer (#319159) M src/nemo-bookmarks-window.c commit 4bd09dd6ac7771579dc9e5af8779371c569a54ae Author: Andika Triwidada Date: 2010-08-10 Updated Indonesian translation M po/id.po commit 3988f758f0086a3b0cc149a9b7f4ebdc4bb9ef69 Author: Yaron Shahrabani Date: 2010-08-09 Updated Hebrew translation. M po/he.po commit aa27b362af03f198d5e49dbba85d662348d8ae8b Author: Nils-Christoph Fiedler Date: 2010-08-08 Updated LowGerman translation M po/nds.po commit 51ad44b586793dcc040001ae4d4d5c622c0102bb Author: Kjartan Maraas Date: 2010-08-07 Updated Norwegian bokmÃ¥l translation M po/nb.po commit ec99a1028efd2914a7ebaa5c85417168e956f4ef Author: drtv Date: 2010-08-07 Updated Tamil translation M po/ta.po commit 023076ad6a8cc79e8fcb11dfc769c801cbddc5d6 Author: drtv Date: 2010-08-07 Updated Tamil translation M po/ta.po commit 516733dba0f33edab1944649693bba271263daf4 Author: drtv Date: 2010-08-06 Updated Tamil translation M po/ta.po commit 803071c151adb67daaa669cbaa2614181157b82f Author: Fran Diéguez Date: 2010-08-05 Updated Galician translations M po/gl.po commit a9592caff33f54555d71715593879f09cfd6022a Author: Claude Paroz Date: 2010-08-05 Update POTFILES.in M po/POTFILES.in commit 0d33233e110922f614b7378f0ae9f8b94321dd06 Author: Reuben Potts Date: 2010-08-05 Added Manx translation M po/LINGUAS A po/gv.po commit 36add5d8c8107a0c2ed97a64f2a644c2362566a4 Author: Tomas Bzatek Date: 2010-08-05 Remove lockdown from monitored GConf paths M libnemo-private/nemo-global-preferences.c commit 9e219b3750a2cf60897bcd6213957cb9635dc05f Author: Tomas Bzatek Date: 2010-08-05 Require gsettings-desktop-schemas M configure.in commit 3c8b43bf6c10e83d0bd8fd97e0dae7032339ba72 Author: Tomas Bzatek Date: 2010-08-05 Convert disable-command-line lockdown to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c commit f871519fb28449c370448d8032294971ead1f162 Author: Tomas Bzatek Date: 2010-08-05 Remove unused gsettings schema keys M libnemo-private/org.gnome.nemo.gschema.xml.in commit 0c0d34f9cf2448303249122cd3baae6d1e32b93d Author: Tomas Bzatek Date: 2010-08-05 Re-enable commented-out keys in gsettings conversion file Please see bug 626106 for full story. Let's hope data mapping will work one day, for now it makes no issues. M libnemo-private/nemo.convert commit 224ea80bceb93e01cd9676c14e24c27eb556b813 Author: Sense Hofstede Date: 2010-08-04 Updated Frisian translations M po/fy.po commit 60ce7af080842792df21af6ff7fadf4a6674cf60 Author: Dirgita Date: 2010-08-04 Updated Indonesian translation M po/id.po commit 6c71e95a995db6fa15fd97fb314152481676b23a Author: Cosimo Cecchi Date: 2010-08-03 Remove useless code for handling color drops M libnemo-private/nemo-dnd.h M libnemo-private/nemo-file-dnd.c M libnemo-private/nemo-icon-dnd.c commit 5ce852673cc5d5ae45bd042f9ab07916358f349a Author: Cosimo Cecchi Date: 2010-08-03 Use the actual action for GDK_ACTION_ASK drops M libnemo-private/nemo-icon-dnd.c commit 2a980bb67b95c9d6c8218181e8c492869beb126a Author: Tomas Bzatek Date: 2010-07-30 Add GSettings migration file M libnemo-private/Makefile.am A libnemo-private/nemo.convert commit 3ea4de522ddba6ad9313dc3fdf2d6936b130913c Author: Marcus Carlson Date: 2010-08-02 Only show "Organize Desktop by Name" on Desktop (#530136) M src/file-manager/fm-icon-view.c commit f985fe76918ef299e3b580fef8922045c9a4cfed Author: Cosimo Cecchi Date: 2010-08-03 Don't unref the DBus proxy if it's NULL M libnemo-private/nemo-mime-actions.c commit 6d91cfb1d053a433cc5e17336c2e22c4e1d71673 Author: Cosimo Cecchi Date: 2010-08-01 Correctly show the multiple files warning Only show it when we're actually opening files, not folders. M libnemo-private/nemo-mime-actions.c commit 5b31e211ff20645c548949bd8d012b7bcaa39bf2 Author: Ankit Patel Date: 2010-07-27 Updated Gujarati Translations to correct dynamic variables mistakes M po/gu.po commit a1a8f97c9dcd9fdbbbfdddcec7f7d8da85a68dfb Author: Runa Bhattacharjee Date: 2010-07-27 Updated Bengali India Translation M po/bn_IN.po commit 52cf8ee6614dc311412ccecd8ea229d7b8c2a091 Author: Marcus Carlson Date: 2010-07-25 Enter key when combo box has focus validates new media dialog (#589436) M libnemo-private/nemo-autorun.c commit 915e5523947fe049e06f9bd8574760f6765e8ad7 Merge: 84b89c5 e50565b Author: Cosimo Cecchi Date: 2010-07-26 Merge branch 'remove-emblems-splitted' commit e50565bae0943c3bfe7025fc1f9728b07ef6ebd4 Author: Cosimo Cecchi Date: 2010-07-26 Remove sort by emblems in the UI file. M src/nemo-file-management-properties.ui commit 786dfd9d98dd7d313fa9cc33a7ebb500f100262c Author: Cosimo Cecchi Date: 2010-07-26 Remove emblem references from the GSettings schema. M libnemo-private/org.gnome.nemo.gschema.xml.in commit 326e6b14fbb7c106b35993ad3db8f243e38b3e44 Author: Cosimo Cecchi Date: 2010-07-26 Remove useless struct. M libnemo-private/nemo-file-private.h commit edfa318f2624bccba7b002c4176a839bf36136bd Author: Cosimo Cecchi Date: 2010-07-26 Remove useless defines. M libnemo-private/nemo-icon-names.h commit 09778cd3845fd3b6cf890d8263575e1a188fcdb2 Author: Cosimo Cecchi Date: 2010-07-26 Remove useless defines. M libnemo-private/nemo-file.h commit 23c1dbcac260018428949bb954dff65dd774ee11 Author: Cosimo Cecchi Date: 2010-07-26 Readd code to read emblems provided by extensions. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 84b89c5e4c1e7185d053c59fb6b14f72c1670e88 Author: Daniel Nylander Date: 2010-07-25 Updated Swedish translation M po/sv.po commit 2f21906e0f8d54df736a13e38f7b84013f8afb33 Author: Cosimo Cecchi Date: 2010-07-25 [data] remove other unused icons M icons/Makefile.am D icons/backgrounds.png D icons/chit_frame.png D icons/colors.png D icons/emblems.png D icons/erase.png commit 87469500d98babc7d74a74d2e6a88535a1b5ad95 Author: Cosimo Cecchi Date: 2010-07-25 [data] remove patterns M configure.in M data/Makefile.am D data/patterns/Makefile.am D data/patterns/blue_gray_rough.png D data/patterns/blue_ridge.png D data/patterns/blue_type.png D data/patterns/brushed_metal.png D data/patterns/burlap.jpg D data/patterns/camouflage.png D data/patterns/chalk.jpg D data/patterns/cork.png D data/patterns/countertop.png D data/patterns/dark-gnome.jpg D data/patterns/dots.png D data/patterns/fibers.png D data/patterns/fleur_de_lis.png D data/patterns/floral.png D data/patterns/fossil.png D data/patterns/gnome.jpg D data/patterns/green_weave.png D data/patterns/ice.png D data/patterns/manila_paper.png D data/patterns/moss_ridge.png D data/patterns/numbers.png D data/patterns/ocean_stripes.png D data/patterns/purple_marble.png D data/patterns/reset.png D data/patterns/ridged_paper.png D data/patterns/rough_paper.png D data/patterns/sky_ridge.png D data/patterns/snow_ridge.png D data/patterns/stucco.jpg D data/patterns/terracotta.png D data/patterns/wavy_white.png commit b5dd2515600f6dca2543aed45ae5455d9626ae92 Author: Cosimo Cecchi Date: 2010-07-25 [data] remove useless browser file M data/Makefile.am D data/browser.xml commit 1abbbd936663d91c8d4b854a0beed41f64d85f73 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove useless nemo-emblem-utils M libnemo-private/Makefile.am D libnemo-private/nemo-emblem-utils.c D libnemo-private/nemo-emblem-utils.h M src/file-manager/fm-properties-window.c commit f9be00dfbf7e6baa1ee66e3ed0d392b26d23b665 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove unused sort option M src/nemo-file-management-properties.c commit a147dffbf4ffbb11063f820a26537484bc67b558 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove useless variables. M src/file-manager/fm-properties-window.c commit 48df65532da4646db7250452e7cfb731f5773566 Author: Cosimo Cecchi Date: 2010-07-25 Remove [_set/_get]_keywords API from NemoFile. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 988e0ef8c5048ed7add4441f2325a5eb725b728e Author: Cosimo Cecchi Date: 2010-07-25 Remove 'Sort by Emblems' from the views. M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/file-manager/nemo-icon-view-ui.xml commit 4c465f5590f3e908b98197faeb63767193bb6e79 Author: Cosimo Cecchi Date: 2010-07-25 Remove dead code from the properties window. M src/file-manager/fm-properties-window.c commit d58d42c261db94bf0d538698939698f2aeb63d1d Author: Cosimo Cecchi Date: 2010-07-25 Remove code to handle emblems in DnD. M libnemo-private/nemo-dnd.h M libnemo-private/nemo-file-dnd.c M libnemo-private/nemo-file-dnd.h M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-tree-view-drag-dest.c commit 3e1347c1100095b38deb2431a434ad56e543aafa Author: Cosimo Cecchi Date: 2010-07-25 Remove code for handling reset backgorund in DnD. M libnemo-private/nemo-dnd.h M libnemo-private/nemo-file-dnd.c M libnemo-private/nemo-icon-dnd.c M src/file-manager/fm-properties-window.c commit 82bfad0af3902dd22e764a3cae9ad82735aac591 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove unused NemoSidebarTitle M src/Makefile.am D src/nemo-sidebar-title.c D src/nemo-sidebar-title.h commit 41b7e9fe4d944dc9adabd62c35b053bc8099c393 Author: Cosimo Cecchi Date: 2010-07-25 [eel] remove unused eel-xml-extensions. M eel/Makefile.am D eel/eel-xml-extensions.c D eel/eel-xml-extensions.h M eel/eel.h M src/nemo-navigation-window-menus.c M test/test-eel-pixbuf-scale.c commit cc4cbfcde75280055d78c61f867009820efb1749 Author: Cosimo Cecchi Date: 2010-07-25 [ln-p] remove unused NemoCustomizationData M libnemo-private/Makefile.am D libnemo-private/nemo-customization-data.c D libnemo-private/nemo-customization-data.h M src/file-manager/fm-properties-window.c commit 4ba7cefdd56ac289bb157d5d7d99034378efdebe Author: Cosimo Cecchi Date: 2010-07-25 [eel] remove unused EelWrapTable M eel/Makefile.am D eel/eel-wrap-table.c D eel/eel-wrap-table.h M eel/eel.h M src/file-manager/fm-properties-window.c commit 1ad357964e6d4e33a3fa4301245318e6e080385f Author: Cosimo Cecchi Date: 2010-07-25 [eel] remove unused EelLabeledImage M eel/Makefile.am D eel/eel-labeled-image.c D eel/eel-labeled-image.h M eel/eel.h M src/file-manager/fm-properties-window.c M test/Makefile.am D test/test-eel-labeled-image.c D test/test-nemo-wrap-table.c commit 6feed0a28d927a98aa5b09bc6622de1fc146387b Author: Cosimo Cecchi Date: 2010-07-25 [eel] remove unused EelImageTable M eel/Makefile.am D eel/eel-image-table.c D eel/eel-image-table.h M eel/eel.h M test/Makefile.am D test/test-eel-image-table.c commit 28fbb49494879666928a23aa37d36ca0e819d176 Author: Cosimo Cecchi Date: 2010-07-25 [eel] remove unused EelBackgroundBox M eel/Makefile.am D eel/eel-background-box.c D eel/eel-background-box.h commit 83af9319fe2ad9eb8af559dc1934a0fc48ed98ba Author: Cosimo Cecchi Date: 2010-07-25 [src] remove NemoInformationPanel It's old, basically unused, and unmaintained. M src/Makefile.am M src/nemo-application.c D src/nemo-information-panel.c D src/nemo-information-panel.h M src/nemo-navigation-window.h M src/nemo-window.c M src/nemo-window.h commit dc0517bb3462c3da5d7fd2afb31470cc58fac903 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove emblems from the properties window. M src/file-manager/fm-properties-window.c commit b2eb619da772af14f2e4127988a4431eedf212b6 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove NemoEmblemSidebar M src/Makefile.am M src/nemo-application.c D src/nemo-emblem-sidebar.c D src/nemo-emblem-sidebar.h commit c1a69337f031d0fce79fb6f0be52c44670145668 Author: Cosimo Cecchi Date: 2010-07-25 [src] remove NemoPropertyBrowser This is part of a complete removal of the backgrounds/emblems feature. M src/Makefile.am M src/nemo-navigation-window-menus.c D src/nemo-property-browser.c D src/nemo-property-browser.h M src/nemo-shell-ui.xml M src/nemo-window-menus.c commit 92d8c11fb694aaf44b13184c704f7ec792796922 Author: Daniel Nylander Date: 2010-07-25 Updated Swedish translation M po/sv.po commit 6fe90302d79742b7a17449569c47de9b04e83c35 Author: Aron Xu Date: 2010-07-24 Update Simplified Chinese translation. M po/zh_CN.po commit 8497f4011e7c42010b9db669b31a09cae7f57844 Author: Alexander Larsson Date: 2010-07-23 Remove gconf schemas M configure.in M libnemo-private/Makefile.am D libnemo-private/apps_nemo_preferences.schemas.in commit f58f80d4414daa520bd7287999c36b783103b70f Author: Alexander Larsson Date: 2010-07-23 Bump glib requirements for g_settings_reset M configure.in commit 31833fee708e23bb6ed16af045fa59b711076ecf Author: Alexander Larsson Date: 2010-07-23 Remove eel-enumeration, eel-gconf-extensions and eel-preferences M eel/Makefile.am D eel/eel-enumeration.c D eel/eel-enumeration.h D eel/eel-gconf-extensions.c D eel/eel-gconf-extensions.h M eel/eel-lib-self-check-functions.h D eel/eel-preferences-builder.c D eel/eel-preferences.c D eel/eel-preferences.h M eel/eel.h commit ca1c74b6df8a67e305c73adc1893e3552b763835 Author: Alexander Larsson Date: 2010-07-23 Remove last users of eel_preferences and eel_gconf M libnemo-private/nemo-desktop-link-monitor.c M libnemo-private/nemo-directory-background.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-program-choosing.c M src/file-manager/fm-tree-view.c M src/nemo-connect-server-dialog-main.c M src/nemo-file-management-properties-main.c M src/nemo-file-management-properties.c M src/nemo-history-sidebar.c M src/nemo-navigation-window-pane.c M src/nemo-pathbar.c M src/nemo-places-sidebar.c M src/nemo-window-menus.c D test/test-nemo-preferences-display.c M test/test.c commit e85f7b768edd103a48dc18993edd431fd880f5d4 Author: Alexander Larsson Date: 2010-07-23 Convert last eel_preference users to raw gconf This is moslty the lockdown stuff, but we also access the background setting. This should be converted to use the new gsettings when they land. M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/nemo-connect-server-dialog-main.c commit 02bb707335bbee09bb033f69c87baab65f8c8051 Author: Alexander Larsson Date: 2010-07-23 Initialize gsettings in nemo-connect-server M src/nemo-connect-server-dialog-main.c commit f202dab6902b28fdf1deaad7e4d259c50ef6b575 Author: Alexander Larsson Date: 2010-07-23 Remove remnants of old file-limit preference M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory.c M libnemo-private/nemo-directory.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h commit 97bbb3cd5029157fe044ad1949620ed6ee4f2278 Author: Alexander Larsson Date: 2010-07-23 Fix conversion of enable-delete M src/file-manager/fm-directory-view.c commit f495063f73e4949959678280186f99bb801f804b Author: Alexander Larsson Date: 2010-07-23 Move desktop-font preference to desktop settings M libnemo-private/nemo-global-preferences.h M libnemo-private/org.gnome.nemo.gschema.xml.in M src/file-manager/fm-desktop-icon-view.c commit 36c238331d19b9a33f13fcbaf49928f35b78ff8c Author: Alexander Larsson Date: 2010-07-23 Convert list-view preferences to gsettings Also removes unused default-use-manual-layout setting, and joins the sort order preferences of the list view and the icon view. M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-file-management-properties.c commit 000b73a429932d9816aaf5e69cd521675b39b548 Author: Alexander Larsson Date: 2010-07-23 Move the sort order prefs from view-specific to common prefs We already only have one UI setting that controls both, so it makes no sense to have two settings. M libnemo-private/org.gnome.nemo.gschema.xml.in commit 77207d5ff5bade458446d5783fe6a99fc38ac6de Author: Alexander Larsson Date: 2010-07-23 Add eel_g_settings_add_auto_strv M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit 1f2e9750da78aab404f4bda66889c9c5dc6adc94 Author: Alexander Larsson Date: 2010-07-22 Remove unused NEWS side pane prefs M libnemo-private/nemo-global-preferences.h commit 80a26e69ad2383d3aca093ed993e7ff3f8a1bc5b Author: Alexander Larsson Date: 2010-07-22 Convert compact view prefs to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-icon-view.c M src/nemo-file-management-properties.c commit 706efc521fec6035d644600b18afdfe20ac9d472 Author: Alexander Larsson Date: 2010-07-22 Convert tree sidebar prefs to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-tree-view.c M src/nemo-file-management-properties.c commit f6697ac99280f4fd9b8920d52bcc7407fd09c15c Author: Alexander Larsson Date: 2010-07-22 Convert desktop preferences to gsettings M libnemo-private/nemo-desktop-link-monitor.c M libnemo-private/nemo-desktop-link.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-container.c M libnemo-private/org.gnome.nemo.gschema.xml.in M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit 43652872e6b5644c831a9041c9d2e3e22a8ef773 Author: Alexander Larsson Date: 2010-07-22 Fix up desktop-is-home-dir gsettings conversion M libnemo-private/nemo-file-utilities.c commit 831787a7460655ebbac3499d399d72d45b1cdc60 Author: Alexander Larsson Date: 2010-07-22 Fix desktop-font gsettings conversion M src/file-manager/fm-desktop-icon-view.c commit df9c8ce6b162f37fe9372ee8b9e5c4798c9033e0 Author: Alexander Larsson Date: 2010-07-22 Convert icon-view preferences to gsettings M libnemo-private/nemo-file.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-thumbnails.c M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-icon-container.c M src/file-manager/fm-icon-view.c M src/nemo-file-management-properties.c commit 467af3b7e13fcc51ad1ecafd05bbfd4a4f7d9541 Author: Alexander Larsson Date: 2010-07-22 Add some more g_settings auto helpers to eel-glib-extensions M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit 75ade49a17470a86354eb8b591212d512c2ab08b Author: Alexander Larsson Date: 2010-07-22 Convert preview settings to gsettings M libnemo-private/nemo-file.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-icon-view.c M src/nemo-file-management-properties.c commit bcf929af833a83aba7ab58b7ae85697a288d006d Author: Alexander Larsson Date: 2010-07-22 Convert show-directory-item-counts to gsettings M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-file-management-properties.c M src/nemo-sidebar-title.c commit 4b5a2c833296abfb2ea28c0cca45d1a748d8a0d1 Author: Alexander Larsson Date: 2010-07-22 Convert show-text-in-icons to gsettings M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-file-management-properties.c commit 184d31a6773358c1d081c82e508cd4c369e6a711 Author: Alexander Larsson Date: 2010-07-22 Remove unused search-bar-type setting M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h commit 3f87495987c2db24002e48da344e96243a5c70e2 Author: Alexander Larsson Date: 2010-07-22 Convert default-folder-view to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-file-management-properties.c commit 87aa83c53183b02ca78fedf3c39b4ff15ad09e11 Author: Alexander Larsson Date: 2010-07-22 Convert sort-directories-first to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-directory-view.c M src/nemo-file-management-properties.c commit c6a6fb894cf9bd12fbd12977ab5ccd9e58540ae1 Author: Alexander Larsson Date: 2010-07-22 Conver window-state to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-application.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit adee5018f3a4985cf8d538a998f32ed9bb6a6ffd Author: Alexander Larsson Date: 2010-07-22 Convert install-mime-activation to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-mime-actions.c commit a7163bb6c91c40a8dea2e3b6c34623a0449053a4 Author: Alexander Larsson Date: 2010-07-22 convert exit with last window to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-main.c commit e167d6f663fc2c420d939f5cbb24c6463b03e8c2 Author: Alexander Larsson Date: 2010-07-22 Convert new tab position to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-mime-actions.c M src/nemo-navigation-window-menus.c M src/nemo-window-manage-views.c commit 42e9d22c84a3f54dfaa6da39243dd07c18a7cb9c Author: Alexander Larsson Date: 2010-07-22 Convert always-use-browser to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-directory-view.c M src/nemo-application.c M src/nemo-bookmarks-window.c M src/nemo-connect-server-dialog-nonmain.c M src/nemo-file-management-properties.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-window-manage-views.c commit 97d62a1d402853f2dd328a53cb7e94581b8e2498 Author: Alexander Larsson Date: 2010-07-22 Convert click-policy to GSettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-canvas-item.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-file-management-properties.c M src/nemo-history-sidebar.c commit cf4f7f10baa305cc3cbacb0b3c27c1eb45ae65f4 Author: Alexander Larsson Date: 2010-07-22 Convert executable-text-activation to GSettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-mime-actions.c M src/nemo-file-management-properties.c commit e3777c0e025815fd40908ea826f0091ecfe84fb0 Author: Alexander Larsson Date: 2010-07-22 Convert mouse prefs to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-navigation-window.c commit 202b69146a1fb42e147d1ca6f8694b27d8ada28b Author: Alexander Larsson Date: 2010-07-22 Convert date-format to gsettings M libnemo-private/nemo-directory.c M libnemo-private/nemo-file.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-file-management-properties.c commit 4c3067f86f9dfb848ab941ea8a2fb8aeb2c34944 Author: Alexander Larsson Date: 2010-07-22 Add eel_g_settings_add_auto_enum M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit 7abbb99a0e16be6050d61719a6b69197746ed7e4 Author: Alexander Larsson Date: 2010-07-22 Convert show-advanced-persmissions to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-properties-window.c commit 9318df841a5a0ccd0723e2d5dbce8d2ddfd89b1d Author: Alexander Larsson Date: 2010-07-21 Convert show-hidden-files to gsettings and merge it with show-backup-files M libnemo-private/nemo-desktop-directory-file.c M libnemo-private/nemo-desktop-directory.c M libnemo-private/nemo-desktop-icon-file.c M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory-private.h M libnemo-private/nemo-directory.c M libnemo-private/nemo-directory.h M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-merged-directory.c M libnemo-private/nemo-search-directory.c M libnemo-private/nemo-vfs-directory.c M libnemo-private/nemo-vfs-file.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-tree-model.c M src/file-manager/fm-tree-view.c M src/nemo-file-management-properties.c M src/nemo-window-menus.c M test/test-nemo-directory-async.c commit 036ae8def6b46048b8d3db36ae944f3d6c6523de Author: Alexander Larsson Date: 2010-07-21 Initialize global preferences in nemo-file-management-properties M src/nemo-file-management-properties-main.c commit f5b77ef6fb16d0378916a0b9e99161694480a0b3 Author: Alexander Larsson Date: 2010-07-21 Remove declaration of nonexisting functions M libnemo-private/nemo-file-utilities.h commit 8c13219e9a44e90e1e74ea20a440dc763b5892ed Author: Alexander Larsson Date: 2010-07-21 Convert desktop preferences to gsettings M libnemo-private/nemo-desktop-directory.c M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-desktop-icon-view.c M src/nemo-application.c M src/nemo-main.c M src/nemo-pathbar.c M src/nemo-places-sidebar.c commit 77f7a0378921b98f9b9bd0347acc25aabaa954dd Author: Alexander Larsson Date: 2010-07-21 Convert enable-delete to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-tree-view.c M src/nemo-file-management-properties.c commit 85cd2e45893a561ebd739c9bca595a1ef9a4f136 Author: Alexander Larsson Date: 2010-07-21 Convert confirm-trash preference to gsettings M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-directory-view.c M src/nemo-file-management-properties.c commit 924e9ee3ad889d9a8abc63c79c79c1cb25aaf0cf Author: Alexander Larsson Date: 2010-07-21 Convert media handling preferences to gsettings M libnemo-private/nemo-autorun.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-application.c M src/nemo-file-management-properties.c commit d6ab21e01e525f7c18b6c592802cc4f3b8764665 Author: Alexander Larsson Date: 2010-07-21 Convert side pane width to gsettings M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-navigation-window.c commit df4dcf7dc10b40af61e2922dbfd728ffdb575e76 Author: Alexander Larsson Date: 2010-07-21 Convert side pane background to gsettings M libnemo-private/nemo-global-preferences.h M src/nemo-information-panel.c commit 352e84790d3738a8d1e965ccd0f911c290dfef5d Author: Alexander Larsson Date: 2010-07-21 Convert background prefs to GSettings M libnemo-private/nemo-directory-background.c M libnemo-private/nemo-global-preferences.h commit 096b906da1e22b9ece5e568f195961ac40cae542 Author: Alexander Larsson Date: 2010-07-21 Create the global nemo_preferences GSettings object M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h commit c70466a133e6ca670e998af11bdc39aa2aec4825 Author: Alexander Larsson Date: 2010-07-21 Remove deprecated prefs for nemo theme M libnemo-private/nemo-directory-background.c M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-icon-container.c M src/nemo-property-browser.c commit a31e758e00b714a6897ebc6adf11c1599455b7f6 Author: Alexander Larsson Date: 2010-07-21 Rename sidebar ids as per the new gsettings pref names M src/file-manager/fm-tree-view.h M src/nemo-emblem-sidebar.h M src/nemo-history-sidebar.h M src/nemo-information-panel.h M src/nemo-notes-viewer.h M src/nemo-places-sidebar.h commit b33acb0abea58b2e980876ccde9fdc3bfce5c589 Author: Alexander Larsson Date: 2010-07-21 Add GSettings schemas for nemo M configure.in M libnemo-private/Makefile.am A libnemo-private/org.gnome.media-handling.gschema.xml.in A libnemo-private/org.gnome.nemo.gschema.xml.in commit ac038a0d90a4d59b564803be2698bc883672ab84 Author: Tomas Bzatek Date: 2010-07-21 Set default value for the navigation_window_saved_maximized gconf key And avoid gconftool messages like WARNING: Failed to parse default value `' for schema (/schemas/apps/nemo/preferences/navigation_window_saved_maximized) M libnemo-private/apps_nemo_preferences.schemas.in commit d992764b81b8b77efd0a68629372b569fb09dd11 Author: Fran Diéguez Date: 2010-07-21 Updated Galician translations M po/gl.po commit fed4221b81043420447bc45502314a4c1b6b12d6 Author: Chao-Hsiung Liao Date: 2010-07-20 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit bed28df1062042de23e939aeda409a9fc35d8eac Author: Mario Blättermann Date: 2010-07-18 [i18n] Updated German translation M po/de.po commit c7aae474dd404a015beb7413bab7d6d517ff2951 Author: Jorge González Date: 2010-07-18 Updated Spanish translation M po/es.po commit ab1ddd9e2bb2401a32cc0ebc587401b815504bd5 Author: Yaron Shahrabani Date: 2010-07-18 Updated Hebrew translation. M po/he.po commit faf1c74e479a6fb44fc1b51ee8e3319ee646cb81 Author: Sense Hofstede Date: 2010-07-18 Updated Frisian translations and added the language to LINGUAS M po/LINGUAS A po/fy.po commit b8f5d27f7deadb985d7574bc0547f2c616d8e9b9 Author: Cosimo Cecchi Date: 2010-07-17 Don't set a NULL argv for GApplication (#624508) M src/nemo-application.c commit 521e3c8481fcf2af398d2ed62692d415448386cd Author: Cosimo Cecchi Date: 2010-07-17 Refer to 3.0 instead of 2.32 in a string (#624286) M src/nemo-application.c commit b145c20c58e465114d372590e460a98c40a770dc Author: Diego Escalante Urrelo Date: 2010-07-15 nemo-recent: gtk_recent_manager_set_limit is deprecated Views are expected to filter results on their own, not the model. Bug #624506 M libnemo-private/nemo-recent.c commit 24bfbbb615a507b005d3b8d4bdea9efd69387ea0 Author: Mario Blättermann Date: 2010-07-16 [i18n] Updated German translation M po/de.po commit 837ed1bf4741550b9c41f041ee418af1912ee320 Author: Yaron Shahrabani Date: 2010-07-16 Updated Hebrew translation. M po/he.po commit 397f9a3b66edfde3974256c7c4ac3e031ef99328 Author: Diego Escalante Urrelo Date: 2010-07-13 Update GtkNotebook callbacks to gtk+ master GtkNotebookPage is gone in switch-page, it's just a GtkWidget now. Bug #624295 M src/nemo-navigation-window-pane.c M src/nemo-side-pane.c commit e3b7cebba5c6be648286905fe116e744eb532f16 Author: du baodao Date: 2010-07-15 Update Simplified Chinese translation. M po/zh_CN.po commit fe2322d56aace170295ba51221d0ad0cc66a1c17 Author: Paolo Borelli Date: 2010-07-15 Remove leftover comments. These eel functions do not exist anymore. M eel/eel-gdk-extensions.c commit 5fab3e456c7bf05bb2b080ef97b7aa1470390806 Author: Lucian Adrian Grijincu Date: 2010-07-15 po: Updated Romanian translation completed translation M po/ro.po commit a13a4faf32ab442734a11bf2d3855007231f8b6a Author: Lucian Adrian Grijincu Date: 2010-07-15 po: Updated Romanian translation media & trash consistency. M po/ro.po commit cde01839725762691f663d6d7cfec710024781b1 Author: Lucian Adrian Grijincu Date: 2010-07-14 po: Updated Romanian translation Signed-off-by: Lucian Adrian Grijincu M po/ro.po commit aea71b38892a2a0932472521d0414f8ad4ce9939 Author: Kjartan Maraas Date: 2010-07-13 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 683c15d3400988e5458ad91036b000c47859dec5 Author: Fran Diéguez Date: 2010-07-13 Updated Galician translations M po/gl.po commit 92076643ef6b11b9ffe5c9624ad50dccc2b6269e Author: Cosimo Cecchi Date: 2010-07-12 Release 2.31.5. M NEWS M configure.in commit 8ef7a9a1a1bdd02926b8b1fe59a6e97cf6c69574 Author: Marcus Carlson Date: 2010-07-10 Adds key binding for expanding and collapsing folders in list view https://bugzilla.gnome.org/show_bug.cgi?id=504869 M src/file-manager/fm-list-view.c commit 525b54d9a2385efdae21fd0b0da3631ba0071ce1 Author: Marcus Carlson Date: 2010-07-11 Ask for confirmation before opening more than 5 files (#596577) M libnemo-private/nemo-mime-actions.c commit b6fa38579dae68afd5b6ac71c98f7868e0a1731a Author: Marcus Carlson Date: 2010-07-10 Remove unnecessary include and remove a FIXME (#544211) Include of nemo-desktop-window.h in nemo-window.c is not needed anymore M src/nemo-window.c commit f12805d978c576e5f93f48815565f6e02fdd38ff Author: Marcus Carlson Date: 2010-07-10 Eat Control + v to not enable type ahead (#350819) M libnemo-private/nemo-icon-container.c M src/file-manager/fm-list-view.c commit 0a1cf043c9ec90b7b3da7e454eb860c5e2347866 Author: Marcus Carlson Date: 2010-07-11 Also change filename on disk when renaming a .desktop file (#145125) M libnemo-private/nemo-file.c commit 0fb0e54f06ec1090a0e3267a48bc66cc50603e82 Author: Marcus Carlson Date: 2010-07-10 Fixed typo (#624055) M src/nemo-file-management-properties.ui commit 34936ae8336e32359b3cc36b1bb2ba850313f4f5 Author: Marcus Carlson Date: 2010-07-10 Change clicked signal to toggled to not get into bad state (#440435) M src/nemo-property-browser.c commit a0bd71abc1d664d2ae3b949a3181041cdc162f2c Author: Cosimo Cecchi Date: 2010-07-10 Compile cleanly with GCC 4.5. M libnemo-private/nemo-directory-background.c M libnemo-private/nemo-icon-dnd.c M src/nemo-information-panel.c commit cd447610e3a8b32ec85d32cac7a12efcc33238ee Author: Fran Diéguez Date: 2010-07-07 Updated Galician translations M po/gl.po commit 8c033772f9ddf816103a21a6689e8a18831090fa Author: Marcus Carlson Date: 2010-07-05 Remove "Browse Folder" on Desktop when browsing is set to default (#563829) M src/file-manager/fm-directory-view.c commit 1f6f65c9547b430eb1414758a50d2aeea142869e Author: Marcus Carlson Date: 2010-07-05 Don't eat Alt+Right/Left in icon container So they do not interfere with history browsing https://bugzilla.gnome.org/show_bug.cgi?id=411664 M libnemo-private/nemo-icon-container.c commit e23140e8aea753ebb4195f1cfe728c62367fbdeb Author: Jorge González Date: 2010-07-04 Updated Spanish translation M po/es.po commit aca606ed03617ed15dc87ad34c1e0b72eda72928 Author: A. Walton Date: 2010-07-04 Use the correct icon for autorunning Open Folder According to the HIG, this icon should be 'folder-open'. This closes GNOME bug #608060. M libnemo-private/nemo-autorun.c commit c71ac3d1e00c3013a6736ac6dcf3ad074380b8a3 Author: YunQiang Su Date: 2010-07-04 Updated zh_CN translation. M po/ChangeLog M po/zh_CN.po commit 6b65b65f773e2ad27a23d40194b64fa911ae888c Author: Luca Ferretti Date: 2010-03-06 Fix mnemonics and capitalization for extra pane menu entries https://bugzilla.gnome.org/show_bug.cgi?id=612021 M src/file-manager/fm-directory-view.c M src/nemo-navigation-window-menus.c commit bb1ecb90fea17606c0eec2e36be7f60f47bb43ff Author: Ray Strode Date: 2010-07-04 Support overriding .gnome2 directory. The env var GNOME22_USER_DIR should be used for that. https://bugzilla.gnome.org/show_bug.cgi?id=614030 M libnemo-private/nemo-file-utilities.c M src/file-manager/fm-directory-view.c commit 5d86a47524e86980ec0ac21728ec76911d6bface Author: A. Walton Date: 2010-07-04 Set accessible name for the desktop. See https://bugzilla.gnome.org/show_bug.cgi?id=555425 M src/nemo-desktop-window.c commit 3094265abbfd3b70b39bb1dbd9625a81faf0fbca Author: Tomeu Vizoso Date: 2010-02-04 Use G_PASSWORD_SAVE_FOR_SESSION by default. When mounting volumes that require a password, present by default the option G_PASSWORD_SAVE_FOR_SESSION. https://bugzilla.gnome.org/show_bug.cgi?id=587909 M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-directory-view.c M src/nemo-connect-server-dialog-main.c M src/nemo-window-manage-views.c commit cfc72ae3ea86b63660e1bf153a9e33844e5b2281 Author: Thomas Karpiniec Date: 2010-06-08 Use correct logic for delaying updates while loading See http://mail.gnome.org/archives/nemo-list/2010-June/msg00023.html and https://bugzilla.gnome.org/show_bug.cgi?id=599680 for details. M src/file-manager/fm-directory-view.c commit ae1e7474830fb98eea93e1f4aadbf6e2b6caefc2 Author: Marcus Carlson Date: 2010-07-03 Properly handle G_IO_ERROR_FAILED_HANDLED (#601096). This avoid showing an useless message dialog when the user did not give authorization for mounting a device. M src/nemo-window-manage-views.c commit 41526834650640aa961d026ce5dea6025f668900 Author: Marcus Carlson Date: 2010-07-02 Change 'Close all Windows' shortcut to Ctrl+Q. Fixes bug #615808. M src/nemo-navigation-window-menus.c commit 1db7342c3fdc18ddea42266ae25ba3a6585c04b7 Author: Jorge González Date: 2010-07-01 Updated Spanish translation M po/es.po commit ab4a1d8234a63ce5c4ac96b89b624a1b216bd289 Author: Ted M Lin Date: 2009-09-02 Cleanup non-existant folders on pathbar (bug #310205). M src/nemo-pathbar.c commit 41e9a662b329c3438ee0c4c029cd4cf8d22d9574 Author: Cosimo Cecchi Date: 2010-07-01 Require GTK+ 2.90.5. So that we can drag in the right cairo dependency. M configure.in commit 375b1f4335666f9ba8d7e4f8003baecc1b9ec033 Author: Cosimo Cecchi Date: 2010-07-01 Add missing modeline. M eel/eel-canvas-rect-ellipse.c commit 3b671558f1d8ac1ee72e8af13d4ede6ab549a400 Author: Cosimo Cecchi Date: 2010-07-01 Fix build with GTK+3 master, use cairo_region_t. M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas.c M eel/eel-editable-label.c commit d1446086855ec1a673b144befff5b707244b998c Author: Cosimo Cecchi Date: 2010-07-01 Don't set has_custom_name for current location bookmark. So that renaming the relevant location can trigger updates in the listeners. M src/nemo-window-manage-views.c commit 7f6f20fd30dd989b85dbf132fd06e7e3e850d82c Author: Cosimo Cecchi Date: 2010-07-01 Remove dead code. M src/nemo-window-slot.c commit 90ebd95a7dbc3f7bef21e39c14fe04d4849fef37 Author: Marcus Carlson Date: 2010-06-30 Change "Clean Up by Name" to "Organize Desktop by Name" (#530136) M src/file-manager/fm-icon-view.c commit 83944789404d745e71f4b4a2f29c384cd44eba00 Author: Marcus Carlson Date: 2010-07-01 Ignore > 2 clicks in the icon container (#621098). M libnemo-private/nemo-icon-container.c commit 7faea402e1e37d88e5532dea712566312c981f92 Author: Kristjan Schmidt Date: 2010-06-29 Updated Esperanto translation M po/eo.po commit 9c903fd8a5b8daaa265a8d2c05603dbed9447d60 Author: Cosimo Cecchi Date: 2010-06-29 Release 2.31.4. M NEWS M configure.in commit a4e6c93d22394b086055ce92d0e06576958f969b Author: Mattias Põldaru Date: 2010-06-27 [l10n] Updated Estonian translation M po/et.po commit aaaf14437c04bd7ee8c53554e93ea47e615ae2d9 Author: Ivar Smolin Date: 2010-06-27 [l10n] Updated Estonian translation M po/et.po commit 0187296a18d2e30f5f30fab4528e42de42f7692a Author: Bastien Nocera Date: 2010-06-23 Update pkg-config files for GTK+ 3.x M libnemo-extension/libnemo-extension-uninstalled.pc.in M libnemo-extension/libnemo-extension.pc.in commit 3031b7d81721c2f54ce5412779e53ff6ebdf1fe2 Author: Bruno Brouard Date: 2010-06-23 Updated French translation M po/fr.po commit 48f2f2b3bb2abe397e799b74fd9a7140f52e307d Author: Matthias Clasen Date: 2010-06-21 Depend on the right gtk gir file We need Gtk-3.0.gir now. M libnemo-extension/Makefile.am commit 8f77b22b6091f87986abbd42d7637edf17e473a6 Author: Frédéric Péters Date: 2010-06-20 [build] link against gail-3.0 (GNOME bug 622155) M configure.in commit dc0ad00d37a68c009f555300cef427c4fb38d82c Author: Fran Diéguez Date: 2010-06-20 Updated Galician translations M po/gl.po commit f2e87dbcdb5535724a59ab9c69afe038b124b2bf Author: Matthias Clasen Date: 2010-06-19 Use the right datatype in the schema GConf calls it a bool, not a boolean. M libnemo-private/apps_nemo_preferences.schemas.in commit 45c9eb9bcbdddc91b4f53ecbd5731fc7eec88ac3 Author: Cosimo Cecchi Date: 2010-06-18 Move some variables around. M src/nemo-application.c commit e5d50bfd152e3d248519160a82908470973a539f Author: Cosimo Cecchi Date: 2010-06-18 Port to GApplication. Drop the libunique dependency. M src/nemo-application.c M src/nemo-application.h M src/nemo-main.c commit f75a6809f97033c75bf89cb6239415540953e9bb Author: Claudio Saavedra Date: 2010-06-18 Build against GTK+ 3.0 (#621938). M configure.in commit 89456b131830476d48234cd0ef32faf287496afb Author: Cosimo Cecchi Date: 2010-06-18 Use gtk_widget_get_child_requisition for the pathbar. Basically backport this GTK+ commit to make the pathbar work properly with width-for-height. http://git.gnome.org/browse/gtk+/commit/?id=0b92348077489047af98f360fd9bb3d59ee6d04a M src/nemo-pathbar.c commit c9e20bc18f5590b9377cab3b4ab5fc72108f7413 Author: Cosimo Cecchi Date: 2010-06-18 Don't fix relative paths for URIs. M src/nemo-location-entry.c commit 48c0e19e60eee88f38a6e9c7a51211376a4c90f9 Author: Cosimo Cecchi Date: 2010-06-17 Add a border around info bars (#621366). M src/file-manager/fm-directory-view.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit eae04584d51b9e058c6dcaea488880d8a43409bf Author: Cosimo Cecchi Date: 2010-06-17 Update for GLib 2.25.9 API changes (#621879). M configure.in M libnemo-private/nemo-mime-actions.c M src/nemo-application.c M src/nemo-application.h commit 5a53ae7e699edb480b76b72df99fdf1dd68eb8f8 Author: A S Alam Date: 2010-06-15 Updating Punjabi Translation by A S Alam M po/pa.po commit 877f57375a200daceafc9f5b96b9802cfc21e500 Author: A S Alam Date: 2010-06-15 Updating Punjabi Translation by A S Alam M po/pa.po commit af984bc991757eeda233c6e335cc3f35e6329a97 Author: Fran Diéguez Date: 2010-06-13 Updated Galician translations M po/gl.po commit aefc1fc8d2a49e123c4c647cfa01499d4649ef6a Author: Andrej ŽnidarÅ¡iÄ Date: 2010-06-11 Updated Slovenian translation M po/sl.po commit ca0dbef16103f523b3dfb86e795447998f060b53 Author: Cosimo Cecchi Date: 2010-06-11 [src] remove a debug printf. M src/nemo-sidebar-title.c commit d667293d865797665b50de2b972297ae61881eb6 Author: Cosimo Cecchi Date: 2010-06-11 [build] bump GTK+ required version to 2.21.2. M configure.in commit d9f80b3f407b65f559c0ca47cddac41175ac353d Author: Cosimo Cecchi Date: 2010-06-11 [test] GSEAL test-eel-image-table. M test/test-eel-image-table.c commit 78287a76d6be97428d166f781385b86e18c9b6b8 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-zoom-control. M src/nemo-zoom-control.c commit bbeb350ef219f6e94d9eba6e78d0ebbdb2201a08 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-window. M src/nemo-window.c commit 44af78c3c205f88801a8bdfa3cb0a02f7cd87d3f Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-window-manage-views. M src/nemo-window-manage-views.c commit b5407396039035e6f4e78c2d9d03891d76dd93bd Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-window-bookmarks. M src/nemo-window-bookmarks.c commit 2675ebc0873e71af0a5f8cc3463313525bfeebac Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-spatial-window. M src/nemo-spatial-window.c commit 11736c1fcbe581eab9c4a86619cfff0e71bbef38 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-sidebar-title. M src/nemo-sidebar-title.c commit 24b94447cb798ee03c9d21973f2d650c4cec2ad9 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-side-pane. M src/nemo-side-pane.c commit 2aa9bed8a98cbf68fec53b88e7d05f86f158bd07 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-query-editor. M src/nemo-query-editor.c commit 075446f3751566ec1187d6cdb3751456c9c50867 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-property-browser. M src/nemo-property-browser.c commit 06a2e40ccc45d82692997ee29e56314a45ea373f Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-places-sidebar. M src/nemo-places-sidebar.c commit 61006bd18b748c50bde01efe4abcb038a710ee11 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-pathbar. M src/nemo-pathbar.c commit 791e4c7cf2f0ee3c5f8bd55b1867daea6d891000 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-notebook. M src/nemo-notebook.c commit 2b200c5bcaee4018a9fcf82a7b1e0076f2568588 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-navigation-window. M src/nemo-navigation-window.c commit cb1e2694bdaa8c8fbad8b2541f0efe354d81b1c0 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-navigation-window-menus. M src/nemo-navigation-window-menus.c commit a0d1ca75e37fd26135fe9c85d8d86dc75e831d86 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-location-dialog. M src/nemo-location-dialog.c commit 4bba151bdacd27a193c100cf771144b7d2501548 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-location-bar. M src/nemo-location-bar.c commit eab92fb34f344fcadaaaf17beb7609a1f2cab0fa Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-information-panel. M src/nemo-information-panel.c commit 26f5fcc5efe27ca7f63b45d04a773caae6a0becd Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-emblem-sidebar. M src/nemo-emblem-sidebar.c commit 45fc9cc4fae20e69e12ca14b767277d190978c71 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-desktop-window. M src/nemo-desktop-window.c commit ac4547b030a3b0b9ed60ff9bb2f783ac10a7d62b Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-connect-server-dialog. M src/nemo-connect-server-dialog.c commit b43e268e738e8754eaa3d0e38a0cb5859f254241 Author: Cosimo Cecchi Date: 2010-06-11 [src] GSEAL nemo-application. M src/nemo-application.c commit c76136d88c314c17dbabca9ddd8808d297ceaee0 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-tree-view. M src/file-manager/fm-tree-view.c commit c764e246da912817929ae33075a3683a22bb3bf6 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-properties-window. M src/file-manager/fm-properties-window.c commit 0fe90a931acbef48d8b50b380ee05362ecdf0058 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-list-view. M src/file-manager/fm-list-view.c commit 8f9b6e75eb8eb5f9ece32963e53a69381fd65336 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-list-model. M src/file-manager/fm-list-model.c commit df190cef8cb35e0f5a717d8bd28b810ab8304137 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-icon-view. M src/file-manager/fm-icon-view.c commit eea532e7f0cf729c6e9e78744add5c8cde304ba4 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-ditem-page. M src/file-manager/fm-ditem-page.c commit 197a0101f756111b4f8712433586761c356051d3 Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-directory-view. M src/file-manager/fm-directory-view.c commit 8ba99b676c20b359c7b46b9ae4e8432fbbf4ae8f Author: Cosimo Cecchi Date: 2010-06-11 [file-manager] GSEAL fm-desktop-icon-view. M src/file-manager/fm-desktop-icon-view.c commit 0405cc8c808247eff6672a1ae69fd35c6bda841b Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-undo. M libnemo-private/nemo-undo.c commit 8ce136d19d72559a7eeb0665b61607646ecf36d6 Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-tree-view-drag-dest. M libnemo-private/nemo-tree-view-drag-dest.c commit 8ad542cf15a6a7749c672def06a5198f93a40e12 Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-progress-info. M libnemo-private/nemo-progress-info.c commit a0d555cf31a6568038fb67c004c1085bec6de8cf Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-open-with-dialog. M libnemo-private/nemo-open-with-dialog.c commit 44f222288b33de74464567a1578fbf7ea69725d7 Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-keep-last-vertical-box. M libnemo-private/nemo-keep-last-vertical-box.c commit 3711a0db65ad8ca432d0359eb11b4cd31f799df6 Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-icon-dnd. M libnemo-private/nemo-icon-dnd.c commit e57bd6003efc33bfb97fd7aa46166eba105cc2a8 Author: Cosimo Cecchi Date: 2010-06-11 [ln-p] GSEAL nemo-icon-container. M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h commit 028a80a630e17df3ba23a6778459122b2e18da0b Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-icon-canvas-item. M libnemo-private/nemo-icon-canvas-item.c commit 92d8c2a24dbf5a1a902efef0da86dd23e43208db Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-horizontal-splitter. M libnemo-private/nemo-horizontal-splitter.c commit 2206f6c82c5a49769ccdede84d74bf595a0a57c1 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-file-operations. M libnemo-private/nemo-file-operations.c commit dddf609f373f472bca41070296a54be7e67b7adf Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-file-conflict-dialog. M libnemo-private/nemo-file-conflict-dialog.c commit 0ea1e03d74713bcac0ad90a03092d8ed6d7d2528 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-entry. M libnemo-private/nemo-entry.c commit a22a367740abe58100e8137ad750176ed79f5325 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-dnd. M libnemo-private/nemo-dnd.c commit 3cd134fde66949514eb86b60795394f1aa7a2db6 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-clipboard. M libnemo-private/nemo-clipboard.c commit fd6f9364d040814346b9995570a558c1d6cb081c Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-clipboard-monitor. M libnemo-private/nemo-clipboard-monitor.c commit 392e079433aed213889b972c906d8d0b1b4290d9 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-cell-renderer-pixbuf-emblem. M libnemo-private/nemo-cell-renderer-pixbuf-emblem.c commit 3709f641bde70d96fb1feb0288521ced6dba7719 Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-bookmark. M libnemo-private/nemo-bookmark.c commit 756beaef00e01c686b061ea77d56c7aa6768d32e Author: Bastien Nocera Date: 2010-06-11 [ln-p] GSEAL nemo-autorun. M libnemo-private/nemo-autorun.c commit 47947617e14e9e3b676b0f8614bbe294f86dde86 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-wrap-table. M eel/eel-wrap-table.c commit 1db88082b3dddef066f718a44dd750a18b201dbd Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-labeled-image. M eel/eel-labeled-image.c commit 963d2dbd1cca1b92bc35f6421ae8789d1b3f4f9d Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-image-table. M eel/eel-image-table.c commit 6a2110eb0cda5f3c7d47f196b73336ec0227505b Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-gtk-extensions. M eel/eel-gtk-extensions.c commit 239c62774c44ef6e192301379db19ad53c382742 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-gtk-container. M eel/eel-gtk-container.c commit f9273be48cb62cd39aa145fa715547ec077c1670 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-editable-label. M eel/eel-editable-label.c commit 3e8a76045a33c778f423befc1c16a5e26929d00e Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-debug-drawing. M eel/eel-debug-drawing.c commit e07b688a3b8ec257a14087b696b3a02090f289ab Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-canvas. M eel/eel-canvas.c M eel/eel-canvas.h commit 191f491c9f0877c1e2c174e435898ba1e717c352 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-canvas-rect-ellipse. M eel/eel-canvas-rect-ellipse.c commit a63c3afa5c19083558c365fe6374ab5d85db3c98 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-background-box. M eel/eel-background.c commit 24cff3dc16b71105d1c096451357e6df6347b9d1 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-background-box. M eel/eel-background-box.c commit c357d232dd5cbfd7fdb3014dfff4034d01f8e66e Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-art-gtk-extensions. M eel/eel-art-gtk-extensions.c commit dae50fa5b6aeb4f811fb0d8e35da999138653cd9 Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-alert-dialog. M eel/eel-alert-dialog.c commit d104160104f50a3b2fd5e311578314e927ea73ca Author: Bastien Nocera Date: 2010-06-11 [eel] GSEAL eel-accessibility. M eel/eel-accessibility.c commit 0596f0121e6f931bfcd704cb9bcdc8ec0afdf024 Author: Cosimo Cecchi Date: 2010-06-08 Don't use 'File Browser' in the window title for browser mode (#614848). We still use it if spatial mode is the default though. Thanks to Marcus Carlson for the initial patch. M src/nemo-navigation-window.c commit c8c1dd8061d04fc002fa19cd643a95243a4a1468 Author: Cosimo Cecchi Date: 2010-06-07 Release 2.31.3. M NEWS M configure.in commit 54b044b9eaa3614498bf4a56ea915ff3a46f5e6d Author: Cosimo Cecchi Date: 2010-06-07 Update the location bar and dialog to the new API. This also fixes bug #346422. Thanks to Amos Brocco for the initial patch. M src/nemo-location-bar.c M src/nemo-location-dialog.c commit 376f9ba0bdd25794a6bd2a57caa760b8d2cbb32d Author: Cosimo Cecchi Date: 2010-06-07 Support relative paths in NemoLocationEntry. This also adds a custom 'activate' implementation which converts a relative path (if present) to an absolute one. M src/nemo-location-entry.c M src/nemo-location-entry.h commit 613b6a8292296b097660f92566de81fa71d7a878 Author: Cosimo Cecchi Date: 2010-06-07 Use the new API to order files in the list view. This also closes bug #590077. Thanks to Holger Berndt for the initial patch. M src/file-manager/fm-list-view.c commit 1459a109750d0e740fe1327cc029e342c02ce2d3 Author: Cosimo Cecchi Date: 2010-06-07 Use the new API to order files in the icon view. M src/file-manager/fm-icon-view.c commit b04bafc862ef092c1090851e6c87aabfed1eea50 Author: Cosimo Cecchi Date: 2010-06-07 Add methods to get per-file default sort type/attribute. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit e847f4196c5aabb65a1ac43688bcd1b79443b261 Author: Cosimo Cecchi Date: 2010-06-07 Add nemo_file_is_user_special_directory(). M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 0d36142a4eaa799034a25e37e95f6d66ca14f0ee Author: Theppitak Karoonboonyanan Date: 2010-06-06 Updated Thai translation. M po/th.po commit 0c8ea8597ae0616696fb52ae4396082990a85be0 Author: Sira Nokyoongtong Date: 2010-06-06 Updated Thai translation. M po/th.po commit 6cb3dae5f89887a15fa180a52e4f1362c079b1a0 Author: Cosimo Cecchi Date: 2010-06-02 Use single GTK+ header includes. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-conflict-dialog.h commit 02f961d5c892e34f88a680a7662f655b6676400b Author: Kjartan Maraas Date: 2010-06-01 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 4edc5f843a4cb0d89c21fd957dc7d6fa955cf012 Author: Alexander Larsson Date: 2010-06-01 Don't use deprecated Gtk+ api (GtkBoxChild) M libnemo-private/nemo-keep-last-vertical-box.c commit 4cebf7e4582788229f3fde7685ef44148b5cb99d Author: Ivar Smolin Date: 2010-05-31 Estonian translation updated M po/et.po commit 345e520752b627bf0d085ab6f5d480476b1dba89 Author: Cosimo Cecchi Date: 2010-05-30 Specify the expected variant type instead of using G_VARIANT_TYPE_TUPLE. Thanks to Christian Persch. M libnemo-private/nemo-file-utilities.c M src/nemo-application.c commit f1c08dcb6ff93dcdea9dfeacded9d70f7e725167 Author: Cosimo Cecchi Date: 2010-05-30 Bump required GLib version. M configure.in commit ce766ea529017649b72ea844e73c46e1d73c79b6 Author: Cosimo Cecchi Date: 2010-05-30 Use g_bus_watch_proxy() to call PackageKit methods. M libnemo-private/nemo-mime-actions.c commit 73ae91e0664b62e7b066cf5a23f6e37ea145a818 Author: Cosimo Cecchi Date: 2010-05-30 Use g_bus_watch_proxy() to initialize ConsoleKit. M src/nemo-application.c M src/nemo-application.h commit 1eb13e5686f14b006dd0f11a92219b7fe826b50e Author: Cosimo Cecchi Date: 2010-05-30 Re-use the same connection to Inhibit/Unhinibit power manager. M libnemo-private/nemo-file-utilities.c commit 8a58f4e298e844c18928e5a0681fa8ac2b9f2ee1 Author: Christian Persch Date: 2010-05-17 Port to GDBus Bug #618910. M configure.in M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-mime-actions.c M src/nemo-application.c M src/nemo-application.h commit 6cba2c2bcae95e7eca687561359b4d85c89694df Author: Alan Monfort Date: 2010-05-29 Updated Breton translation M po/br.po commit 460c57e9ad8bb725076ae90e2eb8287a90330663 Author: Alan Monfort Date: 2010-05-29 Updated Breton translation M po/br.po commit 8bc39ced44598fb0be61ffdf799c50a81d6dd272 Author: Yaron Shahrabani Date: 2010-05-29 Updated Hebrew translation. M po/he.po commit 68a877ab0fe8fef87841e06e84312eea9068794e Author: Jorge González Date: 2010-05-25 Updated Spanish translation M po/es.po commit 9708b257484931185f458ce343f1e4f88a82c6ab Author: Cosimo Cecchi Date: 2010-05-24 Release 2.31.2. M NEWS M configure.in commit 81e15c0accfe2147e0520fc8fba91fc2d97d0d2a Author: Cosimo Cecchi Date: 2010-05-24 Fix a compiler warning. M cut-n-paste-code/libegg/eggdesktopfile.c commit b0d808de8c8d1be6b8a4403fc587cc032612027a Author: Alexander Larsson Date: 2010-05-24 Change default thumbnail size from 96 to 64 Still not the same as icons (48) but makes for less jaring layouts, and lets you see more of the thumbnail content than 48 would. M libnemo-private/apps_nemo_preferences.schemas.in commit 7b75f714980293b12c2548126ba30c8af7dacecf Author: Paul Seyfert Date: 2010-05-24 Updated German translation M po/de.po commit d320b181dc169cb2720b38e65ef743803ad524ea Author: Thomas Thurman Date: 2010-05-20 Updated Shavian translation M po/en@shaw.po commit ddb325fe0c420edcae32e65ebc0b6958fa0a84e2 Author: Fran Diéguez Date: 2010-05-20 Updated Galician translations M po/gl.po commit 86d41c14159741c6803940a83a42e40a89d061d7 Author: Cosimo Cecchi Date: 2010-05-20 Split WARNING_CFLAGS into its own variable. So that we can use e.g. LIBNEMO_EXTENSIONS_CFLAGS when compiling the gir information. M configure.in M eel/Makefile.am M libnemo-extension/Makefile.am M libnemo-private/Makefile.am M src/Makefile.am M src/file-manager/Makefile.am M test/Makefile.am commit 2617e16aa55367ba3d73a33dc27376cf518d4676 Author: Cosimo Cecchi Date: 2010-05-20 Implement transparent icons for cut files in tree view. M src/file-manager/fm-tree-model.c M src/file-manager/fm-tree-model.h M src/file-manager/fm-tree-view.c commit 5b213054823f64c8125effe56f0288c54aefa625 Author: Cosimo Cecchi Date: 2010-05-20 Use the new NemoFile API in the list model. M src/file-manager/fm-list-model.c commit df11a77d4b08e170b63da4c4b67ea9730634268c Author: Cosimo Cecchi Date: 2010-05-20 Move the clipboard callbacks to NemoClipboardMonitor. M libnemo-private/nemo-clipboard-monitor.c M libnemo-private/nemo-clipboard-monitor.h M src/file-manager/fm-directory-view.c commit bbc6c3d83e51af4da3a093ef95cb17d188f162f2 Author: Cosimo Cecchi Date: 2010-05-20 Add an utility function to compare file locations. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 044952f0a5683e37545cd30d2a5296213abf70bd Author: Cosimo Cecchi Date: 2010-05-15 Implement transparent icons for cut files in list view. M src/file-manager/fm-list-model.c M src/file-manager/fm-list-model.h M src/file-manager/fm-list-view.c commit 07f768de905f42857c01434f2550c43d79eb4ed6 Author: Cosimo Cecchi Date: 2010-05-15 Implement transparent icons for cut files in icon view. M src/file-manager/fm-icon-view.c commit 03ff6b4d60473db94f351b9b3b2c0ee9490556cc Author: Cosimo Cecchi Date: 2010-05-15 Move clipboard information to NemoClipboardMonitor. So that we can use that information from more than one view at the same time. M libnemo-private/nemo-clipboard-monitor.c M libnemo-private/nemo-clipboard-monitor.h M src/file-manager/fm-directory-view.c commit 226e7ba044f15cb22e8f9c3966625c496913f3df Author: Cosimo Cecchi Date: 2010-05-15 Add an "highlighted-for-clipboard" property to the item. M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h commit 76ae23877a3e022d1d47526f1b74e5559faeb756 Author: Cosimo Cecchi Date: 2010-05-15 Move pixbuf render code to libeel. So that we'll be able to use it from outside of NemoIconCanvasItem. M eel/eel-gdk-pixbuf-extensions.c M eel/eel-gdk-pixbuf-extensions.h M libnemo-private/nemo-icon-canvas-item.c commit 97d736a0861a81f825698451249564e42d002d4b Author: Cosimo Cecchi Date: 2010-05-19 Add another missing GConf schema. M libnemo-private/apps_nemo_preferences.schemas.in commit 4309418a12b43e87a4de1f44d0641a6c902a64ce Author: Gregory J. Horvath Date: 2010-05-19 Add a missing GConf schema. M libnemo-private/apps_nemo_preferences.schemas.in commit f1148c5878e8b68c95dad8dec50aa30c6ee9b2d3 Author: Rodrigo Moya Date: 2010-05-19 Add introspection support for libnemo-extension M libnemo-extension/Makefile.am commit 8d366402ca6120e6f75051596d8ae33589ef3591 Author: Rodrigo Moya Date: 2010-05-13 Added introspection to libnemo-extension M configure.in M libnemo-extension/Makefile.am commit 1c88c7186ed298fbdd67e31cb3b8c613093c3411 Author: Adrian Bunk Date: 2010-03-29 autogen.sh: automake 1.9 is required (see configure.in) M autogen.sh commit 38986e1c0773299a7efa9f7333d5d0c513a8b66c Author: Thomas Thurman Date: 2010-05-16 Updated Shavian translation M po/en@shaw.po commit 649b0f65182f370792e00e227923a251e19ace17 Author: Fran Diéguez Date: 2010-05-16 Updated Galician translations M po/gl.po commit 0a8ec392070d9927df450ceffc4333b0a25c281c Author: Fran Diéguez Date: 2010-05-14 Updated Galician translations M po/gl.po commit 0eead029b0725cb70d9817467f820ac53b14eb60 Author: Jorge González Date: 2010-05-13 Updated Spanish translation M po/es.po commit b521530ac4cba5327ea37af7b488355f1d87399c Author: Cosimo Cecchi Date: 2010-05-13 Hide the 'Arrange by Trash Time' option if we're not in the trash. M src/file-manager/fm-actions.h M src/file-manager/fm-icon-view.c commit eab6722face64b510b8bbf330761d5b5ae7e807f Author: Cosimo Cecchi Date: 2010-05-13 Don't rely on updated metadata when resetting columns to default. M src/file-manager/fm-list-view.c commit 96da10025c3bd00ed5d748d0b91447a0137b5ef9 Author: Cosimo Cecchi Date: 2010-05-12 Define different defaults for the columns in trash. These defaults are hardcoded, but I think it's fine, as they're limited to the trash. The rest of nemo will follow the usual defaults. M src/file-manager/fm-list-view.c commit 19bbf8a1ae54cc11d51935f94209074fb2659e90 Author: Cosimo Cecchi Date: 2010-05-12 Use the new API in the preferences. M src/nemo-file-management-properties.c commit 4b3038b4ea85ce309d6fb128675611d3c912739e Author: Cosimo Cecchi Date: 2010-05-12 Use the new methods in the column chooser. The chooser becomes file-oriented as well. It will fetch the common columns if we don't provide any file, and try to fetch the specialized list if we pass a file. M libnemo-private/nemo-column-chooser.c M libnemo-private/nemo-column-chooser.h commit 14dc307c7e76f144d9fbbd091777123867b1efe4 Author: Cosimo Cecchi Date: 2010-05-12 Split the special columns. Add utility functions which return a list of columns depending on the location, separate from the 'common' set which is useful for every directory. M libnemo-private/nemo-column-utilities.c M libnemo-private/nemo-column-utilities.h commit f62cad9bae1b742b41c088449b2278eb7b6fd093 Author: Marcus Carlson Date: 2009-10-11 Adds Trashed On and Original Location as columns in List View And also an 'Arrange by Trash Time' option in Icon View. https://bugzilla.gnome.org/show_bug.cgi?id=89706 M libnemo-private/nemo-column-utilities.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-vfs-file.c M src/file-manager/fm-icon-view.c M src/file-manager/nemo-icon-view-ui.xml commit eafead25cabb9ec580c21f105f053be10dac9d5d Author: Thomas Thurman Date: 2010-05-12 Updated Shavian transliteration M po/en@shaw.po commit 6519089b3597d158618dab8d752b2d4e09494e87 Author: Khaled Hosny Date: 2010-05-12 Cleanup file header M po/ar.po commit 000092092d86c5b39b6d3a4638c860ce50d32961 Author: Khaled Hosny Date: 2010-05-12 Updated Arabic translation M po/ar.po commit 3aa7864fd2fd0459073abe0eb75b9f73fdb91653 Author: Kjartan Maraas Date: 2010-05-11 Updated Norwegian bokmÃ¥l translation M po/nb.po commit a9c3fff8710dfaae0615e48b3f6447d4b5576146 Author: Manoj Kumar Giri Date: 2010-05-11 Updated Oriya Translation M po/or.po commit 5f6b4e6f3b8ca2c27eacf5977121618fb3fb12c1 Author: Bruno Brouard Date: 2010-05-10 Updated French translation M po/fr.po commit 601c42c06e4d40de99c38eb795f20375dd2e7242 Author: Cosimo Cecchi Date: 2010-05-09 Don't add the emblem if it's equal to the icon. M libnemo-private/nemo-file.c commit 414810d3e294eaf3565127cce26fc760f147f6bf Author: Cosimo Cecchi Date: 2010-05-08 Use the mount icon as an emblem in the information sidebar. M src/nemo-sidebar-title.c commit 88781dae75003996accbf521a2d3e405d7d4fd14 Author: Cosimo Cecchi Date: 2010-05-08 Use the mount icon as an emblem in the views. M src/file-manager/fm-icon-container.c M src/file-manager/fm-list-model.c commit 7bfc3c6a7d22e1091f7985377dabd8581e1dfeac Author: Cosimo Cecchi Date: 2010-05-03 Prefer mount icons as window icons (#613733). M src/nemo-navigation-window.c M src/nemo-spatial-window.c commit 38c5b7ee06b4f8d90689dfd8fa5e010066a0b233 Author: Cosimo Cecchi Date: 2010-05-08 Add new icon flags to use mount icons. This will allow us to be more consistent with mount icons around and refactor some code as well. M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h commit 17f50da7dfbb7efdc3db74deed0cd341711ddb6e Author: Mario Blättermann Date: 2010-05-08 Updated German translation M po/de.po commit ca10b4b89df5c8123c08ad1de80139e1a52a4932 Author: Cosimo Cecchi Date: 2010-05-06 Never update icons for remote bookmarks. M libnemo-private/nemo-bookmark.c commit 108a23dc0e0be534530028612d72302c7d2a1e53 Author: Cosimo Cecchi Date: 2010-05-06 Trigger the eject button on release. M src/nemo-places-sidebar.c commit 729ce7cf7feead42d16a5b8793cd7948286c00f8 Author: Cosimo Cecchi Date: 2010-05-06 Use the new API in the places sidebar. M src/nemo-places-sidebar.c commit 6bbe1bd9ed2d9eea934ced04952b3ab4a8d74252 Author: Cosimo Cecchi Date: 2010-05-06 Set a 'folder-remote' icon for remote bookmarks. M src/nemo-connect-server-dialog.c commit 89fa909f3d406dd2e47006eeaaee051bef2b77d5 Author: Cosimo Cecchi Date: 2010-05-06 Set a 'folder-remote' icon if the URI is not native. Also, port to the new API. M src/nemo-bookmark-list.c commit e6d70ef8a41bd0c6e6685f07e85e266e3227c61c Author: Cosimo Cecchi Date: 2010-05-06 Update to the new API. M src/nemo-bookmarks-window.c M src/nemo-window-manage-views.c M src/nemo-window.c commit 856177d1dc13802e6473923d331f8f1ba91f8e51 Author: Cosimo Cecchi Date: 2010-05-06 Change NemoBookmark API. Remove _set_has_custom_name() method and use just one _new() constructor. Also, emit the CONTENTS_CHANGED signal when we're setting a new name, as that will trigger a save/reload of .gtk-bookmarks due to saving a new label. Finally, don't use gnome-fs-bookmark* icon names anymore, as they're deprecated. We now use 'folder' as a default icon, and add a 'warning' emblem when the URI does not exist. M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-bookmark.h commit 1756fb0b77aebae201ffb1ee1641a9118ca941d9 Author: Cosimo Cecchi Date: 2010-05-06 Remove a pile of hacks used to initialize bookmarks. - Make nemo_window_constructed a real GObject implementation and move bookmark initialization code there. - Don't replicate a singleton logic in nemo-window-bookmarks now that NemoBookmarkList is a real singleton - Remove get_bookmark_list() method from NemoWindowInfo, as it's not any useful anymore. M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/nemo-application.c M src/nemo-window-bookmarks.c M src/nemo-window-bookmarks.h M src/nemo-window-menus.c M src/nemo-window-private.h M src/nemo-window.c commit 03c5612730d4de29d8cb80352b1bfc42bab59742 Author: Cosimo Cecchi Date: 2010-05-06 Make NemoBookmarkList a singleton. M src/nemo-bookmark-list.c commit 00035932b2948140d95f27a473be380f189caf21 Author: Fran Diéguez Date: 2010-05-04 Updated Galician translation M po/gl.po commit 997028e6669062537b2f8ec2ce0fad2854f114b3 Author: Jorge González Date: 2010-05-04 Updated Spanish translation M po/es.po commit e6a7039162d4eb37afe329cc4d8378f9edb446c7 Author: Cosimo Cecchi Date: 2010-05-04 Release 2.31.1. M NEWS M po/POTFILES.in commit c0f8096150ea98af40248a55d6dbb77a35c0a771 Author: Jorge González Date: 2010-05-03 Updated Spanish translation M po/es.po commit abade38f2477bc807246d5b4acf8b7a753ea369e Author: Jorge González Date: 2010-05-03 Updated Spanish translation M po/es.po commit 64524ff2724bb6f0cc72fea34cb7ca3d5253cec7 Author: Cosimo Cecchi Date: 2010-05-03 Use header capitalization for "Open With" menu items (#596778). As the HIG says so. M src/file-manager/fm-directory-view.c M src/nemo-information-panel.c commit 79e155aba54ee7cfeac9363548d6b1cee221ae2f Author: Cosimo Cecchi Date: 2010-05-03 Don't give input focus to the selectable label (#591902). M src/nemo-image-properties-page.c commit e0f463562e894a2f394279d00fdf027343d2efad Author: Cosimo Cecchi Date: 2010-05-03 Change "Stretch Icon" to "Resize Icon" (#459900). M src/file-manager/fm-icon-view.c commit 5348820067ab62dd3fcac78f0acc0fef869cc2a1 Author: Cosimo Cecchi Date: 2010-05-02 Use "Cancel" as default response when activating a broken link (#341595) M libnemo-private/nemo-mime-actions.c commit fe817911c538f1018d73945af9d637e01943378b Author: Cosimo Cecchi Date: 2010-05-02 Don't force a default response. M eel/eel-stock-dialogs.c commit 846dd7c0e50b0f2db288285e615698932cf81e41 Author: Kjartan Maraas Date: 2010-05-02 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 1eac7a19cd7c4f543408809d0c0875bec849a494 Author: Fran Diéguez Date: 2010-05-01 Updated Galician translation M po/gl.po commit 777a404b76c0bcb3c3504fa9ff986c256777be8d Author: Torstein Adolf Winterseth Date: 2010-05-01 Updated Norwegian Nynorsk translation M po/nn.po commit 2a87565bcb810597dca323a943c616075ee7c6ab Author: Cosimo Cecchi Date: 2010-04-29 Let the sidebar header fill the whole width (#463111). The code for this is borrowed from Evince's sidebar implementation. M src/nemo-side-pane.c commit b281985fff427982420b7d037dff609383b3ea74 Author: Cosimo Cecchi Date: 2010-04-29 Don't let the sidebar shrink more than its requisition (#311732). This also makes us consistent with the other GNOME apps that use a sidebar widget. M src/nemo-navigation-window.c commit 842c94dbdd20bff3e9dcc1811b6e900d8d27d775 Author: Jorge González Date: 2010-04-29 Updated Spanish translation M po/es.po commit 90b32ff314a141417c2b8e3691766910420ca25e Author: Cosimo Cecchi Date: 2010-04-28 Don't ignore the return value of write() (#617092). M src/nemo-application.c commit 3683288f8a86cd714623cca3d6921315c67ec7f1 Author: Cosimo Cecchi Date: 2010-04-28 Add a 'Restore Selected Items' button in the trashbar. This makes the restore function more visible in the UI (#616304). M src/nemo-trash-bar.c M src/nemo-trash-bar.h M src/nemo-window-manage-views.c commit b87911c0caf3d957fc4e9575fd905493829f787c Author: Cosimo Cecchi Date: 2010-04-28 Move restore_from_trash() in nemo-file-utilities. This is needed so we will be able to use the function from the trash bar later. M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file-utilities.h M src/file-manager/fm-directory-view.c commit a7792d030df5f2139043f7228cb0f30bf1cdf5c1 Author: Jorge González Date: 2010-04-27 Updated Spanish translation M po/es.po commit 02ef15eabeef5cdbcb479adad90632ff12d2b791 Author: Cosimo Cecchi Date: 2010-04-27 Properly update icons as we load the thumbnails. M libnemo-private/nemo-file-conflict-dialog.c commit 9ecdac9b1a4adb3db9ac32606ff36023a3d6909e Author: Cosimo Cecchi Date: 2010-04-27 Fix size requests and wrap modes for labels. M libnemo-private/nemo-file-conflict-dialog.c commit 430d554f55632475dac94a7a9d6009c0f189b178 Author: Cosimo Cecchi Date: 2010-04-27 Initialize variables to NULL. M src/nemo-places-sidebar.c commit 47ad2649dc83faf1b3931d93d5060729344de955 Author: Cosimo Cecchi Date: 2010-04-27 Use a new icon for audio preview (#614907). Thanks to Hylke Bons for the icon. M icons/audio.svg M libnemo-private/nemo-icon-canvas-item.c commit 96a7a6bb7aa680d98f0bb05d77aa6101c25fb491 Author: Jorge González Date: 2010-04-27 Updated Spanish translation M po/es.po commit 46124f684e5db4bd05bc9575eef2b16527d58b66 Author: Cosimo Cecchi Date: 2010-04-27 Bump libnemo-extension API version (#610356). M configure.in commit 4b680e163e41a26c8ace47d43efdc72be9ede93a Author: Cosimo Cecchi Date: 2010-04-27 Don't use C++ keywords in NemoMenu (#616657). M libnemo-extension/nemo-menu.c M libnemo-extension/nemo-menu.h commit eee505e416678ce7f51999b6a4acd385a0ae99c7 Author: Cosimo Cecchi Date: 2010-04-27 Bump version to 2.31.1 on master. M configure.in commit add025f7d1502d97062a9fdce8eff85fcd27205e Author: Martin Pitt Date: 2010-03-30 Do not show Unmount when showing Eject/Safe removal Having three menu entries (unmount/eject/safe removal) in a volume/drive menu entry is too confusing. Unmount only really makes sense for internal drives, for external ones it is pretty much a "geek" option. Geeks can use palimpsest or "unmount /media/foo" from the CLI if they really want to, for everyone else it is just an unintuitive and hard to to explain menu entry. Bug: https://bugzilla.gnome.org/show_bug.cgi?id=598690 Bug-Ubuntu: https://launchpad.net/bugs/453072 (cherry picked from commit 0a5cc4c4e5b01eb8aa38dfae926502ce920efc94) M src/file-manager/fm-directory-view.c M src/nemo-places-sidebar.c commit cee1ced8e45dc9570308ba447f8e3c0edfd986ba Author: Cosimo Cecchi Date: 2010-04-15 Use display names for applications (#611378). Instead of using the simple GAppInfo name property. M libnemo-private/nemo-autorun.c M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-mime-application-chooser.c M libnemo-private/nemo-open-with-dialog.c M libnemo-private/nemo-program-choosing.c M src/file-manager/fm-directory-view.c M src/nemo-information-panel.c M src/nemo-x-content-bar.c commit 9192dd8faffd788acf54a3b98de48cd1252dd9a6 Author: Cosimo Cecchi Date: 2010-04-15 Properly set the application as default (#605814). When the checkbox is enabled in the Open With dialog, set that application as default; it the checkbox is not enabled, add the application to the supported list. M libnemo-private/nemo-open-with-dialog.c commit 3d82f47ee91f5e0ca3284aef55911bace0736243 Author: Cosimo Cecchi Date: 2010-04-26 Don't mark the regex for translation. M src/file-manager/fm-directory-view.c commit 4dd3fc4731a313803c776ee096478a6f60ef5a72 Author: Marcus Carlson Date: 2009-10-05 Adds legend to "Select Items Matching" dialog https://bugzilla.gnome.org/show_bug.cgi?id=301690 M src/file-manager/fm-directory-view.c commit a7336c72c6f6cc0b0340e218fd123bcdddb144b9 Author: Cosimo Cecchi Date: 2010-04-26 Always set the parent window in dialogs (#573788). M eel/eel-stock-dialogs.c M libnemo-private/nemo-mime-actions.c commit d63623cee6ac5cbbb74f6f31a7afa660d2037cbe Author: Cosimo Cecchi Date: 2010-04-09 Focus and sensitivity fixes. M libnemo-private/nemo-file-conflict-dialog.c commit 7e9ec46e34c899cae0eb92aabe9c826ea2abc5c6 Author: Cosimo Cecchi Date: 2010-04-09 Focus the entry after clicking on 'Reset'. M libnemo-private/nemo-file-conflict-dialog.c commit 5423c9f36cea27fac78d2fa7fee75c20a0a44d3e Author: Cosimo Cecchi Date: 2010-04-09 Tweak UI according to usability suggestions. This includes the addition of a reset button, use a single Replace/Rename button and some smaller UI candies. M libnemo-private/nemo-file-conflict-dialog.c commit e1d7563733075cd0302951db45b645bee9f71cdb Author: Cosimo Cecchi Date: 2010-04-09 Reverse broken logic. M libnemo-private/nemo-file-conflict-dialog.c commit 33da32efab246804efb745c0f9c63d88574cf5d0 Author: Cosimo Cecchi Date: 2010-04-08 Remove manual markup. Now that we use Pango to make the string bold, this is useless. M libnemo-private/nemo-file-conflict-dialog.c commit b9640f4cb9b24b567e44f7f87b75f59bddf2f073 Author: Cosimo Cecchi Date: 2010-04-08 Make the primary label bold. For that, use the same code from GtkMessageDialog. M libnemo-private/nemo-file-conflict-dialog.c commit e1a6a08cbff7884635b2e6478171c85ce555b999 Author: Cosimo Cecchi Date: 2010-04-08 Specify which file is older. That's valuable information, so display it clearly in the secondary label of the conflict dialog. M libnemo-private/nemo-file-conflict-dialog.c commit 067619c9c6fa155ff5dfff2b94f5f70e1a52dc4c Author: Cosimo Cecchi Date: 2010-04-08 Make sure NemoFiles are ready. M libnemo-private/nemo-file-conflict-dialog.c commit e84883bde6919d8bcbbc93713c80f3d537131d4e Author: Cosimo Cecchi Date: 2010-04-08 Show the file type only if it's different. Also, don't hardcode markup in strings marked for translations, as i18n don't usually like it. :) M libnemo-private/nemo-file-conflict-dialog.c commit 148dfd2b8d5492b7c9b4824133537d812782ea62 Author: Cosimo Cecchi Date: 2010-04-08 Fix indentation. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-conflict-dialog.h M libnemo-private/nemo-file-operations.c commit 8734e4268b74935aaa5418ee567340fdfd2b953f Author: Cosimo Cecchi Date: 2010-04-08 Fix a conflict after rebase. M libnemo-private/nemo-file-operations.c commit 5d5166d2cdc68ccee3cacd9d0c266de0f0bee3f5 Author: Cosimo Cecchi Date: 2009-04-22 Swap the order of files in the dialog The dialog had the source and destination files wrongly ordered, swap them. M libnemo-private/nemo-file-conflict-dialog.c commit d8a11018692ec20a8ec6a3dcb1f2d942dcb72a90 Author: Cosimo Cecchi Date: 2008-04-23 Use NemoFile machinery instead of is_dir Use the NemoFile cached data to find out whether a file is a directory instead of using GIO. M libnemo-private/nemo-file-conflict-dialog.c commit 7e44bab4b8910bb26a91fc09a8e3b0cd12455bf8 Author: Cosimo Cecchi Date: 2009-04-22 Implement support for rename in the operations code Act accordingly to a rename response from the conflict dialog. M libnemo-private/nemo-file-operations.c commit 95016daa49bdd8b951dd0fa500b9634e12e91856 Author: Cosimo Cecchi Date: 2009-04-22 Adapt the file operations code to use the new dialog Cut out of the file operations module, the code used to display conflict dialogs. Use the new dialog instead. Rename is not working yet. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-operations.c commit dc21af1dc03759661fea147a8b98a8772749b29e Author: Cosimo Cecchi Date: 2008-04-03 Implement responses from the dialog back to the file operation. Add some API to get the response type from the conflict dialog back to the file operations code. Start using that API during the operations accordingly. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-conflict-dialog.h M libnemo-private/nemo-file-operations.c commit bf607e6e3045dff76128894e87cd42affb68a44c Author: Cosimo Cecchi Date: 2008-04-03 HIG fixes Make sure the UI doesn't suck too much. M libnemo-private/nemo-file-conflict-dialog.c commit 2048c2d61db6ec557b6b572fb635a0f5a11bab09 Author: Cosimo Cecchi Date: 2008-04-02 Finish implement icon boxes in the dialog. Finish implement icon boxes in the conflict dialog. Add a main thread runner from inside the file operations, as the operation itself is done in an I/O worker thread. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-operations.c commit fee8b5095521fb6db98f866f6e0d53e8cf381783 Author: Cosimo Cecchi Date: 2008-04-02 UI and HIG fixes Use the correct markup strings in the dialog, and take care of some layouting issues. M libnemo-private/nemo-file-conflict-dialog.c commit 6f0dc097348f7c2d0ede26daf5e76634a6625db3 Author: Cosimo Cecchi Date: 2008-04-02 Use a GtkDialog. Use a GtkDialog instead of a GtkMessageDialog. Take care of some HIG fixes, and try to use icons from NemoFile. M libnemo-private/nemo-file-conflict-dialog.c M libnemo-private/nemo-file-conflict-dialog.h commit 68ac5db7bcb762bcea612239c4a9d6408924a7b2 Author: Cosimo Cecchi Date: 2008-04-02 First implementation of NemoFileConflictDialog Basic UI implementation of NemoFileConflictDialog. Add it to Makefile.am. Also, hook the dialog inside the relevant file operations and load it at the right place when doing a file operation. M libnemo-private/Makefile.am A libnemo-private/nemo-file-conflict-dialog.c A libnemo-private/nemo-file-conflict-dialog.h M libnemo-private/nemo-file-operations.c commit ce66d5d2bf1b3c028f08d1f3ed3fa6d4c7c633f1 Author: Cosimo Cecchi Date: 2010-04-12 Don't use Backspace to delete bookmarks. In the places sidebar, don't assign Backspace to deleting bookmarks, as that's confusing (and we already have Delete for it). Fix bug #340934. M src/nemo-places-sidebar.c commit a051ce374f38b1dc13663f7a099337f39302c5b2 Author: Cosimo Cecchi Date: 2010-04-12 Always return TRUE from drop-motion. Fixes the displaying of a black line when DnD-ing something in the sidebar which is not supported (#432529). M src/nemo-places-sidebar.c commit b80bfe38ac1cc4fd3561961d7f6f8b43ec786f20 Author: Cosimo Cecchi Date: 2010-04-12 Refactor the load/save code for the list. Don't use sync i/o anymore. This should also fix bug #532911. M src/nemo-bookmark-list.c M src/nemo-bookmark-list.h commit 721f9999bcac87f28780d0b6938dac66b04970f2 Author: Cosimo Cecchi Date: 2010-04-12 Bring the object to 2010. M libnemo-private/nemo-bookmark.c M libnemo-private/nemo-bookmark.h M src/nemo-bookmark-list.c M src/nemo-bookmark-list.h commit 5d84350777a40f53ae3970f2acbafb5846cb1c94 Author: Cosimo Cecchi Date: 2010-04-12 Set rate limit to the file monitor. M src/nemo-bookmark-list.c commit 2d64615521d9d6a090ef9a296e7783a73edc1f68 Author: Cosimo Cecchi Date: 2010-04-11 Remove dead code. M src/nemo-places-sidebar.c commit 006f5164b7ce1bf54fed170800ed145eb625826e Author: Cosimo Cecchi Date: 2010-04-11 Use the new NemoBookmarksList API. M src/nemo-places-sidebar.c commit 5b80a0e60516518f359596b5d6285b241d7c6cad Author: Cosimo Cecchi Date: 2010-04-11 Add a method to move bookmarks in the list. So that moving a bookmark in the list doesn't trigger two 'contents-changed' signals in a row. M src/nemo-bookmark-list.c M src/nemo-bookmark-list.h commit c87d0252bbd028ef80c3460be737c4e8ae07aa62 Author: Cosimo Cecchi Date: 2010-04-26 Preserve last selection while updating places. M src/nemo-places-sidebar.c commit 6b768ef18298bd8048f13e50094f5777b2b7e07b Author: Cosimo Cecchi Date: 2010-04-11 Use 'button-release-event' to activate bookmarks. Instead of using the 'row-activated' signal. This allows us to only open the bookmark after DnD (#606097). M src/nemo-places-sidebar.c commit 60b27c11e0dd3416eee13bdea45b280ec2562a36 Author: Cosimo Cecchi Date: 2010-04-13 Migrate confguration to XDG_CONFIG. https://bugzilla.gnome.org/show_bug.cgi?id=601476 M src/nemo-application.c commit 3c98314f94086dd241ca48bedee112d83733c183 Author: Cosimo Cecchi Date: 2010-04-13 Don't use ~/.nemo anymore (#601476). But use XDG_CONFIG to save configuration files. Patch by jarryson. M libnemo-private/nemo-file-utilities.c commit a09d41702b771fb0041fa0c4270afaa678413a2d Author: Cosimo Cecchi Date: 2010-04-13 Remove deprecated GTK+ symbols (#565038). M eel/eel-background.c M eel/eel-canvas.c M eel/eel-debug-drawing.c M eel/eel-editable-label.c M eel/eel-gtk-container.c M eel/eel-gtk-extensions.c M eel/eel-image-table.c M eel/eel-labeled-image.c M eel/eel-wrap-table.c commit 2e79c499851757bf6da55c735268e36fcc4f2552 Author: Alexander Larsson Date: 2010-04-26 Update NEWS for release M NEWS commit 7411a0f07a6505ca5205a819b2539fe95bb1a1c0 Author: Andy Owen Date: 2010-04-26 Update split view menu item sensitivity when closing extra pane M src/nemo-navigation-window.c commit 39547f935a4f766eece11513eee175fffcbad2c1 Author: Andy Owen Date: 2010-04-26 Don't crash if there is no next_pane This happened due to menu sensitivity being wrongs (bug 616179) M src/nemo-navigation-window-menus.c commit bae7b352ae02233e5f3368818bf4daa864ad9a2e Author: Mattias Põldaru Date: 2010-04-26 Estonian translation updated M po/et.po commit dae9a5f81eec0ea5ededecb4375ca76c8f3ed9d1 Author: Maxim V. Dziumanenko Date: 2010-04-24 Updated Ukrainian translation M po/uk.po commit bf052548334dc7eae0b01131a4771c9fc34301f6 Author: Maxim V. Dziumanenko Date: 2010-04-22 Updated Ukrainian translation M po/uk.po commit 3c336f6968ed198c89eaeeae8d44a71312b5682b Author: Carles Ferrando Date: 2010-04-21 Updated Catalan (Valencian) translation M po/ca@valencia.po commit 17e388240fd5947cf21081c1d3971b2c9a66eeb1 Author: Shankar Prasad Date: 2010-04-21 Updated the kn translations M po/kn.po commit 2514148ef1a3d8a22caeb2f80989d29441e816e0 Author: Jorge González Date: 2010-04-17 Updated Spanish translation M po/es.po commit 32327339b335e71f661f5f51c6f66ddb95cbd099 Author: Paolo Borelli Date: 2010-04-17 Do not use "if (spatial) ..." in window superclass Delegate behavior specific to the window type to an appopriate subclass method. M src/nemo-application.c M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit 90c1b707ce4ab0a96dc4200537ef9fae17e45e60 Author: Andika Triwidada Date: 2010-04-17 Updated Indonesian translation due bug #569491 M po/id.po commit fc18d0bfc4f6001be311be63993a90129f02520a Author: Holger Berndt Date: 2010-04-06 Let w close the extra pane The keybinding w closes the active slot until no slot is remaining, in which case it closes the window. This commit includes the extra pane layer in this chain. Fixes bug 615593 M src/nemo-window-pane.c M src/nemo-window.c commit 719c524c571fc0742382bff1c04174bb585326b8 Author: Manoj Kumar Giri Date: 2010-04-16 Updated Oriya Translation M po/or.po commit 85c0047c370b06473026b2920dc53428bd3c30ae Author: Holger Berndt Date: 2010-03-22 Fix sensitivity of "{Copy|Move} to other pane after enable/disable of extra pane" Add an "update_menus" signal to the NemoView interface, so that external events can trigger a menu sensitivity update. Fixes bug 613257. M libnemo-private/nemo-view.c M libnemo-private/nemo-view.h M src/file-manager/fm-directory-view.c M src/nemo-navigation-window-menus.c commit 543d3ddd5131546fbbb2e3e2a504d9800c4f0d62 Author: Peteris Krisjanis Date: 2010-04-15 Updated Latvian translation. M po/lv.po commit 1ec432f114b357822256349b85c7401d1ade4cf5 Author: Runa Bhattacharjee Date: 2010-04-15 Updated Bengali India Translation M po/bn_IN.po commit 183b65d95d7c6418ba74104e6c718572ae518af3 Author: Andika Triwidada Date: 2010-04-15 Updated Indonesian translation M po/id.po commit 00de9e84618738f2f41c5ac5e01e7bddc953423b Author: ReÅŸat SABIQ Date: 2010-04-14 Minor update for Crimean Tatar/Turkish translation M po/crh.po commit 9a45cd408e177c49bfbd7bced2f117c2b5f87e75 Author: Yannig Marchegay Date: 2010-04-14 Updated Occitan translation M po/oc.po commit 7fb83086b3c39aa6555b3fe2b0c3a59449cab5f2 Author: Yannig Marchegay Date: 2010-04-14 Updated Occitan translation M po/oc.po commit 73fc9b35508b3be5d959c568e92ae6870817dee2 Author: Yannig Marchegay Date: 2010-04-14 Updated Occitan translation M po/oc.po commit 27850a638a0075fb35b49c0621363bcb9ffd50d3 Author: Ani Peter Date: 2010-04-14 Updated Malayalam Translation M po/ml.po commit d88eca5a81988d62fbcbcc60037abbaae124b407 Author: Sandeep Shedmake Date: 2010-04-14 Updated Marathi Translations M po/mr.po commit 95b2c6e322a9bd15320fd6cdb37394e645b85ef4 Author: Yannig Marchegay Date: 2010-04-13 Occitan translation update M po/oc.po commit 89953c7140b285cc27a0dc4f8a771a58bee21e20 Author: Yannig Marchegay Date: 2010-04-13 Occitan translation update M po/oc.po commit 36586cd1ad3f0c12c707f052964b3c188343e78a Author: Francisco Diéguez Date: 2010-04-09 Updated Galician translations M po/gl.po commit cb4097700ddfc5992544528cc4e412ec345131aa Author: Tomas Bzatek Date: 2010-04-09 Tracker: Fix filtering by location, code cleanup This also involves code cleanup to maintain consistency with gtksearchenginetracker.c Related: bug 612725 M libnemo-private/nemo-search-engine-tracker.c commit 31b4b4adda7a9da23b611966176c7f7b7ae552cd Author: Cosimo Cecchi Date: 2010-04-09 Don't use LDFLAGS for the eel library. libeel is a convenience library now, so it should pull its dependecies using LIBADD, not LDFLAGS. Patch by Josselin Mouette (#604575). M eel/Makefile.am commit 496d3f15de295482e158194e1fe1dae3569f4524 Author: Cosimo Cecchi Date: 2010-04-09 Use gtk_widget_get_state() (#612423). Instead of the deprecated GTK_WIDGET_STATE macro. Patch by Dominique Leuenberger. M eel/eel-editable-label.c M eel/eel-gtk-extensions.c M eel/eel-labeled-image.c commit 305cf9768bd716ba9bbcd3e773511536243a9cc5 Author: Marcus Carlson Date: 2010-04-07 Fix emblem scaling with zoom >= 150% Emblem handling did not properly take zoom into account (#343540) M libnemo-private/nemo-icon-canvas-item.c commit 263051df98aace0b59fb2bd1772711dceba8e404 Author: Marcus Carlson Date: 2010-04-07 Fix crash when middle click on an invalid network share in Places https://bugzilla.gnome.org/show_bug.cgi?id=579627 M src/nemo-window-manage-views.c commit 1698377dcad6762bc0b32c4efa75d7e2c4b3fb67 Author: Tomas Bzatek Date: 2010-04-06 Support for tracker 0.8 stable release M libnemo-private/nemo-search-engine-tracker.c commit 323124d88ba4bf2d39466ee11c3f166ffebb0a01 Author: Sweta Kothari Date: 2010-04-06 Updated Gujarati Translations M po/gu.po commit ae2b3bffcb1bb5f333bc6654af3c0a3719d50b70 Author: Jordi Serratosa Date: 2010-04-02 Fixes to Catalan translation M po/ca.po commit 1b252c84a9f1efaab652679f2511d5d5a63593f4 Author: Wouter Bolsterlee Date: 2010-03-30 Dutch translation updated by Wouter Bolsterlee M po/nl.po commit 09b695b4cab81b239a3934e6c53222299fc61137 Author: Jordi Serratosa Date: 2010-03-29 Fixes to Catalan translation M po/ca.po commit 3bdca4a2c5720e239a8947348b8390da0ac7b998 Author: Alexander Larsson Date: 2010-03-29 Post release version bump M configure.in commit e414801ab9c3baba23ce82df02f59ec7fdf2f7d8 Author: Alexander Larsson Date: 2010-03-29 Bump version to 2.30.0 M configure.in commit 8174126cad82d54b25b40b883aa05d0a13abdc44 Author: Alexander Larsson Date: 2010-03-29 Require stable versions of glib/gtk+ M configure.in commit 8972aad5f0fc3f6346000845770239d39c0fd63b Author: Alexander Larsson Date: 2010-03-29 Update for release M NEWS commit 6364bbbbea855bcd5f507d08e4270956aed4083a Author: Runa Bhattacharjee Date: 2010-03-29 Typo correction and updation M po/bn_IN.po commit 313ee0e2b19d5850bbc62dae73fe315b4c450277 Author: Jamil Ahmed Date: 2010-03-27 Updated Bengali translation M po/bn.po commit be4461243fdf084bd1a2c466fd3b196e134439d7 Author: Maxim V. Dziumanenko Date: 2010-03-26 Updated Ukrainian translation M po/uk.po commit 94127c6f6c553849c033ce06e0eb3fa8a837d994 Author: Timo Jyrinki Date: 2010-03-26 Separate ejecting from safely removing and link to the relevant bug report. M po/fi.po commit 0fe43b73226164ac381d48e167c15035161f7e19 Author: Gabor Kelemen Date: 2010-03-26 Updated Hungarian translation M po/hu.po commit f9f46d46040e97f802e530706248d39a2daf99cc Author: Simos Xenitellis Date: 2010-03-25 Updated Greek translation for nemo M po/el.po commit de23258a5b70b7237cf972b4689731763eb19ebf Author: Cosimo Cecchi Date: 2010-03-25 Use a better thumbnail frame for image previews. Thanks to Hylke Bons for working on this. Closes bug #613858. M icons/thumbnail_frame.png M libnemo-private/nemo-thumbnails.h commit acb01f0fe637a64f92c1ff2188879b7c470ed0e0 Author: Tomas Bzatek Date: 2010-03-24 Unref local query object when turning search off M src/nemo-navigation-window-menus.c commit a92a7bfcb2c7bb9f171724bc97b1c163f52c0fd7 Author: Tomas Bzatek Date: 2010-03-24 Don't crash when hiding search bar with no text Happens in browser mode and only when search results pane is displayed M src/nemo-navigation-window-menus.c commit 4702bc8e74248de734c2fbcddd57191ba2fc1bd1 Author: Fran Diéguez Date: 2010-03-24 Updated Galician translation M po/gl.po commit 4297995df518bc17f5b3de9889c655c35eb05fbf Author: Inaki Larranaga Murgoitio Date: 2010-03-24 Updated Basque language M po/eu.po commit 9b458e52b43a87c0b5ff13a0634c18dc6328de8a Author: A S Alam Date: 2010-03-24 update for Punjabi by A S Alam M po/pa.po commit ffadc713c20db01c3678f947f510565affcd4887 Author: Anders Jenbo Date: 2010-03-23 Updated Danish translation M po/da.po commit 81709b3bba3630fdee8577453820a353b4757aed Author: Simos Xenitellis Date: 2010-03-23 Updated Greek translation for nemo M po/el.po commit 14b652632c63b586bf32ae6a7a0599da459fcc4a Author: Nikos Bakaoukas Date: 2010-03-23 Updated Greek translation for nemo M po/el.po commit 5bbd6545ac0114e2a6962079fdbcaae5bbe84b78 Author: Tommi Vainikainen Date: 2010-03-22 Updated Finnish translation M po/fi.po commit c18f16106fe0cf6b9c139c61728f6f5233ca0737 Author: Luke Symes Date: 2010-03-14 Don't display a border around the desktop frame. Fixes bug 605704. M src/file-manager/fm-desktop-icon-view.c commit 0a53599124a8d57b5d6ccdb8694da10bea8313d7 Author: ReÅŸat SABIQ Date: 2010-03-18 Updated Crimean Tatar (Crimean Turkish) translation M po/crh.po commit e0b4fd622a4eb31a3d9af56bb0b2d5c1fd7e3d06 Author: Bastien Nocera Date: 2010-03-17 Add AIFF as a supported audio type for preview M src/file-manager/nemo-audio-mime-types.h commit ba6a7c6e1098c5cb88fb7468e98bf9f58ff6b543 Author: Alexander Larsson Date: 2010-03-17 Set exit_with_last_window to false by default This fixes problems with show_desktop=false causing nemo to exit and gnome-session restarting nemo in a loop (#571417). This means nemo will keep running, so that it can handle automount and stuff. If you only run nemo rarely you need to set this to true. In the future we will move the automount handling to gnome-settings-daemon and then we will probably change this back. M libnemo-private/apps_nemo_preferences.schemas.in commit dfa7758c96580e06261756b6f49433befec677c4 Author: Inaki Larranaga Murgoitio Date: 2010-03-16 Updated Basque language M po/eu.po commit 1ab3721437d8371301079023c10dfa14c0eb5b5d Author: Inaki Larranaga Murgoitio Date: 2010-03-15 Updated Basque language M po/eu.po commit e61a5c23dce6af7861628ace3fb049d9a0d4c8e8 Author: Petr Kovar Date: 2010-03-15 Update Czech translation by Lucas Lommer M po/cs.po commit 863a13e1dbbcee2d7405f17b3eef6db93df437df Author: Ivar Smolin Date: 2010-03-14 Estonian translation updated M po/et.po commit e3ea8ba00461ccd43716c1360215d4d44e4fa872 Author: Fran Diéguez Date: 2010-03-13 Updtae Galician translation M po/gl.po commit 68dbac28c64ea365a09b7cbc58fba0434fad8a34 Author: Luca Ferretti Date: 2010-03-12 Updated Italian translation M po/it.po commit 797cacb28b78fede43b713dbd1fba2479bdbe943 Author: Holger Berndt Date: 2010-03-11 Remove grab_focus from list view The grab_focus interface function is now implemented in the directory view. There's no need for special handling of list views anymore. M src/file-manager/fm-list-view.c commit c78da8903804267ef7399d92753c5f5b2e811585 Author: Holger Berndt Date: 2010-03-11 Fix focus handling Move the focus to a new window's first slot. The extra pane doesn't get focus initially, which fixes bug 612203. To make this work for all views, the focus_grab interface function was implemented for the directory view class. M src/file-manager/fm-directory-view.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 34807782c143f99f0ab94dd4a1804239a5710d1a Author: Holger Berndt Date: 2010-03-11 Bring back "Don't grab focus on realize" This brings back commit 4efd42312584b46f248e2839582a87776a7baebe that was reverted in 95ae539e8d042b04ee9c6817bcc41f551ab207fc The focus issues that this introduces will be taken care of in a followup commit. M libnemo-private/nemo-icon-container.c commit dde8fff965302b2d73f3aed81d19e6f93a7c6334 Author: Padraig O'Briain Date: 2010-03-11 Don't use inline keyword Its unnecessary and breaks on e.g. sun compilers. M src/nemo-navigation-window.c M src/nemo-navigation-window.h commit c25488049229c725dde566d9c37e90c0122a6dd2 Author: Gabor Kelemen Date: 2010-03-11 Updated Hungarian translation M po/hu.po commit 44ea265c75a6cf54145002d9323b8bec52f76e3d Author: Tomas Bzatek Date: 2010-03-10 Update for 2.29.92.1 M NEWS M configure.in commit 8c8cf192d861a1a6c202624ee0b4c0ff43077080 Author: Tomas Bzatek Date: 2010-03-10 Fix compilation due to deprecated GTK_WIDGET_STATE symbol Also see https://bugzilla.gnome.org/show_bug.cgi?id=69872#c87 M libnemo-private/nemo-tree-view-drag-dest.c commit fab5d01888eb08e3721db7331011534e40afe24e Author: Duarte Loreto Date: 2010-03-10 Updated Portuguese translation M po/pt.po commit 2d40fbadb053bc7ad0d988050e58a81bfc3ea08b Author: Tomas Bzatek Date: 2010-03-09 Fix libm linking Nemo was underlinked, found by recently introduced change in Fedora: https://fedoraproject.org/wiki/Features/ChangeInImplicitDSOLinking /usr/bin/ld: ../libnemo-private/.libs/libnemo-private.a(eel-canvas.o): undefined reference to symbol 'floor@@GLIBC_2.0' /usr/bin/ld: note: 'floor@@GLIBC_2.0' is defined in DSO /lib/libm.so.6 so try adding it to the linker command line /lib/libm.so.6: could not read symbols: Invalid operation M configure.in commit 4df08e047b42ae4d11cd1edbbb7e99f95ae1b326 Author: Tomas Bzatek Date: 2010-03-08 Remove obsolete defines M configure.in commit 02afb2f5f2b95185c42ecac87af089a8ca8488ab Author: Alexander Larsson Date: 2010-03-08 Bump version to 2.29.92 M configure.in commit 7d79c4ad6db9a39ca6d37bb7eadd95ff84ac2af5 Author: Alexander Larsson Date: 2010-03-08 Update NEWS for release M NEWS commit b6958cb2d9e699c3a81ab39b9aa7766f6070a832 Author: Alexander Larsson Date: 2010-03-08 Don't close the window you initiated an unmount in. Based on patch from Luke Symes M src/nemo-application.c M src/nemo-navigation-window-slot.c commit 80dd8fb8ff0df3aa32314c633b04173517da3a36 Author: Alexander Larsson Date: 2010-03-08 Set initiated_unmount on windows while unmounting M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/nemo-places-sidebar.c commit 5e7f95842228f289b2940f23e63a2dd3b2cca842 Author: Alexander Larsson Date: 2010-03-08 Always call back from nemo_file_unmount/eject, even on success M libnemo-private/nemo-file.c commit 7fb5d7f6e4c32ab391eb9f3a61c0cab59c585874 Author: Alexander Larsson Date: 2010-03-08 Add nemo_file_operations_unmount_mount_full with a callback M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-operations.h commit 43f080c97369796043e45719933f536e0b29582f Author: Luke Symes Date: 2010-03-08 Implement the initiated_unmount property for NemoWindow. Windows will have this set to TRUE when one of their slots initiates an unmount. https://bugzilla.gnome.org/show_bug.cgi?id=611569 M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/nemo-window-private.h M src/nemo-window.c commit e1e1fe0d505bdb9b53d7204bba0abeee52f73bca Author: Tomas Bzatek Date: 2010-03-08 Load tracker/beagle at runtime Dynamically load tracker (preferred) and beagle client libraries on demand if available. This allows more flexibility for packagers and users. See bug 589345 for details. M configure.in M libnemo-private/Makefile.am M libnemo-private/nemo-search-engine-beagle.c M libnemo-private/nemo-search-engine-tracker.c M libnemo-private/nemo-search-engine.c commit bbe632e641df6f184de338b8215e390139adc573 Author: MiloÅ¡ Popović Date: 2010-03-07 Fixed typo in Serbian translation M po/sr.po M po/sr@latin.po commit e9e1dbc188983bac428bade85becbfea079306a0 Author: MiloÅ¡ Popović Date: 2010-03-07 Updated Serbian translations M po/sr.po M po/sr@latin.po commit 8217aa1931ed6f275d3651003fe3e599baaf8245 Author: Christian Kirbach Date: 2010-03-06 Updated German translation M po/de.po commit a6715be7e462109020f8450fe9781ea70e5ca128 Author: Holger Berndt Date: 2010-03-05 Bring back + for tab changing Make the first 10 tabs of every pane changable via keyboard shortcuts +1, +2 etc. This brings back non-GUI functionality that was removed together with the tab menus in e156e39e07276a4de8414bfdb82340f8762060b4 Fixes bug 609924 M src/nemo-navigation-window-menus.c commit 97ef4d40e6c743620e0629ee768b6df0effa61df Author: Kjartan Maraas Date: 2010-03-04 Updated Norwegian bokmÃ¥l translation M po/nb.po commit 4f870048b8d6754e29dd5ed0c4104f453caf7d3b Author: Rodrigo Moya Date: 2010-03-04 Replace deprecated GTK_WIDGET_* macros and depend on newer GTK+ M configure.in M libnemo-private/nemo-clipboard.c M libnemo-private/nemo-horizontal-splitter.c M libnemo-private/nemo-icon-canvas-item.c M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-progress-info.c M libnemo-private/nemo-tree-view-drag-dest.c M src/file-manager/fm-list-view.c M src/file-manager/fm-properties-window.c M src/file-manager/fm-tree-view.c M src/nemo-application.c M src/nemo-bookmarks-window.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c M src/nemo-notebook.c M src/nemo-pathbar.c M src/nemo-side-pane.c M src/nemo-spatial-window.c M src/nemo-window-manage-views.c M src/nemo-window.c M src/nemo-zoom-control.c commit af9305deb5a699fa430599685f25ad363d280808 Author: Leonid Kanter Date: 2010-03-04 Update Russian translation by Yury Kozlov M po/ru.po commit 4d742c83498df29d6f4b853dca946c0b4c4b13a3 Author: Alexander Larsson Date: 2010-03-03 Revert "Put tabs at the bottom" This reverts commit c6ee7553fd029239eff50d32dbcb57223ffa185e. We have gotten feedback that this experiment was not liked by users, so reverting. M src/nemo-notebook.c commit 7aad24446ce11d8508853cc0541590d3c8e0f99d Author: Umarzuki bin Mochlis Moktar Date: 2010-03-03 Update Malaj translation. Fixes bug 610519. M po/ms.po commit 95ae539e8d042b04ee9c6817bcc41f551ab207fc Author: Alexander Larsson Date: 2010-03-03 Revert "Don't grab focus on realize" This reverts commit 4efd42312584b46f248e2839582a87776a7baebe. We now don't store the extra view visible status, so the problem this change fixed is gone. And this change caused other focus issues, as per bug 607060. M libnemo-private/nemo-icon-container.c commit c8ded383147e0f860f9a206e9f45606bf16effe9 Author: Holger Berndt Date: 2010-02-25 Don't remember status of extra pane in a gconf key The focus for Nemo' split view mode are occasional, temporary switches to a split view mode for heavy-duty filebrowsing, not to be a permanent double pane filemanager. Therefore, neither split-view toggle status nor splitter position of a window are supposed to affect subsequently opened windows. See comments at bug 608431. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-navigation-window.c commit 0b6dd131e0d4d4ce7694b824e9925c1d021d9754 Author: Changwoo Ryu Date: 2010-03-01 Updated Korean translation M po/ko.po commit 82018666fb492bb423f4bcaccfa9bd50d868974d Author: Daniel Nylander Date: 2010-02-28 Updated Swedish translation M po/sv.po commit 582c1021a4b2f9039296a67bb45f8c3d51c327d5 Author: Piotr DrÄ…g Date: 2010-02-28 Updated Polish translation M po/pl.po commit 78ed12260a72967f7e1d135c4ffe7d51c44e3021 Author: Mario Blättermann Date: 2010-02-27 Updated German translation M po/de.po commit 1688fbbbcd1a55c7a731f65fdef31b9d7c90ed60 Author: Joan Duran Date: 2010-02-27 Updated Catalan translation M po/ca.po commit 533c274c00f1d6ab27b56e58363acd164e15d268 Author: Torstein Adolf Winterseth Date: 2010-02-27 Updated Norwegian Nynorsk translation M po/nn.po commit c7e51ada91e966af89b14c46f6fd20a4da0f5e3c Author: Bruce Cowan Date: 2010-02-24 Updated British English translation M po/en_GB.po commit 5dc02f0410a14b17bcdf74404b79c6b97a47c6e2 Author: Gintautas Miliauskas Date: 2010-02-23 Updated Lithuanian translation. M po/lt.po commit 64c484ae80012d120c3420f9fdd09915aaed32f4 Author: Alexander Shopov Date: 2010-02-23 Updated Bulgarian translation M po/bg.po commit 5f1d9d7b17a9b21d934d05e9c3e724a3ff3318a8 Author: Alexander Larsson Date: 2010-02-22 Require latest gnome-desktop for spanning bg M configure.in commit dd7f350e54b99c6644632062f44165e29a2fd8e6 Author: Alexander Larsson Date: 2010-02-22 Remove src/nemo-throbber.c from POTFILES.in M po/POTFILES.in commit 6b445d8c23b82327083ccd7a0254ccd5d001cfbc Author: Alexander Larsson Date: 2010-02-22 Update NEWS for release M NEWS commit d27a9a4260f76602a0c5e88706c1641e06515971 Author: Alexander Larsson Date: 2010-02-22 Use GtkSpinner instead of custom widget Forgot this part of the commit... M configure.in M src/Makefile.am M src/nemo-navigation-window.c M src/nemo-notebook.c M src/nemo-window-private.h M src/nemo-window-toolbars.c commit 07a6c14e4008e6ea131e5740485e8bd66547db3e Author: A. Walton Date: 2010-02-22 Use GtkSpinner instead of custom widget D src/ephy-spinner.c D src/ephy-spinner.h D src/nemo-throbber.c D src/nemo-throbber.h commit 472d7b454862e5a18a4e04f50162b1cfe41beb30 Author: Luke Symes Date: 2010-02-16 Go to computer:/// on unmount M src/nemo-application.c commit a3f5dde5051737beceeb6bc825758d0ecce1e3fd Author: Luke Symes Date: 2010-02-17 Fix location check in should_close_with_mount https://bugzilla.gnome.org/show_bug.cgi?id=318094 M src/nemo-navigation-window-slot.c commit 45f7cbb0bf331f6e99fc5cbb8dcc84f3b26455fa Author: vasudeven Date: 2010-02-21 updated Tamil translation M po/ta.po commit 8df9b4a10a31532c52f5fbc36f8dee60fa04948d Author: Alexandre Franke Date: 2010-02-20 Update French translation to show real last translator M po/fr.po commit e8099533621bdb3a24178ea05d5a88586259e319 Author: Alexandre Franke Date: 2010-02-20 Fixed French translation (closes bug 610365) M po/fr.po commit 47eaabdecb657c284366c1832206595e470242c6 Author: Khaled Hosny Date: 2010-02-19 Updated Arabic translation M po/ar.po commit 3de6a780cb9dde0c54537139a81ab8186b81ccde Author: Matthias Clasen Date: 2010-02-18 Make it possible to have backgrounds spanning multiple monitors. gnome-desktop added a new 'spanned' picture_option for this. This fixes bug 610396. M eel/eel-background.c M eel/eel-background.h M libnemo-private/nemo-directory-background.c commit 402f79e82c91b5129fa8fb11840d390a8527e2fb Author: vasudeven Date: 2010-02-18 updated Tamil translation M po/ta.po commit e570e2f6fd6ed73aa472d85409be2e01107caa5c Author: Rene Pärts Date: 2010-02-17 Estonian translation updated M po/et.po commit 5de7ed5ee5c9857615c2da8c6424fa99e365dc26 Author: Fran Diéguez Date: 2010-02-15 Updated Galician Translation M po/gl.po commit ecdea68af78c46fbf9b7ecfb77cc8f71f4cfb687 Author: vasudeven Date: 2010-02-15 updated Tamil translation M po/ta.po commit 6549e2e1ef18e20bd6023d645092ae7b3b735d2f Author: Ask H. Larsen Date: 2010-02-14 Updated Danish translation M po/da.po commit 467e375bc52d1ceb400534c5d9d2995de1b40789 Author: Claude Paroz Date: 2010-02-13 Updated French translation Contributed by Claude Paroz and Bruno Brouard M po/fr.po commit 8d7e2a397fe4a70707c9fb92a98c1dfe2b621e2e Author: Lucian Adrian Grijincu Date: 2010-02-13 Update Romanian translation M po/ro.po commit 662e19941905cf80a9131e56cefc4eab69f6e5da Author: Fran Diéguez Date: 2010-02-12 Updated Galician Translation M po/gl.po commit bbb9d918761c07e0711c058e7b8295b3d7079ff3 Author: Matej UrbanÄiÄ Date: 2010-02-11 Updated Slovenian translation M po/sl.po commit 862ba955f5f918eca3853faef00de67f1066c5c7 Author: Chao-Hsiung Liao Date: 2010-02-10 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit ef76f4421331a8575f43db2c4cd5b26a2f5952a2 Author: Tomas Bzatek Date: 2010-02-09 Post release version bump M configure.in commit 574b9a27bcb631dfa616e856f9f11131ddd1e150 Author: Tomas Bzatek Date: 2010-02-09 Update for 2.29.90 M NEWS M configure.in commit e302cf74e2374f3e3850b4341c3456199d520726 Author: Gabor Kelemen Date: 2010-02-08 Hungarian translation updated M po/hu.po commit 09c0a7dfeb8530dcf8cc871b7377d27e4c41c2bd Author: Theppitak Karoonboonyanan Date: 2010-02-08 Updated Thai translation. M po/th.po commit a38cc9eb354fb48f48c38501ccf649a9e3f412d5 Author: Henrique P. Machado Date: 2010-02-06 Updated Brazilian Portuguese translation M po/pt_BR.po commit 80ce7ee481d292fae620b878b1c83dd65d71dfbe Author: Jorge González Date: 2010-02-06 Updated Spanish translation M po/es.po commit ebca4f18692c06e8af724317a82328a84514e6b0 Author: Claude Paroz Date: 2010-02-06 Fix copy-pasted tooltip string M src/file-manager/fm-directory-view.c commit cd49c551d46a41d803d8bb76c7bef6d395e14369 Author: Jennie Petoumenou Date: 2010-01-31 Updated Greek translation M po/el.po commit fde78a67b016d7c59b86145ac31d6b46462ee1b0 Author: Mattias Põldaru Date: 2010-01-29 Updating Estonian translation M po/et.po commit cf6477ac9b5576ab0f28077d817388fc3b77637f Author: Jamil Ahmed Date: 2010-01-29 Updated Bengali translation M po/bn.po commit e7f8fdf47e421122a7d13703fd3ff6cb6cd14b82 Author: Alexander Shopov Date: 2010-01-26 Updated Bulgarian translation M po/bg.po commit 4474a1d606c486486eb88e5043da500dd5885e1d Author: Alexander Larsson Date: 2010-01-25 Post release version bump M configure.in commit 49967fd917d0ae5f3e5d63858199fd41e1cd0811 Author: Alexander Larsson Date: 2010-01-25 Update NEWS for release M NEWS commit 1b07696835481a911e44c5964eeb545537242cff Author: Khaled Hosny Date: 2010-01-23 Updated Arabic translation M po/ar.po commit e156e39e07276a4de8414bfdb82340f8762060b4 Author: Alexander Larsson Date: 2010-01-22 Remove tabs menu I don't think this menu is much use, and it clutters up the menus even for users who don't use tabs, which is against our policy of having the more advanced features affect users not using them as little as possible. Also, remove the setting to disable tabs althoughter, as with the menu removed the tabs feature is very minimal when not in use. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/file-manager/fm-tree-view.c M src/nemo-actions.h M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c M src/nemo-places-sidebar.c M src/nemo-window-private.h commit c9d59901003f635221299ca90887b830f3c0a3fa Author: Kjartan Maraas Date: 2010-01-22 Updated Norwegian bokmÃ¥l translation M po/nb.po commit ec8b9a8b58ddd9d6bf08ac9e0b875581009255b3 Author: Thomas Hindoe Paaboel Andersen Date: 2010-01-18 Replace deprecated GTK_OBJECT_TYPE with G_OBJECT_TYPE GNOME bug 565038 M eel/eel-canvas.c commit 6146cd17e4340ca3af43050e405c7ef64efd6e5d Author: Benjamin Berg Date: 2010-01-19 Use test instead of fg for eel-editable-label test Since we use base for the background we should use text for the foreground. (#548295) M eel/eel-editable-label.c commit 46af408406ace29ad8e52e26cdfb43c50c5b96ca Author: Jorge González Date: 2010-01-16 Updated Spanish translation M po/es.po commit fb138478020738917f0fe408e5c4e2fafd3c2bb8 Author: Nelson Benítez León Date: 2010-01-06 Update glib required version M configure.in commit 7fcd79f3d404a734095b4e42cfa36b45aad95c4d Author: dumol Date: 2010-01-10 Updated Romanian translation M po/ro.po commit e050b4134983ea14115d276ee41ba3e877952e52 Author: Lucian Adrian Grijincu Date: 2010-01-10 Updated Romanian translation M po/ro.po commit 344f80b837341e114f5a4f7473ad7d7cfa3c6efc Author: Daniel Nylander Date: 2010-01-09 Updated Swedish translation M po/sv.po commit c444f6d555df95ea2767992c0af6a7cdce3f0d53 Author: Maxim V. Dziumanenko Date: 2010-01-06 Update Ukrainian translation M po/uk.po commit dd151d503dbe6c12dca868b69a8bcddf8fc798b4 Author: Timo Jyrinki Date: 2010-01-06 A few fixes by me from Launchpad. M po/fi.po commit 8769220d5c95057470d58c7591732afc126b58a1 Author: Mattias Põldaru Date: 2010-01-05 Updating Estonian translation M po/et.po commit a12dd191b5b0286a975e8dbfb435ddc09ec1f930 Author: Matej UrbanÄiÄ Date: 2010-01-02 Updated Slovenian translation M po/sl.po commit 331e69edcb178fe157a2990ea9beab0cd128a6be Author: Khaled Hosny Date: 2009-12-25 Updated Arabic translation M po/ar.po commit 972d4f7a4c04f1fffe1a6ad7aa8c4fc9b5bead49 Author: Jorge González Date: 2009-12-19 Updated Spanish translation M po/es.po commit 89c29e1beb04b7f0cc751976bff052af26faf8cd Author: Alexander Larsson Date: 2009-12-17 Move the navigation bar size group to be a cross window header size group This way we can make sure we align the headers of the sidebar too. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window.c M src/nemo-side-pane.c M src/nemo-window-private.h commit 595150f7a94664fb247cef5b0af714fd7f1c0e6b Author: Alexander Larsson Date: 2009-12-17 Add nemo_side_pane_get_title M src/nemo-side-pane.c M src/nemo-side-pane.h commit f8447895dbb680a7abbb483a80d1db05e07ee730 Author: Alexander Larsson Date: 2009-12-17 Post release version bump M configure.in commit 0c33ea773fa27da99187c3bd7ddfcbb42ed6d90d Author: Alexander Larsson Date: 2009-12-17 Fix up include M src/nemo-location-bar.h commit 056ac6c3deaad63f70b61c68743cd03baa0db726 Author: Alexander Larsson Date: 2009-12-17 Dist nemo-extension-private.h M libnemo-extension/Makefile.am commit 2622cc470fa482f8b766bd9a37afc1f0597b8e08 Author: Alexander Larsson Date: 2009-12-17 Remove the rest of shave M Makefile.am M configure.in D m4/Makefile.am commit 21b1aa0144389f7f0a9645d0a734fe5881223844 Author: Alexander Larsson Date: 2009-12-17 Update NEWS for release M NEWS commit e2363ba468bca0662a7f139386432a677478f722 Author: Alexander Larsson Date: 2009-12-17 Change "enable browser" prefs to "enable spatial" Since browser is now the default we want to change the description and default state of the prefs UI for this to follow this change. M src/nemo-file-management-properties.c M src/nemo-file-management-properties.ui commit 70f2f7c8e36898553ba0c6593aee1e8ee52bd7a7 Author: Alexander Larsson Date: 2009-12-17 Add eel_preferences_builder_connect_inverted_bool M eel/eel-preferences-builder.c M eel/eel-preferences.h commit 07c0bf9cb422d38fb4c38faed7af261c5411378c Author: Alexander Larsson Date: 2009-12-17 Enable browser mode by default As discussed on the list we're moving to browser mode with the switch to gnome-shell. Gnome-shell is not quite ready yet, but we want to move towards that as early as possible so we can iron out all the details in the new behaviour. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c commit c69f3a2ba2d0bd23de5a218b8ce13d256481213a Author: Alexander Larsson Date: 2009-12-17 When showing a window for the first time, focus the active slots view M src/nemo-window.c commit cf1e32162affc91b5b3a2ca934c0dee45e3f1a2e Author: Alexander Larsson Date: 2009-12-17 Set right slot in active pane state for new views M src/nemo-window.c commit 4efd42312584b46f248e2839582a87776a7baebe Author: Alexander Larsson Date: 2009-12-17 Don't grab focus on realize This causes problems when opening up an extra view as it forces it to become focused which is not what we want. M libnemo-private/nemo-icon-container.c commit d9abc4bf2ff65009ab1521c31f0877b0e312c8a6 Author: Alexander Larsson Date: 2009-12-17 Move "go to same location as other pane" in the menus We don'r want separators around this single item, put it with the navigation stuff instead (not ideal, but ok). M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml commit ea28580ac582c6df66215b39743e3914c422f236 Author: Alexander Larsson Date: 2009-12-17 Fix typo M src/nemo-navigation-window-ui.xml commit 3fb63af8aed0f350f4eabf65085d80a4442a34b5 Author: Alexander Larsson Date: 2009-12-17 Remove switch to other pane menu item and make F6 do this instead This is a very useless menu item, its sole reason for existance is to bind a keyboard combo to it. Instead we should just choose one. Some research indicate that F6 is standard for this. In Gtk+ F6 is used for split view navigation in general, so it will toggle between the sidebar and the two views. However, you can reach the sidebar in other ways using keynav, and the more important thing is the pane toggling, so we override this and make F6 be pane switching only. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml commit b4f413314de5857867ef152384741c49f2613737 Author: Alexander Larsson Date: 2009-12-17 Replace shave with AM_SILENT_RULES M configure.in M eel/Makefile.am M libnemo-private/Makefile.am D m4/shave-libtool.in D m4/shave.in D m4/shave.m4 commit 8f3e5b8d65d5c67ce6b762c8c33efc42ee13f6c3 Author: Alexander Larsson Date: 2009-12-17 Don't focus the search entry when we're activating a pane with search This is not the right behaviour, and additionally it caused problems to do this from the focus in signal handler for the icon view, since the recursion of the focus changes caused HAS_FOCUS state to be mixed up. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c commit a9384103fe8822a351aa5256c21e00058bfef310 Author: Alexander Larsson Date: 2009-12-17 Set active pane when its search bar gets focus M src/nemo-navigation-window-pane.c commit e5806d3a65f0b6dda23d4c4c12d53a5d09cc1f52 Author: Alexander Larsson Date: 2009-12-17 Add event for search bar getting focus M src/nemo-search-bar.c M src/nemo-search-bar.h commit aecc6b6abf1e1c313d2d4473902a2b9eb0e11827 Author: Alexander Larsson Date: 2009-12-17 Minor whitespace cleanups M src/nemo-window.c commit adc968f34c1085ce4e5378fba92655082052f13d Author: Alexander Larsson Date: 2009-12-17 Move nemo_navigation_window_pane_set_active into a vfunc Now nemo_window_pane_set_active works for both navigational and spatial panes. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit 36ba547921917daa970bd2d8510e3cd1bef894bf Author: Alexander Larsson Date: 2009-12-16 Move active background color handling to the view This stuff references view implementations and should not be in the generic code. M libnemo-private/nemo-view.c M libnemo-private/nemo-view.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/fm-list-view.c M src/nemo-window-slot.c commit 096453c004a2538b816046b0388d6cfb60b618b2 Author: Alexander Larsson Date: 2009-12-16 Remove unnecessary check M src/nemo-window-manage-views.c commit d40b44e5f54a16bdf91ebf2d291732941717fdc6 Author: Alexander Larsson Date: 2009-12-16 Clean up sync_location_widgets by using vtable calls instead of type checks M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-window-pane.c M src/nemo-window-pane.h commit 7c66c6c020edf40383681a6e691c1451ff90b9f7 Author: Alexander Larsson Date: 2009-12-16 Only update toolbar items when active pane changes M src/nemo-window-manage-views.c commit cc3241aa713b99c72f30b01be9179f9b7a4635fc Author: Alexander Larsson Date: 2009-12-16 Fix indentation M src/nemo-window-slot.c commit 3a9fae22b64e4c4c3fa66520314285b4a8b836bb Author: Alexander Larsson Date: 2009-12-16 Move sync_search_widgets from window to pane Since the search widgets are per pane we need only update them for the pane, never for all the window. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-slot.c M src/nemo-window.c M src/nemo-window.h commit a6b53ce4d5b811c854ef8987d1bf6af7ab355b68 Author: Alexander Larsson Date: 2009-12-16 On view selection failure, reload the right window M src/nemo-window-manage-views.c commit 1d62423f6518be0a063e93cc160a0ffdae26ff6d Author: Alexander Larsson Date: 2009-12-16 Remove nemo_window_sync_location_widgets Not used anymore M src/nemo-window-manage-views.c M src/nemo-window-private.h commit 8a0ca66f2c2d69cc50cdbcc319f80529b1b30d00 Author: Alexander Larsson Date: 2009-12-16 Only sync the location bar on the affected pane M src/nemo-window-manage-views.c M src/nemo-window-slot.c commit bc87c744f84fe3c787fd504d811db4ba5c50de79 Author: Alexander Larsson Date: 2009-12-16 Fix window slot close crash On window close via nemo_window_close when the viewed file closed there was a ref on the slot living past the window. This caused crashes when disposing the slot as it referenced the window. We fix this by running the dispose handler when closing a slot and by making the dispose handler able to run multiple times. M src/nemo-window.c commit 9d8f34fa253c9c2812cfc7a738e4751fff18c1dd Author: Alexander Larsson Date: 2009-12-16 Remove fm_directory_view_move_copy_items_between_views not used anymore M src/file-manager/fm-directory-view.c commit ce2e90c30506cbce28addf3258938824a1a61494 Author: Alexander Larsson Date: 2009-12-16 Revert "Pass the window instead of the view to action callbacks." This reverts commit f3390c4f9a277ffd95bc5f3c6e475d9dad7d8935. It makes no sense to pass the window for all view specific callbacks. If anything needs to access the window that is easily doable from the view reference. Conflicts: src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.c commit 0a6c249015c7ab1cfa62e64428652970d397f57b Author: Alexander Larsson Date: 2009-12-16 Rearrange copy/move to menus and add home + desktop items M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml commit 3bd562283262314fc8dd9840a3c1b5d390ab1860 Author: Alexander Larsson Date: 2009-12-16 Don't disable next pane ops if tabs are disabled M src/file-manager/fm-directory-view.c commit ef9b76bc41992a0bd9bb870e64ee0749bfe74d8b Author: Alexander Larsson Date: 2009-12-16 Remove unnecessary includes M src/nemo-window.c commit dc26bef3e209d654c8f952ff4837beb34c0fa8ae Author: Alexander Larsson Date: 2009-12-16 Remove next_pane functions from NemoWindowInfo No need for these, and they put FMDirectoryView at the wrong place. M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/nemo-window.c commit 0ea5a1bfe0815f71fcacec151852bada86b477f2 Author: Alexander Larsson Date: 2009-12-16 Remove use of nemo_window_info_copy_move_selection_to_next_pane Doing this via the window is unnecessary. Also, we simplify the copy operation by not using cut+paste. M src/file-manager/fm-directory-view.c commit e0a6c302d23fde1e4781671f70d501fdeffb7c8f Author: Alexander Larsson Date: 2009-12-16 Don't use nemo_window_info_next_pane_is_writable Instead we can use get_extra_slot and other existing functions, thus avoiding referencing fm-directory-view from the main code. M src/file-manager/fm-directory-view.c commit 1545e04eaf41068c3add34792815b2df84b7fd5d Author: Alexander Larsson Date: 2009-12-16 Use window_get_extra_slot instead of get_directory_view_of_next_pane We want to remove get_directory_view_of_next_pane as the main code should not reference FMDirectoryView. M src/file-manager/fm-directory-view.c commit 6a71f0f996e7c946a10e263951a906dd9795c4dc Author: Alexander Larsson Date: 2009-12-16 Add nemo_window_info_get_extra_slot M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/nemo-window-private.h M src/nemo-window.c commit 7545b45b7c1c1f849b01814304b24af5238dba7e Author: Alexander Larsson Date: 2009-12-16 Remove unnecessary includes M src/nemo-navigation-window.c commit fa563623570eeb6a0ab8d90aae386ecbbd740721 Author: Emilio Pozuelo Monfort Date: 2009-12-15 Bug 604574 - Fix NAME section in nemo-connect-server.1 M docs/nemo-connect-server.1 commit 9c7c2c9d2cc0a8648abf2dbc851e9efec3e3df1c Author: Alexander Larsson Date: 2009-12-15 Make trash keybindings only work if the action is sensitive This fixes https://bugzilla.gnome.org/show_bug.cgi?id=603413 in a way not causing regressions. M src/file-manager/fm-directory-view.c commit d87cf7e75c37d139631807bc22c07ba879f8218f Author: Alexander Larsson Date: 2009-12-15 Use right signal handler for delete signal action This is not actually called atm, since an action overrides it, but we should do it right anyway. M src/file-manager/fm-directory-view.c commit d5d94cdf05a8f775494e5445e0c899a4548d2690 Author: Alexander Larsson Date: 2009-12-15 Revert "Disable Trash/Delete key bindings when appropriate" This reverts commit e7c171acb8060436969139210060874f3a43d835. It causes regressions (see bug 603413) Conflicts: src/file-manager/fm-directory-view.c M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml commit 75bcfea177c837215ea46c970bfea24ec04a3dae Author: Alexander Larsson Date: 2009-12-14 Don't access uninitialized variable gdk_property_get doesn't set prop_text if it fails. M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-tree-view-drag-dest.c commit fb39afae9bf1027cf405f7309685327abd67f1bf Author: Alexander Larsson Date: 2009-12-14 Better tab size This removes the minimum size of tabs, since that causes problems when there are little availible horizontal size (such as in split view), as it caused ellipsizion to only work for strings larger than the minimum set size. However, doing *just* this causes the tabs by default to be only 3 chars wide, which is obviously also bad. So we enable tab-expansio to solve this. The new situation is not ideal either, but its the best we can do before this gtk bug is fixed: https://bugzilla.gnome.org/show_bug.cgi?id=125250 M src/nemo-notebook.c commit 7fb432ba6b6816076e9eb5cd6f586df2e90ed33a Author: Alexander Larsson Date: 2009-12-14 Better split view size allocation Ensure that the views always get *some* size so that we can at least always see the scrollbars, etc. Also make the toplevel size of a pane be a fixed size, thus guaranteeing the two panes in a split view return the same size request, thereby guaranteeing a default (if unset by user) position of 50%. Without this we could get e.g. a size request from the tabs or the location bar size change causing a change in the view splitter position. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit 50fece012964a9bea091a21bb51d65bf877a1ff4 Author: Alexander Larsson Date: 2009-12-14 Don't allow the right part of the sidebar split be shrunk Views at 0x0 pixels make no sense. M libnemo-private/nemo-horizontal-splitter.c commit ee66bca8b74b1530e29414ef226e12157e92d9b7 Author: Alexander Larsson Date: 2009-12-14 Make slot label/icon update work right We move the update calls to a bit later when all the slot-internal state (like slot->location, etc) has been updated. M src/nemo-window-manage-views.c commit 53ae0522ab2ee458eb8235beaf6c8e3afefe49b6 Author: Alexander Larsson Date: 2009-12-14 Minor cleanup Use temporary variable to avoid casts. M src/nemo-navigation-window.c commit 451aafee60cd171650993c5b7640116319eebc9e Author: Alexander Larsson Date: 2009-12-11 Require latest gnome-desktop for gnome-bg changes M configure.in commit 04c26296fb78b6de1a5bf933e543734ce18bd062 Author: Alexander Larsson Date: 2009-12-11 Move status bar to under view in navigational view This means the status bar moves closer to what it shows the status of. Additionally it gives more space for the sidebar, which is not needed for the normally small status messages we have. M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window.c commit 7c1207aa1317e95762b9773f7a2ca72a96177942 Author: Alexander Larsson Date: 2009-12-11 If starting with split view, create extra slot durin construction M src/nemo-navigation-window.c commit 1a6db1b3ff79971f75ad309c22d60c14b2af2857 Author: Alexander Larsson Date: 2009-12-11 Don't show the window until all views in it are visible For the dual-pane at startup case we want to delay window change until all views are loaded. Also when switching to split view we want to delay showing until the view is loaded. M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/file-manager/fm-directory-view.c M src/nemo-navigation-window-pane.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-slot.h M src/nemo-window.c M src/nemo-window.h commit 84631cacd1909000ebd43b7267b7cacb8115d857 Author: Alexander Larsson Date: 2009-12-11 When loading a location in a slot also load in other non-loaded panes This makes sure that if a window is created with more than one pane we'll load something in each of them. M src/nemo-window-manage-views.c commit fbbf8701595d4b6ad3cef93cc83e861d35b34859 Author: Alexander Larsson Date: 2009-12-11 Fix up indentation M src/nemo-window.c commit fb87db4e78a494623921a1ad844b86448965a924 Author: Alexander Larsson Date: 2009-12-11 Update location for all active slots When the location changes for a slot we should update it if its the active slot in its pane (since each pane has a location bar), not only if its in the active pane. M src/nemo-window-manage-views.c commit 605cdcc062c77c3badcb03eb0c8f97385b4739a4 Author: Alexander Larsson Date: 2009-12-11 Remove nemo_window_get_pane_from_slot This is useless, just look at slot->pane M src/nemo-window-private.h M src/nemo-window.c commit 877da7dab374c4ae66ee57b7e5c10e672058b523 Author: Alexander Larsson Date: 2009-12-11 Only sync tab name in menu for the active pane M src/nemo-navigation-window.c commit 55f1438bf898c819504dae540a7540ec30508f1e Author: Alexander Larsson Date: 2009-12-11 Don't rewrite bookmarks file when file appearance changes We no longer write the icon to the bookmarks file so this is just unnecessary. Also this means we don't rewrite the bookmark file on each startup. M src/nemo-bookmark-list.c commit 3fab1d20298552000369480a694186fd7354f586 Author: Alexander Larsson Date: 2009-12-11 Fix up background setting for non-desktop windows M eel/eel-background.c commit c68a696dcb8884ded4571c375e368f3f3375d068 Author: Alexander Larsson Date: 2009-12-10 Only fade the desktop background, not normal windows All this flashing is just in the way, especially when the color changes as part of a pane going inactive. M eel/eel-background.c commit 6e5323188fc6af5d8920a01c3e34496df3320760 Author: Alexander Larsson Date: 2009-12-10 Remove border width on notebook This makes the view line up with the sidebar, etc. M src/nemo-navigation-window-pane.c commit 09efd40fbb2cd924bfee6650bea50e2ffb21a349 Author: Alexander Larsson Date: 2009-12-10 Remove border on statusbar https://bugzilla.gnome.org/show_bug.cgi?id=499361 M src/nemo-window.c commit 9bc68d825f3e928e736caf213b84371607a6bd41 Author: Baptiste Mille-Mathias Date: 2009-12-10 Put border around file views https://bugzilla.gnome.org/show_bug.cgi?id=499361 M src/file-manager/fm-directory-view.c commit c6ee7553fd029239eff50d32dbcb57223ffa185e Author: Alexander Larsson Date: 2009-12-10 Put tabs at the bottom There is way to much visual clutter at the top already, with the location bars and toolbars. M src/nemo-notebook.c commit 4b49aab5aa6a9ef9ab288ff2ce463affca1eacf2 Author: Alexander Larsson Date: 2009-12-10 Remove location button This takes a lot of space for something thats not commonly used. Especially with two of it visible in split view mode. Maybe we should make a preference for it, but its not interesting in the main UI. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h commit df7048157403efefb560c5d1075f04088af3048b Author: Holger Berndt Date: 2009-12-05 Improve search button handling in split view mode This commit fixes issues that were introduced in merge commit e92c336df90df012746d08d9af8121edc38b0f3c Now the escape key during temporary search toggles the search key off again, as does changing active pane during temporary searches. M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h commit 8bafe8109f2151ee1febfc4a00255b92053c2ef8 Author: Holger Berndt Date: 2009-06-25 Fix View -> Location Bar in dual pane mode. Although each pane has a separate location bar, the show/hide location bar setting is window-global instead of applying to individual panes: Either both panes have a location bar, or neither one does. Inconsistencies with remembered show/hide location bar gconf setting were also fixed. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c commit ee3c49268205cd6fd99694706a4b2b7e3aca8086 Author: Alexander Larsson Date: 2009-12-10 Remember extra pane status access windows. The status of the extra pane display is remembered in a gconf key, analog to show/hide statusbar and other window display properties. As the extra-pane action implementation does a lot of widget and action re-ordering, this can only be done when a windows is set up completely, and is thus delayed in an idle-callback. If splitting the view is to be done on startup, the showing of the window is delayed to avoid ugly visible reordering. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-actions.h M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window-slot.c M src/nemo-window.c commit 5d236a20aadd291196e6ead3a2220e9c0258b126 Author: Holger Berndt Date: 2009-06-13 Make it possible for Nemo Scripts to access the other pane. This is accomplished by placing additional variables into the environment of the script, analoguous to the single-pane ones: - NEMO_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS - NEMO_SCRIPT_NEXT_PANE_SELECTED_URIS - NEMO_SCRIPT_NEXT_PANE_CURRENT_URI If there is no second pane in the window, these are set to empty strings. M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/file-manager/fm-directory-view.c M src/nemo-window.c commit 09359fd13b52c5f5cebe55a9efae21c0290fe86f Author: Holger Berndt Date: 2009-06-13 Implement "Go to same location as other pane" menu item. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml commit a0bd4bc51d556a44ada296b3d3ec22e6c19f04f4 Author: Holger Berndt Date: 2009-06-13 Implement "Switch to other pane" menu item. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-private.h commit 0a5d182ac274a0b11a39daa41285fbf1d39b1e70 Author: Holger Berndt Date: 2009-07-20 Also draw background of inactive pane in insensitive color when in list view M src/nemo-window-slot.c commit 2f843f0ed243a1c1f184c69e166c9da710fe1618 Author: Holger Berndt Date: 2009-06-13 Draw background of inactive panes in INSENSITIVE color. In order to make it easier to visually distinguish active and inactive panes, the background of inactive panes is drawn in the theme's INSENSITIVE color. Like the inactive location bar widgets, this is only a visual marker, and does not mean that that pane is insensitive. It's still clickable, and in fact a click makes the corresponding pane active. M eel/eel-background.c M eel/eel-background.h M src/nemo-window-pane.c M src/nemo-window-slot.c M src/nemo-window-slot.h commit 4cc909a668692551db92a67bcb36b7cdeb473579 Author: Holger Berndt Date: 2009-06-11 Implement "{copy,move} to other pane" menus. M libnemo-private/nemo-window-info.c M libnemo-private/nemo-window-info.h M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/nemo-directory-view-ui.xml M src/nemo-shell-ui.xml M src/nemo-window-private.h M src/nemo-window.c commit 7191f6fa4f3013481463c1181b51b705d5c48d9a Author: Holger Berndt Date: 2009-06-11 Fix tab menus in split view mode. Only the menu of the active pane is inserted. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c M src/nemo-window.c commit c3da9152ce3efadbeaf92340ca832af6dbfc6266 Author: Holger Berndt Date: 2009-06-11 Make location bar more reactive, part 2: navigation bar Followup to the last commit: The location bar of the inactive pane now has an insensitive apprearance, but is in fact clickable/focusable. A click makes the corresponding pane active via the focus-in event of the entry widget. M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-navigation-window-pane.c commit 689fd8e7ac943f1bed48dc0f6aad4b0e418e1005 Author: Holger Berndt Date: 2009-06-11 Make location bar more reactive: path bar, toggle button and zoom control The buttons in the directory button bar are made inactive when the corresponding pane is inactive. This means that the buttons have an insensitive appearance, but are in fact clickable. Clicking on them will make the corresponding pane active while changing into the respective directory. This required the pathbar to export the button widget, done with the new function nemo_path_bar_get_button_from_button_list_entry(). M src/nemo-navigation-window-pane.c M src/nemo-pathbar.c M src/nemo-pathbar.h M src/nemo-zoom-control.c M src/nemo-zoom-control.h commit 531ff030ef016b118f174252b1ac9aee0e385c63 Author: Holger Berndt Date: 2009-06-07 Don't use a function to get the active slot. M src/nemo-window-slot.c commit f3390c4f9a277ffd95bc5f3c6e475d9dad7d8935 Author: Holger Berndt Date: 2009-06-07 Pass the window instead of the view to action callbacks. With dual pane, actions may work on more than one view. Thus it makes sense to pass the window instead of the view to the callbacks. If the callbacks want the old behaviour, they first need to get the active view of the window, and work with that. M src/file-manager/fm-directory-view.c commit 3cb24525f5e3681592900a3db49f2862debf084d Author: Holger Berndt Date: 2009-06-07 Also active/deactive panes based on focus-in-event for list views M src/file-manager/fm-list-view.c commit 02529b86015195128ebcbe3702888445727d5679 Author: Holger Berndt Date: 2009-06-06 Propagate activation in slot-info interface M libnemo-private/nemo-window-slot-info.c M libnemo-private/nemo-window-slot-info.h M src/file-manager/fm-icon-view.c M src/nemo-window-slot.c commit 01e94440638904b0bc546b1ef1081a88e92d3e8e Author: Holger Berndt Date: 2009-05-27 Start implementation of "add extra pane" menu item callback Upon activating that menu item, create new pane and pack into the split view hpane. On deactivation, delete non-active pane. M src/file-manager/fm-list-view.c M src/file-manager/fm-list-view.h M src/nemo-navigation-window-pane.c M src/nemo-navigation-window.c commit 8babbe1095134861e4e57f482557587ee9b78576 Author: Holger Berndt Date: 2009-05-25 Add skeleton for split view. Add a new menu item "View -> Extra pane", and corresponding skeleton callback functions and UI containers. M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window-private.h commit 6fc12915c7e3b8e92696630117afb5d5f5aaf60c Author: Alexander Larsson Date: 2009-12-10 Move location from toolbar to pane widget M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window.c commit e1fe45ddde92aece9aafdeb2febcfe76178e48b1 Author: Holger Berndt Date: 2009-05-24 Move notebook from window into pane This is another refactorisation commit. A notebook is also pane specific, not window specific. In particular, the following function logic has been moved: notebook_popup_menu_move_left_cb notebook_popup_menu_move_right_cb notebook_popup_menu_close_cb notebook_popup_menu_show notebook_tab_close_requested notebook_button_press_cb notebook_popup_menu_cb notebook_switch_page_cb nemo_navigation_window_pane_setup_notebook The following functions have been renamed: nemo_navigation_window_initialize_tabs_menu to nemo_navigation_window_pane_initialize_tabs_menu (also made public) nemo_window_get_slot_for_content_box to nemo_window_pane_get_slot_for_content_box M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-notebook.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window.c commit f14e7d47456867899016889756f32120dda847fb Author: Alexander Larsson Date: 2009-12-09 Move location bar entries to pane Location bar entries are pane-specific, not window specific. Therefore, it is neccessary to move significant parts of the logic around, mainly from NemoWindow to NemoWindowPane, and NemoNavigationWindow to NautilisNavigationWindowPane. In particular, the following functions have been moved into the pane: bookmark_list_get_uri_index restore_focus_widget search_bar_activate_callback search_bar_cancel_callback navigation_bar_cancel_callback navigation_bar_location_changed_callback location_button_should_be_active location_button_toggled_cb path_bar_location_changed_callback path_bar_button_pressed_callback path_bar_button_released_callback path_bar_button_drag_begin_callback path_bar_path_set_callback nemo_navigation_window_show_location_bar_temporarily nemo_navigation_window_show_navigation_bar_temporarily nemo_navigation_window_path_bar_showing nemo_navigation_window_set_bar_mode nemo_navigation_window_search_bar_showing nemo_navigation_window_hide_location_bar nemo_navigation_window_show_location_bar nemo_navigation_window_location_bar_showing nemo_window_zoom_{in,out,to_level,to_default} The location bar setup parts of nemo_navigation_window_init() have been moved to nemo_navigation_window_pane_setup_location_bar. The following fuctions have been made public: hide_temporary_bars load_view_as_menu unset_focus_widget update_up_button Much logic of the following functions has been moved to the pane, but the functions themselves have been left in the window as triggers: nemo_navigation_window_hide_temporary_bars nemo_window_sync_location_widgets M src/nemo-application.c M src/nemo-location-bar.c M src/nemo-location-bar.h M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-pane.c M src/nemo-navigation-window-pane.h M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window.c commit 014b488d184fafe59f29810d372eccebd3c66876 Author: Holger Berndt Date: 2009-05-18 Use the new NemoNavigationWindowPane class in NemoNavigationWindow's M src/nemo-navigation-window.c commit 651053fec975b95536b7e967c7e8b81732b1f740 Author: Holger Berndt Date: 2009-05-18 Add new class NemoNavigationWindowPane, derived from NemoWindowPane NemoWindowPane is the base class for window panes, while NemoNavigationWindowPane will add some functionality spefic to panes in a Nemo navigation window. M po/POTFILES.in M src/Makefile.am A src/nemo-navigation-window-pane.c A src/nemo-navigation-window-pane.h commit e1db3d61f6510a8f6cc063ba84b5fa26bebf6189 Author: Alexander Larsson Date: 2009-12-07 Associate basic slot functions to panes instead of windows. M src/nemo-application.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-manage-views.c M src/nemo-window-manage-views.h M src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window.c M src/nemo-window.h commit e7f2144e38c02f6aeba7b563e8bc1fb195616477 Author: Alexander Larsson Date: 2009-12-07 Move slots from NemoWindow to NemoWindowPane A window does not hold lists of slots anymore, but lists of panes, which in turn hold lists of slots, making a slot effectively a layer between a window and a slot. Much of the remaining part of the patch is simply replacing "window->details->active_slot" with "window->details->active_pane->active_slot" and similar changes. Commits to move corresponding parts of the logic out of the window into the pane are to follow. M src/nemo-application.c M src/nemo-location-bar.c M src/nemo-location-dialog.c M src/nemo-navigation-action.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-bookmarks.c M src/nemo-window-manage-views.c M src/nemo-window-pane.c M src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window-slot.c M src/nemo-window-toolbars.c M src/nemo-window.c commit d3ee81d3021204786c3c51bf9f651fffbd10ff0b Author: Holger Berndt Date: 2009-01-31 Associate a slot to a pane instead of a window NemoWindowSlot->window is removed and NemoWindowSlot->pane is added. All references to window is then replaces with ->pane->window. M src/nemo-application.c M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-slot.c M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-manage-views.c M src/nemo-window-slot.c M src/nemo-window-slot.h M src/nemo-window.c commit adc0b289f6f92751bd40a6005375eae2a79439c3 Author: Alexander Larsson Date: 2009-12-07 Add a NemoWindowPane to all windows M src/nemo-navigation-window.c M src/nemo-spatial-window.c M src/nemo-window-private.h M src/nemo-window.c commit daa113b66fbf4193cdb049c11bd3df9f98f4ba0a Author: Holger Berndt Date: 2009-01-30 Introduce concept of a NemoWindowPane A pane is another layer around a slot. For spatial windows, a pane will contain a single slot. For navigation windows, a pane will contain a list of slots, as well as a corresponding toolbar items. M src/Makefile.am A src/nemo-window-pane.c A src/nemo-window-pane.h M src/nemo-window-private.h M src/nemo-window.c commit 8e69e90733dcb1bd65d2fdcc2a026cb458c25ed2 Author: Alexander Larsson Date: 2009-12-09 Remove all traces of old view-as and zoom widgets M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-window.c M src/nemo-window.h commit 14def79a4e1cd7d78d0dd155fa5b643f440859e7 Author: Alexander Larsson Date: 2009-12-09 Add a view as toolbar item using the view-as action M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml commit c7aeb63442007fbdac9feff66cc4541972162738 Author: Alexander Larsson Date: 2009-12-09 Add NemoViewAsAction This is an action that makes it easy to create a view as toolbar item. M src/Makefile.am A src/nemo-view-as-action.c A src/nemo-view-as-action.h commit bff56af563ee232815c6bd0502869fac7eb97476 Author: Alexander Larsson Date: 2009-12-09 Add NemoWindow::view-as-changed M src/nemo-window.c commit 946f377fc531b47ba71f85b8d57a4f2f20c9c432 Author: Alexander Larsson Date: 2009-12-09 Use NemoZoomAction to put zoom item in toolbar M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml commit da25dfdc1e94aae68bb9ff35497e7c2481449389 Author: Alexander Larsson Date: 2009-12-09 Add NemoZoomAction This is an action that can be used to easily put zoom items in toolbars. M src/Makefile.am A src/nemo-zoom-action.c A src/nemo-zoom-action.h commit 70298f3dfc04c6c7cc995c94af7b67d97d60a66a Author: Alexander Larsson Date: 2009-12-09 Add NemoWindow::zoom-changed signal M src/nemo-window.c commit 27b7859f2aa6d61b0b4cf5ae48333dc089ddf56f Author: Alexander Larsson Date: 2009-12-09 Add VOID:INT,BOOLEAN,BOOLEAN,BOOLEAN,BOOLEAN marshaller Needed for zoom-changed signal M libnemo-private/nemo-marshal.list commit 3add7e368af3ea9f37e2f5f386543cf228b0b74f Author: Baptiste Mille-Mathias Date: 2009-12-10 Add border on sidebar (remove on header) https://bugzilla.gnome.org/show_bug.cgi?id=499361 M src/file-manager/fm-tree-view.c M src/nemo-emblem-sidebar.c M src/nemo-history-sidebar.c M src/nemo-places-sidebar.c M src/nemo-side-pane.c commit 49193a40792ba8df413a3b361940f977dc009aef Author: Alexander Larsson Date: 2009-12-10 Add shadow_type arg to eel_scrolled_wrap_table_new M eel/eel-wrap-table.c M eel/eel-wrap-table.h M src/file-manager/fm-properties-window.c M src/nemo-emblem-sidebar.c commit 60dd20355079003afe3ba342e6233834afeffd39 Author: William Jon McCann Date: 2009-12-03 Fixes to enable per-monitor backgrounds https://bugzilla.gnome.org/show_bug.cgi?id=147808 M eel/eel-background.c commit 90b8c56e64caa7fd2435cdb619c8ed83971b9519 Author: Aron Xu Date: 2009-12-09 Update Simplified Chinese translation, M po/zh_CN.po commit 2d61fcdf4987802441b7d9dab5364a28fb2dbd7c Author: Alexander Larsson Date: 2009-12-08 Don't leak NemoDirectory M libnemo-private/nemo-file.c commit ac9f08eb1f74b32c432b0a4904fb57e982202a4c Author: Alexander Larsson Date: 2009-12-08 Don't leak NemoDirectory M src/nemo-navigation-window.c commit 8c3e5abb396bb67274d9e3d769295ece33b52091 Author: Alexander Larsson Date: 2009-12-08 Use nemo_directory_unref to unref directories Its nice to have nemo_directory_ref/unref paired for help when debugging. M src/file-manager/fm-tree-model.c commit 18763611ef08a6915b4bfd03a3c0bc287ba142ca Author: Alexander Larsson Date: 2009-12-07 Forgot to add nemo-extension-private.h in last commit A libnemo-extension/nemo-extension-private.h commit 09877bd2c4da7282f3d341297af75eda197f3e33 Author: Kjartan Maraas Date: 2009-12-05 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit 881f208b876c6e4386d54a0db3fca26aaa34ff71 Author: Alexander Larsson Date: 2009-12-04 Add lookup and creator functions for NemoFileInfo objects This has been requested by many extension developers. M libnemo-extension/nemo-file-info.c M libnemo-extension/nemo-file-info.h M libnemo-private/nemo-file.c commit 002bea81792cdfe6f4e45da95a59708040566171 Author: Alexander Larsson Date: 2009-12-04 Don't change background on the initial style_set call This results in queueing an unnecessary background change which causes the EelBackground to be unrealized wrongly. This fixes https://bugzilla.gnome.org/show_bug.cgi?id=578136 M eel/eel-background.c commit fd2e7311edd0d673adc21efdd7d4c6585723c730 Author: Alexander Larsson Date: 2009-12-04 Revert commit 7b86b78e2ff6a0f1b45ac8f8a9c30cf3d0c6ae96 This is not the right solution M eel/eel-background.c commit d876890dfdbcd7c6255f14f9b910255598fcf84b Author: Khaled Hosny Date: 2009-12-04 Fix typo M po/ar.po commit 7ad4b090a3d90f9333d2efdd52f2019a1cab1292 Author: Ivar Smolin Date: 2009-12-01 Updating Estonian translation M po/et.po commit e7c171acb8060436969139210060874f3a43d835 Author: Michael Terry Date: 2009-12-01 Disable Trash/Delete key bindings when appropriate This makes trash/delete key binding be enabled/disabled just like the menu items are. M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml commit 523a87744cdf86123da2de4e42a650aa0e891259 Author: Daniel Nylander Date: 2009-11-30 Updated Swedish translation M po/sv.po commit 2fb27dad4661dfce14a1ac5c7bc23e68fec7ee5c Author: Yaron Shahrabani Date: 2009-11-30 Update Hebrew translation M po/he.po commit 529ebf07a31e3a460f0ebde97833235136e50cf4 Author: Ivar Smolin Date: 2009-11-29 Updating Estonian translation M po/et.po commit 519ec1ef646f5edeff75801e592ab8f9e7423f82 Author: Alexander Larsson Date: 2009-11-27 Don't free uninitilized errors test_dir_is_parent doesn't set error, so no need to free it. M libnemo-private/nemo-file-operations.c commit 58e8653a8b0eb885f73c65eebc5926539eef9687 Author: Gabor Kelemen Date: 2009-11-27 Updated Hungarian translation M po/hu.po commit c125ec694bb7f7159cb72a3eb15f5845fc2c10ef Author: Alexander Larsson Date: 2009-11-27 Go to default location (not root) when clicking on mount in sidebar M src/nemo-places-sidebar.c commit ce39f704ff3494893a1198697cc2ae7b12f0d7ee Author: Alexander Larsson Date: 2009-11-27 Use mount default location for desktop links M libnemo-private/nemo-desktop-link.c commit 817803aaeefd9ebf6ee1df4053f8f986943d91f5 Author: Alexander Larsson Date: 2009-11-27 Handle GMount default_location in pathbar as fake root M src/nemo-pathbar.c commit d9d860a8e2fa5d41ff941ce5dc8e80672c05d5b8 Author: Alexander Larsson Date: 2009-11-27 Clean up fake-root handling M src/nemo-pathbar.c commit 5b1159927b98b569fcb22f05986a140a7c42ba0a Author: Alexander Larsson Date: 2009-11-26 Ensure show-hidden-files UI is uptodate When we read the per-location show-hidden-files setting, also update the UI. Fixes bug #568089. M src/nemo-window-manage-views.c commit 09f24d05eae830fd0ec696267f85e02debdc95a7 Author: Jorge González Date: 2009-11-27 Updated Spanish translation M po/es.po commit 5e86595f45d8470732dee1bd820512f5229bf160 Author: Matej UrbanÄiÄ Date: 2009-11-26 Updated Slovenian translation M po/sl.po commit 04c84927339a18aac3c8ee2fa3b2f6edc88e969f Author: Nils-Christoph Fiedler Date: 2009-11-25 Updated LowGerman translation M po/nds.po commit 6f0c44a70f62395e6281604601075994fa921afc Author: Alexander Larsson Date: 2009-11-25 Add entry icon to search bar This way you can activate a search using the mouse. (Bug #598256) M src/nemo-search-bar.c commit eee73c5eb6d83955a7b7a1af9a86f8294eea218a Author: Nikos Verschore Date: 2009-11-25 Make search button a toggle button Make the search button on the toolbar toggle between search and normal mode. See: https://bugzilla.gnome.org/show_bug.cgi?id=332078 M src/nemo-navigation-window-menus.c M src/nemo-navigation-window-ui.xml M src/nemo-navigation-window.c M src/nemo-navigation-window.h M src/nemo-query-editor.c commit 6ff1e3881e070a0a235208cc10dfdc53e8faa0aa Author: Alexander Larsson Date: 2009-11-25 Avoid deprecated gtk_button_pressed/released We replace these with direct use of deprecated signals, which is not ideal either. However, it makes us not reference depcrecated symbols and makes it works. I don't know how else to solve this. M src/nemo-navigation-action.c M src/nemo-window-menus.c commit 6161343d9d3eaa4fa044613085c00415852f8b55 Author: Pierre Wieser Date: 2009-11-25 Allow absolute pathnames for plugin menu/toolbar item icons. M libnemo-private/nemo-ui-utilities.c M src/file-manager/fm-directory-view.c commit 36d83807cc0744e131e3532714849a7d1bbbf65d Author: Pierre Wieser Date: 2009-11-25 Add nemo_icon_info_lookup_from_path() M libnemo-private/nemo-icon-info.c M libnemo-private/nemo-icon-info.h commit 4ea889ee82a66fb929920589322eb0565984f31d Author: Tao Wei Date: 2009-11-24 Updated Simplified Chinese translation. M po/zh_CN.po commit 2c50a8dea92273286404ba1e87f892354fb9b777 Author: Jorge González Date: 2009-11-19 Updated Spanish translation M po/es.po commit 7a890c3f5adb8eb35e208958b293e03c691c7830 Author: Alexander Larsson Date: 2009-11-19 Ensure range checking works below zero We add an int to an unsigned and then check for underflow, but this check will never trigger for unsigned variables like an enum. We fix this by using a signed value for the addition result. M src/file-manager/fm-list-view.c commit 1f8f54f4777343dda87043e444a24c3f86e90439 Author: Alexander Larsson Date: 2009-11-19 Ensure ABS calls work on difference of unsigned values guint64 - guint64 is of type guint64, so ABS doesn't work on it. Cast to gint64 to make sure this works. M libnemo-private/nemo-file-operations.c commit 3c0cc87da5eccab0c022d5bfee6191af4a3f4ea9 Author: Matej UrbanÄiÄ Date: 2009-11-18 Updated Slovenian translation M po/sl.po commit a76fe6975c0e3a31aa8d8ab4ddf3b7afbafbe274 Author: James Dietrich Date: 2009-10-27 Complete XDS support https://bugzilla.gnome.org/show_bug.cgi?id=585790 M libnemo-private/nemo-dnd.h M libnemo-private/nemo-file-dnd.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-operations.h M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-icon-container.h M libnemo-private/nemo-icon-dnd.c M libnemo-private/nemo-marshal.list M libnemo-private/nemo-tree-view-drag-dest.c M libnemo-private/nemo-tree-view-drag-dest.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c commit f146e054849fef9300e9fc8786c11e2d9b7c91d7 Author: Marcus Carlson Date: 2009-10-12 Changed the "event-after" signal to "changed" to update the "Location" / "Go to" label Change the secondary icon in the location to a "Go" (play) icon when the label is "Go to" otherwise a clear icon https://bugzilla.gnome.org/show_bug.cgi?id=163245 M src/nemo-location-bar.c M src/nemo-location-entry.c M src/nemo-location-entry.h commit 3ee90909fa92feaf3df0964eed2b95c5d968ba98 Author: Tomas Bzatek Date: 2009-11-10 Unfreeze updates in directory list view after rename cancellation We successfully cancelled rename operation but the directory view was left in frozen state, containing pseudo items with NULL elements. Fixes bug 590591. M src/file-manager/fm-list-view.c commit e487552287e5970dbbb39199b55026f2788bb42b Author: Alexander Larsson Date: 2009-11-17 Correctly update the request counters The request counters weren't updated by nemo_directory_add_file_monitors and nemo_directory_remove_file_monitors. This can cause a number of weird problems, including those described in bug #598931. This checkin fixes this, and fixes bug #598931. M libnemo-private/nemo-directory-async.c commit f60a28846a32543849a4916d032efdf71e167548 Author: Alexander Larsson Date: 2009-11-17 Add debug code for tracking down errors in request counters nemo_directory_verify_request_counts can be uncommented and called in various places to catch when the request counters are not properly updated. M libnemo-private/nemo-directory-async.c commit 0f638d6505b3adbd2d73fa1bd5894d62d40a2844 Author: Kjartan Maraas Date: 2009-11-15 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit f829c8fe28f221a153f9bedb5f7c86073f082550 Author: Aron Xu Date: 2009-11-14 Updated Simplified Chinese translation. M po/zh_CN.po commit 50836f6b37714516a7fb561475b3fe36666b1749 Author: Alexander Shopov Date: 2009-11-13 Updated Bulgarian translation M po/bg.po commit e5247083a16425171858e2a61ec54efee8191eac Author: Thomas Thurman Date: 2009-11-11 Further Shavian translation M po/en@shaw.po commit 97d98d9c7aeef53378bd07dfac78bf9ea770383e Author: Mario Blättermann Date: 2009-11-10 Added nds to LINGUAS M po/LINGUAS commit a0216f02be4793f8d0a19a3cdff5ae1619748472 Author: Nils-Christoph Fiedler Date: 2009-11-10 Added Low German translation A po/nds.po commit 13f4560aeeedd3f1626556d688e008aaf9b97f20 Author: Thomas Thurman Date: 2009-11-10 Shavian translation M po/LINGUAS A po/en@shaw.po commit 2bad8fcd7c67439826b7174bad4d2bfa5dee36c9 Author: Kjartan Maraas Date: 2009-11-09 Single gtk/gdk includes. M eel/eel-canvas.h commit c0d618993a79f655f474532ed8d1d0118d479a68 Author: Jovan Naumovski Date: 2009-11-06 Minor fix in Macedonian translation. M po/mk.po commit 0458c87d2f5561d03eb1bae593a867135c3c14a5 Author: Matej UrbanÄiÄ Date: 2009-11-06 Updated Slovenian translation M po/sl.po commit 6613262f4e6d40d153299d7fd4726210268a2a53 Author: Cosimo Cecchi Date: 2009-11-02 Don't get drag data in list mode if we don't support the target. This fixes bug #600183. M libnemo-private/nemo-tree-view-drag-dest.c commit 71e7b576751c1192fe0c05529619f4c0aba674c0 Author: Cosimo Cecchi Date: 2009-11-02 Emit the selection-changed signal when inverting. Do emit the selection-changed signal in NemoIconContainer when we invert the selection, so that the views can update the UI items accordingly (#600308). M libnemo-private/nemo-icon-container.c commit 51150a7fb834a7e6e64511e7f7cf7070328222c8 Author: Kostas Papadimas Date: 2009-11-01 Updated Greek translation M po/el.po commit a16d73fa256e7bcf15f36136dea2bec7b37aefaf Author: Gintautas Miliauskas Date: 2009-10-30 Updated Lithuanian translation. M po/lt.po commit d727babc5ebbc7d282d80fbace69a7401eb3795e Author: Gintautas Miliauskas Date: 2009-10-25 Updated Lithuanian translation. M po/lt.po commit bf8571a78f1f8c73ea449e56fa413abb3f40b91c Author: Cosimo Cecchi Date: 2009-10-25 Move functions outside of #ifdefs (#599290) This unbreaks the build if you compile without EXIF/EXEMPI. M src/nemo-image-properties-page.c commit ec8b2f666d175860b36a29870160a41446e0c160 Author: drtvasudevan Date: 2009-10-23 Updated Tamil translation M po/ta.po commit 04025fea82e720c6704da76c5e4d786775a7fb00 Author: Tomas Bzatek Date: 2009-10-20 Handle failed connection to tracker daemon 0.7 series Also, consolidate string memory management, to be consistent and clear on a first sight. Related to changes in bug 596082. M libnemo-private/nemo-search-engine-tracker.c commit 9be1fc059a2f7ce429592be5a6e2a56e7a36a8d7 Author: Jorge González Date: 2009-10-20 Updated Spanish translation M po/es.po commit fe2d7c35cc4f35c2dfd3e9345e354bd388fceca8 Author: ReÅŸat SABIQ Date: 2009-10-20 Another minor update for Crimean Tatar (Crimean Turkish) translation M po/crh.po commit ed199bbd9762a248d9b5036b7130d8965d13dfb9 Author: ReÅŸat SABIQ Date: 2009-10-19 Update for Crimean Tatar (Crimean Turkish) translation M po/crh.po commit 7f3453af4c59331e77dc09f07fdd9b24d533620a Author: Cosimo Cecchi Date: 2009-10-18 Use separate labels for attributes (#598545). This is useful so that we can easily select the text for each attribute. M src/nemo-image-properties-page.c commit 67d827e10e34186b4d3c1410817a5f7aac507b14 Author: Kjartan Maraas Date: 2009-10-17 Updated Norwegian nynorsk translation and fixed a typo. Closes bug #598607 reported by Torstein A. W. M po/nn.po commit f2ab25b7705e4f320e0fdb33a8ad8f302cb1cf0d Author: Sveinn í Felli Date: 2009-10-16 Updated Icelandic translation M po/is.po commit 006abaefbb5d30718678a212cd595a8a7d436d58 Author: Anna Jonna Ãrmannsdóttir Date: 2009-10-02 Updated Icelandic translation M po/is.po commit d1f92784496217f82c4f38b64f51b6820efc6fba Author: Nguyá»…n Thái Ngá»c Duy Date: 2009-10-13 po/vi.po: update translation of "Places" M po/vi.po commit 16226ab944780b9b5a65fe2a38e02f4bcf470254 Author: Jorge González Date: 2009-10-11 Updated Spanish translation M po/es.po commit 3b96ca69946453a4744a58f997289b86f7d41d5d Author: drtvasudevan Date: 2009-10-10 Updated Tamil translation M po/ta.po commit 23278532505862816bd5c8c0ab7d17f7a07b4790 Author: Cosimo Cecchi Date: 2009-10-09 Always check if the drag dest supports the source. In the "drag-motion" callback, make sure we check for target != GDK_NONE before getting non-existent data for it. M libnemo-private/nemo-dnd.c M src/nemo-places-sidebar.c commit 8ef1a18f81a588525fe2cf069ecc9f58a8b6b6ba Author: Ivar Smolin Date: 2009-10-10 Updating Estonian translation M po/et.po commit a2e04a10329f5391b968f82b6110112de0dc2fad Author: Stephen Cook Date: 2009-10-07 Remove very old unnecessary FIXMEs. Closes bug #41245. M libnemo-private/nemo-global-preferences.c M src/nemo-navigation-window.c M src/nemo-window.c commit af9f607c258270cd08e3b994017bc1ca134099fc Author: A. Walton Date: 2009-10-07 Bug 589375 - Crashes with empty location in edit bookmarks Check that the length of the text in the entry is non-NULL. M src/nemo-bookmarks-window.c commit 488a462382bd43a0ad04e274441537d508669c8a Author: Matthias Clasen Date: 2009-10-07 Remove an ugly hack to detect KDE desktop (#564208). M src/nemo-application.c commit f28404dd6af7e95c8038e9f73a31f19398b148c2 Author: Xu Li Date: 2009-07-17 correct the value of GtkRecentData.app_exec in nemo_recent_add_file() M libnemo-private/nemo-recent.c commit 1dd60a63b0048e093da2e2f710bca6a922e4029e Author: Frédéric Péters Date: 2009-08-22 Remove deprecated Encoding key from desktop files M data/nemo-autorun-software.desktop.in.in M data/nemo-browser.desktop.in.in M data/nemo-computer.desktop.in.in M data/nemo-file-management-properties.desktop.in.in M data/nemo-folder-handler.desktop.in.in M data/nemo-home.desktop.in.in M data/nemo.desktop.in.in M src/network-scheme.desktop.in commit cbec5342514b7f52bf654fff418f10bea3aac7ca Author: Nelson Benítez León Date: 2009-05-01 Avoid crash when holding space bar on focused navigation buttons Fixes bgo#580926 M src/nemo-navigation-window-menus.c M src/nemo-window-menus.c commit 370ebf572e4e8d401f65fa7b575899e82fc9dfa7 Author: Cosimo Cecchi Date: 2009-10-07 Use the right GConf key for the disable_tabs setting (#580220). M libnemo-private/nemo-global-preferences.h commit 3ef9873b86ec14ccd33680acb232fa0df0eb11ce Author: Cosimo Cecchi Date: 2009-10-07 Chain up to the parent handler if we click outside any row. By doing so, the tree view widget will gain focus anyway. Fix bug #589088. M src/file-manager/fm-list-view.c commit f29571245545750e26ae84b3b383ab7619ea10bc Author: Marcus Carlson Date: 2009-10-06 Show tooltips in places sidebar https://bugzilla.gnome.org/show_bug.cgi?id=595616 M src/nemo-places-sidebar.c commit 3966879080237672d41e2aab0499a5852ef00ea9 Author: Marcus Carlson Date: 2009-10-03 Make changing visible columns instant. Wasn't like always like this before because nemo-vfs-file.c saved metadata async. https://bugzilla.gnome.org/show_bug.cgi?id=597227 M src/file-manager/fm-list-view.c commit 143fd025cc20423cc9eb8b3a255b4a102a58efce Author: Marcus Carlson Date: 2009-10-03 Adds a "Copy Anyway" option when copying files and disk space is not enough https://bugzilla.gnome.org/show_bug.cgi?id=324361 M libnemo-private/nemo-file-operations.c commit c7bfedfbf8883ddeacfdd0818d7c1af9530c4f52 Author: Marcus Carlson Date: 2009-10-06 Select all on F2 in rename mode This is a another quick way to switch from not selecting extension to selecting everything (in addition to the existing shift-F2 combo). M libnemo-private/nemo-icon-container.c M src/file-manager/fm-list-view.c commit 56f33af7601fb8a1ce28a953ae7516eb7e46c7a5 Author: Jochen Skulj Date: 2009-10-05 Updated German translation M po/de.po commit 7bff0191b0c94c6570c5ffd3d34e8b1cf30da408 Author: Denis ARNAUD Date: 2009-10-05 Updated breton translation M po/br.po commit 58a073303977708516d3a1ff4528a7ef7ace7f26 Author: Marcus Carlson Date: 2009-09-29 Adds an option to select the application to open an unkown file type upon error opening the file. https://bugzilla.gnome.org/show_bug.cgi?id=92497 M libnemo-private/nemo-mime-actions.c commit d013bf32daa0db99693bc86b6930b56c3d59b42a Author: Kostas Papadimas Date: 2009-09-29 Updated Greek translation. M po/el.po commit 3dd2ddccb759b41762026de8c3f82b0257a73ff8 Author: Jennie Petoumenou Date: 2009-09-29 Updated Greek translation M po/el.po commit 8fe1a569690abd8a472041886b883b55852d445f Author: Marcus Carlson Date: 2009-09-29 Add multiselect capability to list view Use Ctrl+shift to do multiple range selects (#410497) M src/file-manager/fm-list-view.c commit 0b8af64dc9ca5994215362f163e2c09a2d79e9bd Author: Jorge González Date: 2009-09-28 Updated Spanish translation M po/es.po commit 6abf7ba3b026306493ee40f8164e7f632f5c5265 Author: Marcus Carlson Date: 2009-09-28 Add checkbox for not associating a filetype on open with https://bugzilla.gnome.org/show_bug.cgi?id=92497 M libnemo-private/nemo-open-with-dialog.c commit b6112210f2b4c26951c4104a5d46d5b54ec58e2b Author: Alexander Larsson Date: 2009-09-28 Bump version to 2.29.1 on master M configure.in commit 80e87af1b4956e0c1dcb252564a71cf51286ab3f Author: A Date: 2009-09-28 Fix Bug 593523 - Typo in nemo volume mgmt. M src/file-manager/fm-directory-view.c commit 08e6114dbdf4553b4bcc12a38b0955da153c8efe Author: Jürg Billeter Date: 2009-09-23 Update tracker support for version 0.7 Fixes bug 596082. M configure.in M libnemo-private/nemo-search-engine-tracker.c commit a2a7f3a2a7909824c7a2643d9251c0e74f17b548 Author: Timo Jyrinki Date: 2009-09-25 Update Finnish translation (transition from â€taltio†to â€asemaâ€) M po/fi.po commit 541c225fea1d616d01862d0f6b0ff9086317540a Author: Tomas Bzatek Date: 2009-09-24 Don't rely on activation_uri when detecting mounts We test for the activation_uri (i.e. G_FILE_ATTRIBUTE_STANDARD_TARGET_URI) which is usually not exposed from computer:// items until the item is mounted (and that's up to particular gvfs volume monitor). Simply don't test for activation_uri, file type of G_FILE_TYPE_MOUNTABLE should be enough. This fixes https://bugzilla.redhat.com/show_bug.cgi?id=518570 M libnemo-private/nemo-directory-async.c commit e15707648d6d92abe455107718a1e0a440c7fe1f Author: Christian Neumair Date: 2009-09-24 Correctly position icons for text, netscape URI and URI list drops When dropping text, a netscape URI or a URI list to the desktop, remember the position where the drop happened and position the created icon accordingly. Fixes #350022. M src/file-manager/fm-directory-view.c commit 069494e971bba9bfad5cd6997ecf9138677a9bc0 Author: Takayuki KUSANO Date: 2009-09-23 Fix Japanese translation M po/ja.po commit 6fec4348ef56f1df6f7609f9632a5bf4c6512e4d Author: Takayuki KUSANO Date: 2009-09-23 Updated Japanese translation M po/ja.po commit 1055993807fe882a3588f59fe0d93b0b0bb063d8 Author: Alexander Larsson Date: 2009-09-21 Post release version bump M configure.in commit c3b8ec1d6927ccc743e57c315cc2a3ba007ec769 Author: Alexander Larsson Date: 2009-09-21 Update for 2.28.0 release M NEWS M configure.in commit 9fc52ea33822f02e2b5ab876f7ae3ddbcea67523 Author: Shankar Prasad Date: 2009-09-21 Updated Kannada(kn) translation M po/kn.po commit 0cdc94d5345c17e2e929dbd18290ad3e933eb3e5 Author: Petr Kovar Date: 2009-09-20 Updated Czech translation by Lucas Lommer Thanks goes to Tomas Bzatek. M po/cs.po commit cd62ad01e18c0b3b0932af4a9262da1906f2f63a Author: Amitakhya Phukan Date: 2009-09-20 Updating Assamese translations M po/as.po commit 40df45a49785a31c2bdbafef3c8a99766333c5a1 Author: A S Alam Date: 2009-09-19 Updating Translation for Punjabi by A S Alam M po/pa.po commit 8823a3815e0dfcdf92059140d72556ab3acd3b8e Author: Theppitak Karoonboonyanan Date: 2009-09-19 Updated Thai translation. M po/th.po commit 0f075e8e97ad070796584d086678c0e1ad539188 Author: Takayuki KUSANO Date: 2009-09-19 Updated Japanese translation M po/ja.po commit 752e68860bd37941c5fdef3ae29113d12f8dc195 Author: Manoj Kumar Giri Date: 2009-09-18 Upadated Oriya Translation M po/or.po commit 7242f95d083cebfff768d693d2ebf4282154d508 Author: Matej UrbanÄiÄ Date: 2009-09-18 Updated Slovenian translation M po/sl.po commit a728376835fdd39fa505acb84584f7d2600801f2 Author: Luca Ferretti Date: 2009-09-18 Updated Italian translation M po/it.po commit a8097e57788ad735227489e6c51d06bedc796889 Author: Alexander Larsson Date: 2009-09-18 Don't load files for thumbnailing that we can't thumbnail anyway When zooming out we read the real image and use that as the thumbnail. However, we should only do this for files gdk-pixbuf can read as other things can't be read anyway and may potentially be very large (such as videos) since the thumbnail size limit only applies for images. M libnemo-private/nemo-file.c M libnemo-private/nemo-thumbnails.c M libnemo-private/nemo-thumbnails.h commit 4a88ecde61a52ac058999d95388ade9f668482d4 Author: Maxim V. Dziumanenko Date: 2009-09-17 Added Ukrainian translation M po/uk.po commit 51a2a0abd0bd3f6f36737b5afef3ff49a7fa602c Author: Denis ARNAUD Date: 2009-09-17 Updated breton translation M po/br.po commit 5d641153c201f4cbc4d62ac10eb2437a8be5fb78 Author: Mohammad Anwari Date: 2009-09-16 Updated Indonesian translation by Andika Triwidada M po/id.po commit adc53a499c5c143612d7e9b22340efc38240da1d Author: Ilkka Tuohela Date: 2009-09-15 Updated Finnish translation M po/fi.po commit b5af4e6c9c6af492210514af922aa0ed4029dce6 Author: Ilkka Tuohela Date: 2009-09-15 Updated Finnish translation M po/fi.po commit 8da7fdac2375f5b5d0354926b6c130ced602aaaa Author: Rajesh Ranjan Date: 2009-09-15 hindi update by Rajesh Ranjan M po/hi.po commit ba75188ad883fc3be36ebad0740512b03a6e373c Author: Sweta Kothari Date: 2009-09-15 Updated Gujarati Translations M po/gu.po commit 43275654dc3b762841339f2771137d8013f0fe43 Author: Astur Date: 2009-09-14 Updated Asturian translation M po/ast.po commit bd87d7555759021a012691d59d8707c4118a17c7 Author: Gil Forcada Date: 2009-09-14 Minor fix to Catalan translation M po/ca.po commit 96781b9d29259e175f73b87a30eaadf1e12c7490 Author: Carles Ferrando Date: 2009-09-14 Updated Catalan (Valencian) translation M po/ca@valencia.po commit d6b8cb28c7208e0776bb483cde464472249c73ba Author: Alexander Larsson Date: 2009-09-14 Avoid refing NULL icons M src/file-manager/fm-directory-view.c commit eb05225a794de9c7b9326d1e1c56f54902bb6bb5 Author: Kjartan Maraas Date: 2009-09-14 Update Norwegian bokmÃ¥l translation. M po/nb.po commit 58a9e227e519369bca5c7c9897e386110bdda242 Author: Ani Date: 2009-09-14 Updaeted Malayalam Translations M po/ml.po commit 4fb28a5541e564adff7f3a03582c2cb7ed4e294f Author: Lucian Adrian Grijincu Date: 2009-09-14 Updated Romanian translation M po/ro.po commit 979be859028ba20384eee4f907fc647a060cb9fc Author: Ilkka Tuohela Date: 2009-09-13 Updated Finnish translation M po/fi.po commit 78244d5d698786a98d00ef1513e8294825b8813c Author: Bruce Cowan Date: 2009-09-12 Updated British English translation M po/en_GB.po commit e8610aaf1e276993a9942697decc4dc81a5c0168 Author: Ask H. Larsen Date: 2009-09-12 Updated Danish translation M po/da.po commit da24fa0b829c31c4417fed03374b4ad4f63392e8 Author: Reinout van Schouwen Date: 2009-09-12 * 2009-09-12 Reinout van Schouwen - po/nl.po: Updated Dutch translation M po/nl.po commit 48744242700d5dc9de21ef6c33df8eedb757b715 Author: MiloÅ¡ Popović Date: 2009-09-11 Fixes in Serbian translation M po/sr.po M po/sr@latin.po commit 02ea89fd4f92faade026de9463aca4171f4c04d1 Author: Gabor Kelemen Date: 2009-09-11 Updated Hungarian translation M po/hu.po commit 8c636df9374993990ba8a23bbcb986e572508510 Author: Žygimantas BeruÄka Date: 2009-09-10 Updated Lithuanian translation M po/lt.po commit 46aefc46372624957509f971a325e06fe8249c21 Author: Alexander Larsson Date: 2009-09-10 Make the desktop window native so the backing pixmap is drawn by X Without this X draws the toplevel window background and then the real background is drawn from exposes, which doesn't look nice. Fixes bug #593658 M libnemo-private/nemo-icon-container.c commit 594f76e9231eeadfc7972560cf162e921d66aac6 Author: Denis ARNAUD Date: 2009-09-09 Updated breton translation M po/br.po commit d67e3e2377229e19128a2405b70580448fc5e487 Author: Sweta Kothari Date: 2009-09-09 Updated Gujarati Translations M po/gu.po commit b6e45ba165064f508aedad4212759700f0b99f7d Author: A S Alam Date: 2009-09-09 Updaitng for Punjabi M po/pa.po commit 714e8534c90addab5b795cc39c98142ddea17242 Author: Piotr DrÄ…g Date: 2009-09-09 Updated Polish translation M po/pl.po commit e6e10b6facdd8a7058fa5c283462c9f4777a1079 Author: Sandeep Shedmake Date: 2009-09-08 Updated Marathi Translations M po/mr.po commit 21e5e7d3898764a8d493dede40606a9b9e6aa7aa Author: Alexander Larsson Date: 2009-09-08 Free get_types_table internal hashtable on exit M libnemo-private/nemo-thumbnails.c commit 5b075cfa665d07ee6c57e68f6f67aaca76a3b308 Author: Alexander Larsson Date: 2009-09-08 Fix minor leak M src/nemo-application.c commit d442315c303db2def885a00d0abed257156185ce Author: Alexander Larsson Date: 2009-09-08 Free return value from nemo_file_get_metadata_list M src/file-manager/fm-list-view.c commit 75298a3ded74e42b047f95f0746ea3dca8e0a6b7 Author: Alexander Larsson Date: 2009-09-08 Print leaked unique eel_ref_str:s at exit M eel/eel-string.c commit b698cf1932da077f07d99966a4c61568a1ae081e Author: Alexander Larsson Date: 2009-09-08 Fix threadsafety issue in eel_ref_str_unref Its not safe to just decrement count if we didn't read a 1, as we could race with another decrement. M eel/eel-string.c commit 26714114eefe841c4b3eaa5a3a93b50ec69f76a8 Author: Alexander Larsson Date: 2009-09-08 Don't leak list of gconf entries M libnemo-private/nemo-desktop-directory-file.c commit 2434bd43cd43eb8ba97b1a956e4b3cd734cf2a91 Author: Alexander Larsson Date: 2009-09-07 Fix usage of sink, fixing many recently introduced leaks. The conversion away from gtk_object_sink was done wrongly causing lots of leaks. fix this. M eel/eel-background.c M eel/eel-gtk-extensions.c M libnemo-private/nemo-dnd.c M src/file-manager/fm-list-view.c M src/file-manager/fm-tree-view.c M src/nemo-emblem-sidebar.c M src/nemo-history-sidebar.c M src/nemo-information-panel.c M src/nemo-notes-viewer.c M src/nemo-places-sidebar.c M src/nemo-spatial-window.c commit b4cd0d66db105822bfa5531a146428b548aff369 Author: Alexander Larsson Date: 2009-09-07 Update to latest foocanvas This has some cleanups and fixes a memory leak that was introduced in the eel copy by removing gtk_object_sink. M eel/eel-canvas-rect-ellipse.c M eel/eel-canvas-rect-ellipse.h M eel/eel-canvas-util.c M eel/eel-canvas.c M eel/eel-canvas.h commit b17f8f7995aa1ba2b62d8272436d761bc1600bb1 Author: Alexander Larsson Date: 2009-09-07 Don't leak file metadata M libnemo-private/nemo-file.c commit 7c2c5f904d183d510e9fb4f4ac07fe7660274692 Author: Alexander Larsson Date: 2009-09-07 Free "remaining" returned from GOption M src/nemo-main.c commit 26a91c8e225f01363976485c782840135d50e6d8 Author: Alexander Larsson Date: 2009-09-07 Centralize extra view ref and sink if required Doing this in only one place makes sense as its clearer. Previously we ref:ed one extra time for the window->view ref but left the floating ref to be taked when adding the widget to a parent. This breaks when we free the view before adding it to a parent, so we need to properly sink it. M libnemo-private/nemo-view-factory.c M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-empty-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c commit c302620c144c7968c7ae35b45ab55a3124fd2923 Author: Alexander Larsson Date: 2009-09-07 post release version bump M configure.in commit d0a6955e983ba112a65140ce3b55a7dd953fd8e8 Author: Alexander Larsson Date: 2009-09-07 Update NEWS M NEWS commit bd108f3700594e5c859d89287a59733a5585e4d9 Author: Padraig O'Briain Date: 2009-09-07 Don't crash on NULL gconf value This fixes bug #589520 M libnemo-private/nemo-desktop-directory-file.c commit 02a7a84229063f329731d3db61184207a91bf12e Author: Chao-Hsiung Liao Date: 2009-09-06 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit 3af7944871692b9e0c0754ed5351ac24d2a6f9ff Author: Khaled Hosny Date: 2009-09-05 Updated Arabic translation M po/ar.po commit 41a15a48a2d452078ae7845374ad9577b30e8155 Author: Ivar Smolin Date: 2009-09-05 Updating Estonian translation M po/et.po commit 7553bdccaddb56be2b156dfcd1e409ea30b870a7 Author: Mario Blättermann Date: 2009-09-04 Updated German translation M po/de.po commit 13ecc3e0eef4d9267f9919cd79180c0ed4ce4bbf Author: Duarte Loreto Date: 2009-09-04 Updated Portuguese translation M po/pt.po commit 2a562f03810a31a0cd2be36faff5059dab2b8fe2 Author: MiloÅ¡ Popović Date: 2009-09-01 Updated Serbian translation M po/sr.po M po/sr@latin.po commit 3901a97853dad9bf2d586e401a2542aa86703e65 Author: Kjartan Maraas Date: 2009-09-01 Update Norwegian bokmÃ¥l translation. M po/nb.po commit 40164f40de5bcfec618da3f200eff5d2371f4bde Author: Shankar Prasad Date: 2009-09-01 Updated Kannada(kn) translation M po/kn.po commit e9b017891f7ab2586b92f4111637b2d02b0f4a51 Author: krishnababu k Date: 2009-08-31 Updated Telugu Translations M po/te.po commit 2cf936c4105f88a953f91c8bdf37d65553681684 Author: Joan Duran Date: 2009-08-30 Updated Catalan translation M po/ca.po commit 4d9e7a5bf3d180ae47b789b90ee56fc2cbde24c3 Author: Baris Cicek Date: 2009-08-30 Updated Turkish translation. M po/tr.po commit cf32d3a9429a08fa5fd9557c57e896d85064e9da Author: Inaki Larranaga Murgoitio Date: 2009-08-29 Updated Basque language M po/eu.po commit bd4180156f506861b335a71a4d6e54886a237527 Author: Bruno Brouard Date: 2009-08-28 Updated French translation M po/fr.po commit 04e3be13647469de3fe97c15b2fab28eb1cdd81c Author: Inaki Larranaga Murgoitio Date: 2009-08-27 Updated Basque language M po/eu.po commit 542f56ecb2af09c78dd7507d6e9f10b96d4d2e34 Author: Runa Bhattacharjee Date: 2009-08-27 Updated Bengali India Translations M po/bn_IN.po commit e6ef2d96f6adc507425123716961aa48281af83d Author: A Date: 2009-08-27 Fix test in uninhibit code M libnemo-private/nemo-file-utilities.c commit bf6bfde36bcadf43a39fb095650b7fc78741d62a Author: Matthias Clasen Date: 2009-08-26 Fix a duplicate id in a .ui file This caused nemo-file-management-properties to crash. M src/nemo-file-management-properties.ui commit 064086ef68a0692ac9050b7a0d3ded4a836c8180 Author: Marcus Carlson Date: 2009-08-26 Always show app icon for open-with in the popup menu as in the normal menu Fixes bug #591663. M src/file-manager/fm-directory-view.c commit 3bd3f5f4d7a8ef10c6133c5957025df1560e9185 Author: ifelix Date: 2009-08-26 Updated Tamil Translations M po/ta.po commit b151573894ee19b4c13f3d35ac5cac7660caee63 Author: Henrique P Machado Date: 2009-08-24 Updated Brazilian Portuguese translation. M po/pt_BR.po commit 324e267fc916d5f16e505c2f57a69c271c1388ee Author: Alexander Larsson Date: 2009-08-24 Post release version bump M configure.in commit c685eae6206409ca4bbcec4c74367e5295f40461 Author: Alexander Larsson Date: 2009-08-24 Update NEWS M NEWS commit c1755706945092334af274f3a88049976baa4763 Author: Alexander Larsson Date: 2009-08-24 Bump version to 2.27.91 M configure.in commit d8337a4b7969b43bf5712cd5e85dc5f936ed5044 Author: Ryan Lortie Date: 2009-08-22 Cancel audio preview when deleting the file Fixes #137500. M src/file-manager/fm-icon-view.c commit b9cd9a5810e044c9351d2408186fb135f4452635 Author: Jamil Ahmed Date: 2009-08-24 Updated Bengali translation M po/bn.po commit 8ddb1d53eaa01f4c076c4d96e8da1a9a812e303b Author: Changwoo Ryu Date: 2009-08-23 Update Korean translation M po/ko.po commit da36928ac4d0989d2b6c3d54f7dc522fca7491ab Author: Seán de Búrca Date: 2009-08-22 Updated Irish translation M po/ga.po commit 97915f97bcbd047de2a5fd4b6bf25b01436085d3 Author: Alexander Shopov Date: 2009-08-22 Updated Bulgarian translation M po/bg.po commit 4a7af52ab6f964b9174b59e3f71252447158ffa4 Author: Antón Méixome Date: 2009-08-19 Updated Galician Translation M po/gl.po commit 72f65592a84cb8e9ad2ccaa6bbfd7fe4fbe7371b Author: Alexander Larsson Date: 2009-08-18 Migrate old nemo metadata to gvfs on startup If ~/.nemo/metadata/migrated-to-gvfs doesn't exist, migrate and create it. M src/Makefile.am M src/nemo-application.c commit 1d14824dc8ab6f1f8573b07c11ce437ae22dc77b Author: Alexander Larsson Date: 2009-08-17 Add nemo-convert-metadata tool This can be used to convert old-style nemo metafiles to gvfs metadata. M src/Makefile.am A src/nemo-convert-metadata.c commit a557cf30fe1f3761901a7248106840add2c1d105 Author: Alexander Larsson Date: 2009-08-18 Move NEMO_DESKTOP_METADATA_GCONF_PATH to nemo-metadata.h Need this in the metadata conversion code M libnemo-private/nemo-desktop-directory-file.c M libnemo-private/nemo-metadata.h commit 7c316ae074658c8927e48ea00f4305767ea9f7dd Author: A. Walton Date: 2009-08-13 Bug 587316 – Truncate file names when deleting Files with extremely long file names could cause the dialog box to become wider than the screen. Based on a patch contributed by Marcus Carlson. M libnemo-private/nemo-file-operations.c commit ce36628b3d615204eebd60a9df67b88857321965 Author: Yaron Shahrabani Date: 2009-08-14 Updated Hebrew translation M po/he.po commit e0446d33be8ce22d1925c60db6a9b26c232020a8 Author: Jochen Skulj Date: 2009-08-13 Updated German translation M po/de.po commit 39b18f636baddcc3de5866ef3dbb6d66dc344a37 Author: Rajesh Ranjan Date: 2009-08-13 Updated Hindi Translations M po/hi.po commit bbdb3b31455d462c18afa3764293f06fb81df54b Author: Daniel Nylander Date: 2009-08-13 Updated Swedish translation M po/sv.po commit 477fdafe22aa0e3cb78ab73c7ec4e205468c0a75 Author: Matthias Clasen Date: 2009-08-12 Fix a typo M libnemo-private/apps_nemo_preferences.schemas.in commit e8f0c90ab9444511311f300f6b0596df01c38f1e Author: Seán de Búrca Date: 2009-08-11 Updated Irish translation M po/ga.po commit 13b85463fb7b9af0faac01b30e8459545e87b6f0 Author: Mattias Põldaru Date: 2009-08-11 Updating Estonian translation M po/et.po commit fdb2ccedb2bfd3b2d6dfd5759913875b8d93834a Author: A. Walton Date: 2009-08-10 Fix unintiallized GError in power management M libnemo-private/nemo-file-utilities.c commit f77c52ec952f25170338e6e896af035b4ef55cfe Author: Jorge González Date: 2009-08-10 Updated Spanish translation M po/es.po commit 37e7ceca45aea48129cf55ea2583f23330d26b91 Author: A. Walton Date: 2009-08-10 Bug 334806 – Inhibit power-manager when copying files Introduces code to inhibit GNOME power manager whenever a file operation which may not complete quickly is running. M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file-utilities.h commit 4dd0fdef1d77cb6b9be83348ff5c00293e14a991 Author: Ivar Smolin Date: 2009-08-10 Updating Estonian translation M po/et.po commit fa1d8989b1b3e4d18c3f4c097d57c76ff86a7387 Author: Luca Ferretti Date: 2009-08-09 Remove unused variable to fix the build M src/nemo-navigation-window-menus.c commit 3c5be2ea6403ad071da5e350332e2890d9d53994 Author: Khaled Hosny Date: 2009-08-08 Updated Arabic translation M po/ar.po commit eb585679b6e4fad7d252a7458177c4e0a8468298 Author: Matthias Clasen Date: 2009-08-08 Always show icons in places menu in spatial mode. Part of bug #590647. M src/nemo-spatial-window.c commit 826d5237d2ea179006b62def4db376544e74d764 Author: Marcus Carlson Date: 2009-08-08 Always show icons in the history and go menu. Part of bug #590647. M src/nemo-navigation-window-menus.c M src/nemo-window-menus.c commit 9cba51e5cb8827997eb4203c6eed4614efa34aaa Author: Marcus Carlson Date: 2009-08-08 Always show application icons in popup menus. Part of bug #590647. M src/file-manager/fm-directory-view.c commit 1604ee0ceb8026aff744981b893d8fc8da25ec6c Author: Seán de Búrca Date: 2009-08-06 Updated Irish translation M po/ga.po commit 339017547f1aa41d90cf31a6b985588f3ff64e4a Author: Antón Méixome Date: 2009-08-06 Updated Galician Translation M po/gl.po commit 47af29868f527a93acb1822b6bdb2537253a387e Author: Kjartan Maraas Date: 2009-08-06 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit a0b11f325a221c7ca46811ada00bad1035e4857a Author: Khaled Hosny Date: 2009-08-06 Misc. fixes to Arabic translation M po/ar.po commit 85bb10a2b4f7230e7a0aa5b9945d155c1a21b2b4 Author: Khaled Hosny Date: 2009-08-05 Updated Arabic translation M po/ar.po commit f8f6a95bc05353b4a68c07fc710742b9bcdc7d0d Author: A. Walton Date: 2009-08-03 Fix crash in connect server dialog Under custom locations, entering no URI will crash. M src/nemo-connect-server-dialog.c commit cfa61d576da08590bec118ce1ed03e7189a974b2 Author: A. Walton Date: 2009-08-03 Reorder assignments in mime application chooser Writing over toggle_renderer with the wrong cell renderer. M libnemo-private/nemo-mime-application-chooser.c commit a8ca44f54aea29ccb2eb0163f8ffe670fd6761b1 Author: A. Walton Date: 2009-08-03 Reverse back/forward mouse button sense. Be consistent with Firefox, etc. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M src/nemo-navigation-window.c commit aa5dbe04bc2d92e2603b34d44f486fd2bae95169 Author: Seán de Búrca Date: 2009-07-31 Updated Irish translation M po/ga.po commit 6d648632b8978590befcd867bd2c9920b6aa49ff Author: Alan Monfort Date: 2009-07-31 Updated breton translation M po/br.po commit 838d31d11e3fed0d98642397c9d986ddd5bea390 Author: Denis Arnaud Date: 2009-07-30 Updated breton translation M po/br.po commit e7d2f70203673d9a294460df164aec295db17234 Author: Denis Arnaud Date: 2009-07-30 Updated breton translation M po/br.po commit 97d348f792a2659fbb88de17d25e83c93b14414c Author: Vincent Untz Date: 2009-07-28 Respect /desktop/gnome/lockdown/disable_command_line We need to show/hide the "New Launcher" menu item in the context menu, depending on this gconf key. M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/file-manager/fm-actions.h M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-directory-view.c commit 359fa218a1a890bb87fb331acc30d62b57bc7c61 Author: Ivar Smolin Date: 2009-07-27 Updating Estonian translation M po/et.po commit aac26f4c0fce20e7cac87ca51c0629458e804ee8 Author: Mattias Põldaru Date: 2009-07-22 Updating Estonian translation M po/et.po commit 44c05bbc866fb4430a16b169aa3854bab1af6555 Author: drtvasudevan Date: 2009-07-21 Updated Tamil translation M po/ta.po commit c0c9bbc96228a8864eda9d0b7f4c82c7d1c0dba4 Author: Ivar Smolin Date: 2009-07-20 Updating Estonian translation M po/et.po commit 2a94803b44010e3c47a9f7b94894fab8d6062abc Author: Jaap A. Haitsma Date: 2009-07-18 Fix handling of small images/icons Small images with an alpha plane don't get a frame Use different scaling strategy for small images. Small images/icons won't get up scaled in default zoom view. They are shown in their actual Fixes bug #585186 M libnemo-private/nemo-file.c commit a8f82a8a00f672a3111d97070c3a6f34e2b46c90 Author: Chao-Hsiung Liao Date: 2009-07-18 Updated Traditional Chinese translation(Hong Kong and Taiwan) M po/zh_HK.po M po/zh_TW.po commit bd6db659cb232d8b8f81a9ada748025aa1d16fff Author: Alexander Larsson Date: 2009-07-14 Clean up metadata key names now that they are public Prefix all internal keys with "nemo-". Use dash, not underscore as delimitor (this is what gio file attrs use) Rename "keyword" to "emblems" Rename "default_component" to "nemo-default-view" M libnemo-private/nemo-file.c M libnemo-private/nemo-metadata.c M libnemo-private/nemo-metadata.h M src/nemo-window-manage-views.c commit c2951134aac83f4e8194e7cb71a92b5f9d273100 Author: Sweta Kothari Date: 2009-07-14 Updated Gujarati Translations M po/gu.po commit 53bcaac5fd2cf03f686f19dbdc9d889480cd8709 Author: Cosimo Cecchi Date: 2009-07-14 Post-release version bump M configure.in commit 608b7f5c2ab1c6e9c0d011e3fef3b506afa5f8ba Author: Cosimo Cecchi Date: 2009-07-14 Update for 2.27.4 M NEWS M configure.in commit e4b5573bec0215006201b9a0dda60888a32debe6 Author: Cosimo Cecchi Date: 2009-07-14 Comment out the metadata tests for now M libnemo-private/nemo-directory.c commit 91cec6f5e6bbc672d2cebef162ea797eb5e9d55d Author: Sweta Kothari Date: 2009-07-13 Updated Gujarati Translations M po/gu.po commit 9ca82f0443f49bb80beb050f1d1bb3ef2a338698 Author: Maxim V. Dziumanenko Date: 2009-07-09 Updated Ukrainian translation M po/uk.po commit 3bd36d1a3b6f576e124a41800d7138cbfa34782f Author: Maxim V. Dziumanenko Date: 2009-07-09 Updated Ukrainian translation M po/uk.po commit fd9df908248be20bc5f79def1dd96a45bb9f56c8 Author: Cosimo Cecchi Date: 2009-07-09 Don't force no horizontal scrollbar in the note viewer This causes issues with long words in the notes viewer, as the window will grow bigger along with the word. Patch by Luke Symes, fix bug #399018. M src/nemo-notes-viewer.c commit c1b58565da21a6d9e95dc920afd632da6e906fc9 Author: drtvasudevan Date: 2009-07-09 Updated Tamil translation M po/ta.po commit 560e736891e9268c73171ef3afbbc5c2bde819b9 Author: Jorge González Date: 2009-07-08 Updated Spanish translation M po/es.po commit 72a17d86468291eb64fdc549753836e76e3add6a Author: Daniel Nylander Date: 2009-07-08 Updated Swedish translation M po/sv.po commit 2eb7e673837b32fe8c7d9b4431fd76213a908a3a Author: Wang Yan Date: 2009-07-04 Don't display the timeout dialog with broken launchers Don't display the timed wait dialog if we're already reporting a broken link to the user. Fix bug #579165. Signed-off-by: Wang Yan M libnemo-private/nemo-mime-actions.c commit 45c928d3cf112f22d69b25299898301c54d9e961 Author: Cosimo Cecchi Date: 2009-07-08 Use application icons in the context menu If it's possibile, use the application icons in the open with submenu. This also removes quotation marks and useless duplicate "Open With" strings from the submenu. Patch by Marcus Carlson, fixes bug #587533 and #546916. M src/file-manager/fm-directory-view.c commit 4b434c4f73b56a92ff4bf50435487357719eebaf Author: Cosimo Cecchi Date: 2009-07-08 [build] bump up the required version of GLib M configure.in commit cf5538067776605cb031a58ce2f77271375db498 Author: David Zeuthen Date: 2009-06-30 Bug 587486 – Pass GMountOperation to unmount/eject/stop ops - Port everything to use _with_operation() variants of unmount/eject methods - This includes changing the NemoFile a bit; see the patch for details - Add support for g_drive_can_start_degraded() so we offer to start (degraded) drives even when g_drive_can_start() returns FALSE - Also add support for new mountable::* attributes so we can have "Detect Media" items in the context menu when right-clicking mounts/volumes/drives in computer:/// and on the desktop M libnemo-private/nemo-desktop-icon-file.c M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-vfs-file.c M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml M src/nemo-application.c M src/nemo-places-sidebar.c commit 8b7599a8897e5f5314b8637e7523f35285db118c Author: Daniel Nylander Date: 2009-07-07 Updated Swedish translation M po/sv.po commit 547fa8e9f8fe654b92d5b8b0f2dcc074a7ad91d8 Author: Claude Paroz Date: 2009-07-07 Updated French translation Contributed by Laurent Coudeur and Claude Paroz M po/fr.po commit 9da3dacb61a5f70b0b5a62c57f3278169fdea56a Author: Jorge González Date: 2009-07-07 Updated Spanish translation M po/es.po commit f24c7689e1efb27dd2953bdee7de8c02f183d9be Author: Alexander Larsson Date: 2009-06-30 Properly escape names used as gconf keys M libnemo-private/nemo-desktop-directory-file.c commit b8995fce159472dac07666dfb4d7e3ff1412403a Author: Alexander Larsson Date: 2009-06-29 Support metadata for the virtual desktop icons M libnemo-private/nemo-desktop-directory-file.c M libnemo-private/nemo-desktop-directory-file.h M libnemo-private/nemo-desktop-icon-file.c M libnemo-private/nemo-global-preferences.c commit 02f908f3d864f1f3bf0729158907f312e0306c05 Author: Alexander Larsson Date: 2009-06-29 Move metadata setting to a NemoFile vfunc This allows non-vfs backends to implement metadata M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-vfs-file.c commit 28d5e790dbe7752de156e01610c3e5c354064192 Author: Mattias Põldaru Date: 2009-06-26 Updating Estonian translation M po/et.po commit 65425491f90194e3034b5b49e0e333b5717d1776 Author: Alexander Larsson Date: 2009-06-26 Forgot to remove some references to removed symbols M libnemo-private/nemo-file-changes-queue.c commit 7874f2d9422618107edabd7056b7167844c389ca Author: Alexander Larsson Date: 2009-06-25 Support unsetting metadata M libnemo-private/nemo-file.c commit 99b68670ad94bfb5db1b162ae0d84e27f226d18f Author: Mattias Põldaru Date: 2009-06-25 Updating Estonian translation M po/et.po commit 22a457fd40d09139e5d7bbe6404006d0e091bc15 Author: drtvasudevan Date: 2009-06-24 Updated Tamil translation M po/ta.po commit 37be3809bc0d25d28298b38bc0b893a6fd3a665f Author: Alexander Larsson Date: 2009-06-23 Remove all traces of former nemo metadata code M libnemo-private/Makefile.am M libnemo-private/nemo-directory-async.c M libnemo-private/nemo-directory-background.c D libnemo-private/nemo-directory-metafile.c D libnemo-private/nemo-directory-metafile.h M libnemo-private/nemo-directory-private.h M libnemo-private/nemo-directory.c M libnemo-private/nemo-file-attributes.h M libnemo-private/nemo-file-changes-queue.c M libnemo-private/nemo-file-changes-queue.h M libnemo-private/nemo-file-operations.c M libnemo-private/nemo-file-utilities.c M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-link.c D libnemo-private/nemo-metafile.c D libnemo-private/nemo-metafile.h M libnemo-private/nemo-mime-actions.c M src/file-manager/fm-directory-view.c M src/file-manager/fm-properties-window.c M src/nemo-main.c M src/nemo-notes-viewer.c M src/nemo-sidebar-title.c M src/nemo-window-manage-views.c M test/test-nemo-directory-async.c commit fc4e74e6763000bac2a459e83811cf01e6cb7720 Author: Alexander Larsson Date: 2009-06-23 Use gvfs based metadata M libnemo-private/Makefile.am M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h A libnemo-private/nemo-metadata.c M libnemo-private/nemo-metadata.h M src/file-manager/fm-list-view.c commit c7b6875c98ecd25dc26853b783e1a4ffe96fab36 Author: Alexander Larsson Date: 2009-06-23 Add eel_g_strv_equal M eel/eel-glib-extensions.c M eel/eel-glib-extensions.h commit ffc93d52d4650e63e01b488ef582983919c89de3 Author: A. Walton Date: 2009-06-22 Another missed FreeBSD build fix. M libnemo-private/nemo-metafile.c commit 08144422c582077664b878fecc9878fc785b94df Author: Petr Kovar Date: 2009-06-21 Fixed Czech translation by Lucas Lommer Thanks goes to Vladimir Burian. M po/cs.po commit 22c5e7beacd28a64b4ff82ad20df0c954128ba46 Author: Jorge Gonzalez Date: 2009-06-21 Updated Spanish translation M po/es.po commit 104557839d2cfb375e5729e17c3fba3810f538e7 Author: Ivar Smolin Date: 2009-06-19 Updating Estonian translation M po/et.po commit dec816b65de82e832e29c0cea1a8c330ffa5954a Author: A. Walton Date: 2009-06-19 Fix the build. self_start_stop_type uninitialized in fm-directory-view.c M src/file-manager/fm-directory-view.c commit bcf5f921cda6f582230d3d0707f93172c3fa65e6 Author: A. Walton Date: 2009-06-19 Bug 586346 – Build failure on FreeBSD Wasn't the wrong number of arguments, it was the wrong type of argument (time_t, not long). So we add a cast to make it more explicit to the compiler there. M libnemo-private/nemo-file.c commit 0fe78fa2ae3d1a1e46996cc27c66421965bce57c Author: A. Walton Date: 2009-06-19 Bug 586346 – Build failure on FreeBSD Use g_snprint() instead of snprintf(). M libnemo-private/nemo-file.c commit 66b53e82aa5d45cec89c99ab74e86caf2c49df00 Author: David Zeuthen Date: 2009-06-17 Bug 585591 – Starting/stopping drives This is the Nemo user for the new GIO API for starting/stopping drives. See http://bugzilla.gnome.org/show_bug.cgi?id=585591 for details. M libnemo-private/nemo-file-private.h M libnemo-private/nemo-file.c M libnemo-private/nemo-file.h M libnemo-private/nemo-mime-actions.c M libnemo-private/nemo-vfs-file.c M src/file-manager/fm-actions.h M src/file-manager/fm-directory-view.c M src/file-manager/nemo-directory-view-ui.xml M src/nemo-places-sidebar.c commit 3af5d8c5bf61bdf206b9c79df0c27c0152b46496 Author: Mattias Põldaru Date: 2009-06-18 Updating Estonian translation M po/et.po commit 9ff24d6790da178fb8cba9c3c150a04ff4afea74 Author: Ivar Smolin Date: 2009-06-17 Updating Estonian translation M po/et.po commit 06e4eb732621b01c624b0e2665de523396e99f2f Author: Vincent Untz Date: 2009-06-17 Use gtk_cell_layout_get_cells instead of deprecated API M src/nemo-places-sidebar.c commit a2c338278cb82c4a2d8c4175d1db9ca7d7985d43 Author: A. Walton Date: 2009-06-17 Revert last commit as discussion in #gnome-hackers Turns out, g_app_info_should_show() is really broken, as this hides some apps we shouldn't be hiding. Wondering how we can unbreak this.. M libnemo-private/nemo-open-with-dialog.c commit e9d7b28a49d2afa5d67a34ef568a9e390df9a052 Author: A. Walton Date: 2009-06-17 Bug 586040 – "Open With" dialog duplicates Turns out, Nemo was showing GAppInfo's which shouldn't be shown in the UI. M libnemo-private/nemo-open-with-dialog.c commit b800160b430c17ddae5621a9af8b498d9092883d Author: A. Walton Date: 2009-06-16 Bug 563906 – Grammatical Error in String Fixes this bug. M src/nemo-window-manage-views.c commit 41975360a57115b5223e3466517df66b45c3fb63 Author: Alexander Larsson Date: 2009-06-15 Call g_reload_user_special_dirs_cache() when xdg-user-dirs change This means we will get the new special file icon for the changed files. Also, invalidate the file when we change it ourself so that the icon change is picked up. M libnemo-private/nemo-file-utilities.c commit a1ea86bd6c3d1123463e377e362dfffd047ef6a5 Author: Alexander Larsson Date: 2009-06-15 Post release version bump M configure.in commit e524b867b2653f6f92c8fb44f4b347b5fbc23c2c Author: Alexander Larsson Date: 2009-06-15 Update NEWS for 1.3.1 M NEWS commit b3f20601fe476d0af7b1175b14d9cb6729b96795 Author: Daniel Nylander Date: 2009-06-13 Updated sv translation (Daniel Nylander) M po/sv.po commit 5abcdbd43ef07460970ff2080dae121d908a0432 Author: A. Walton Date: 2009-06-12 Bug 547749 – "Open with" Applications not sorted. Use a sort model and add a sortable column to sort the application by name. M libnemo-private/nemo-open-with-dialog.c commit 932fa70aade6c12b1ef7a0158c0247e79546452c Author: Jorge Gonzalez Date: 2009-06-11 Updated Spanish translation M po/es.po commit 7ef11edc4d1819fe40b9c238e4d4ed31c07a9f0e Author: Manoj Kumar Giri Date: 2009-06-10 Added entries for Hindi Translation updated by Rajesh Ranjan M po/ChangeLog commit c0a359c656280dc504ea138b9e52763852ea202a Author: Manoj Kumar Giri Date: 2009-06-10 Updated Hindi Translation on behalf of Rajesh Ranjan M po/hi.po commit 4cf7e22dc55b37e5678ff69ac02d4acc5ac989fa Author: Kjartan Maraas Date: 2009-06-10 Updated Norwegian bokmÃ¥l translation. M po/nb.po commit 2316b80240b7b3c4e9627f31779b31d31cb1418d Author: Ivar Smolin Date: 2009-06-09 Updating Estonian translation M po/et.po commit 8db758307d49bf94c6e379b4439bb1fc61b7e28a Author: Cosimo Cecchi Date: 2009-06-08 Use a better string for schemas (#585134) M libnemo-private/apps_nemo_preferences.schemas.in commit 73443aae586eb99e6ca4406a03d91544def77968 Author: Runa Bhattacharjee Date: 2009-06-08 Updated Bengali India Translation M po/bn_IN.po commit 03e8e436fe57369ee1d28cfef77791dc258e8f22 Author: Mattias Põldaru Date: 2009-06-08 Updating Estonian translation M po/et.po commit 26d6ec74a5ebac6fb64e6ce0484ed96eefa7a78f Author: Petr Kovar Date: 2009-06-07 Fixed Czech translation by Lucas Lommer Thanks goes to Kamil Paral. M po/cs.po commit 437b01afc7ee7325ec8ba65bea05a13ef072063a Author: A. Walton Date: 2009-06-05 Bug 583214 – Nemo aborts when giving an empty dest. Follow up commit which fixes the code formatting and ensures the 'Open' button is insensitive when the entry is empty. M src/nemo-location-dialog.c commit 7b7a40130eb556fc7f32fb21a73c6437b29b0c73 Author: Christian Persch Date: 2009-06-04 Correct "srdcir" typo to "srcdir" M Makefile.am commit aa1afee5cc5b96161b6bb7c1639a180a39850653 Author: Theppitak Karoonboonyanan Date: 2009-06-04 Updated Thai translation. M po/th.po commit c0aa87793104abbea45fb1791a1a1cbb771f8b99 Author: Ask H. Larsen Date: 2009-05-30 Updated Danish translation M po/da.po commit 5bff677a0dc3ab5d5c68a2ef107cdbb34f133b34 Author: Cosimo Cecchi Date: 2009-05-28 Remove useless statfs/statvfs checks Those checks are now obsoletes. This also fixes bug #583264. M configure.in M src/file-manager/fm-properties-window.c commit 0133e979531cd41ca7f1d76ff5adf66ddfa7d67a Author: Cosimo Cecchi Date: 2009-05-28 Clear text in the location entry Add a clear text icon in the location entry, now that the icon entry is available in GTK+ 2.16 (#145732). M src/nemo-connect-server-dialog.c M src/nemo-location-entry.c commit 7b86b78e2ff6a0f1b45ac8f8a9c30cf3d0c6ae96 Author: Cosimo Cecchi Date: 2009-05-28 Emit APPEARANCE_CHANGED when setting the bg color Emit the APPEARANCE_CHANGED signal when we're setting the color, as we're ignoring the pending changes after the backgorund is realized, and thus we're not getting color updates (#578136). M eel/eel-background.c commit 518a1ae6ba0a3e09236f944ee655334087d5ddee Author: Cosimo Cecchi Date: 2009-05-28 Display information about the selected object Display information about the selected object in the "Information" sidebar, using thumbnails if possible. Also, remove the "Open with" buttons there for directories. Fix bug #122045, thanks to Amos Brocco. M src/nemo-information-panel.c M src/nemo-sidebar-title.c commit 4bb61206b7dd4a3510ab15e8df0288e670f816d6 Author: Alexander Larsson Date: 2009-05-27 Dist COPYING.EXTENSIONS M Makefile.am commit 7d9b6812d006d9aeecfb33d072cb382184fb901b Author: Alexander Larsson Date: 2009-05-27 Add COPYING.EXTENSIONS clarifying some extension license issues A COPYING.EXTENSIONS commit 74782b711adccfb85273ac38484e4adac8e010b4 Author: Jorge Gonzalez Date: 2009-05-26 Updated Spanish translation M po/es.po commit 152b56a058dfd0c57cdc267a63fb3099c0c74e0c Author: Yaron Shahrabani Date: 2009-05-25 Updated Hebrew translation M po/he.po commit 5fc840a5f089c627b4e38e2cf99f907ad8abb1a6 Author: drtvasudevan Date: 2009-05-25 Updated Tamil translation M po/ta.po commit 3d8011ca8c095be884b603ccea261b955fa6518b Author: JF Ding Date: 2009-05-25 Support daemon mode (exit_with_last_window preference) This can be used if you want to run nemo just to handle volume monitoring, etc. M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-main.c commit b49db4e5c9a3d21d3bc20c075e76b98b9977eedf Author: drtvasudevan Date: 2009-05-23 Updated Tamil translation M po/ta.po commit 7ea93ff768efdbc106407719b96a46fc34227273 Author: Ivar Smolin Date: 2009-05-19 Updating Estonian translation M po/et.po commit 2a005bc2c308e3960e723ed5cc8748f168acda17 Author: A. Walton Date: 2009-05-19 Bug 583214 – Nemo aborts when giving an empty dest. Fixes crash caused by passing a null path. M src/nemo-location-dialog.c commit 2eb9e588f954f8700d143fdb9d6d1e33318d9a33 Author: Alexander Shopov Date: 2009-05-19 Updated Bulgarian translation M po/bg.po commit d850d4742f41957506500c290c2756193c2a776f Author: Jorge Gonzalez Date: 2009-05-17 Updated Spanish translation M po/es.po commit 9af920dc7ab772c134ecd754be89b5d2b1aab5e0 Author: Petr Kovar Date: 2009-05-17 Fixed Czech translation by Lucas Lommer Phase two. M po/cs.po commit 173731a6dae993b5f15e334f1ebfa4756302efb8 Author: Petr Kovar Date: 2009-05-17 Updated Czech translation by Lucas Lommer M po/cs.po commit de14cf64ec9179a32617b1b26ce28d47aea2d8d9 Author: Matej Urban Date: 2009-05-15 Updated Slovenian translation M po/sl.po commit 1aba1feef00ad87da6e6e775568d3d8fea371576 Author: Matej Urban Date: 2009-05-15 Updated Slovenian translation M po/sl.po commit 776823f11bc40d78d17db36a303d69de0363d090 Author: Matej Urban Date: 2009-05-15 Updated Slovenian translation M po/sl.po commit 5fde2c7156b5bb8c0411bdbe649dd08172853d3a Author: Alexander Larsson Date: 2009-05-13 Don't crash if parent button_press_event is NULL (#582457) This fixes a crash when you press on the empty area of the toolbars. M src/nemo-navigation-window.c commit 24d9d3715194ff1145550a7fe3e9b8414ca568d2 Author: Holger Berndt Date: 2009-04-29 Allow users to define shortcuts for extension menu items M src/nemo-window-menus.c commit a2ab15477e2e2d13642567316788e12b5ace8504 Author: Tomas Bzatek Date: 2009-05-11 Properly include m4 macros fixes error messages like: ./configure: line 19939: syntax error near unexpected token `m4,' ./configure: line 19939: `SHAVE_INIT(m4, enable)' M Makefile.am commit e595852237c70e56c9d56688e2729eb59f6268fb Author: A. Walton Date: 2009-05-11 Bug 549437 – ctrl + dnd file duplication in list view Fixes bug #549437. Patch provided by "logari81". M libnemo-private/nemo-tree-view-drag-dest.c commit 9d618732420d6d2ae9f666bbb78ee486746c7940 Author: A. Walton Date: 2009-05-10 Update About dialog for 2009. M src/nemo-window-menus.c commit bf1fe66266c96139138908c1f1e1b1cc48f2bd4a Author: Marios Zindilis Date: 2009-05-10 Updated Greek translation M po/el.po commit aeda70b4fa90990a538d37122d88f0a82d0578f5 Author: Simos Xenitellis Date: 2009-05-09 Updated Greek translation M po/el.po commit f7d425f9045dae6d1d79328e66019c3ce18b1f19 Author: Simos Xenitellis Date: 2009-05-09 Updated Greek translation M po/el.po commit 35be2bdcd58e20422d2c8f0cf61b6d2a027dfd93 Author: Marios Zindilis Date: 2009-05-09 Updated Greek translation M po/el.po commit a9d7dfc3efb948a88cb5acfce3db8891e3297499 Author: Christian Kirbach Date: 2009-05-06 Updated German translation. M po/de.po commit 8d3525a3c3d414fe67f8f8b3c183c95e1282bce1 Author: Cosimo Cecchi Date: 2009-05-05 Post release version bump to 2.27.2 M configure.in commit 956bf2c75079003c91774a675091f7133cc8be35 Author: Cosimo Cecchi Date: 2009-05-05 Prepare for 2.27.1 release M NEWS M configure.in commit ec4ce1431bda72fc66ace675d860e7c2bb3bc3e6 Author: Cosimo Cecchi Date: 2009-05-05 Fix distcheck M Makefile.am M data/Makefile.am M src/nemo-main.c commit 057dabdd59a24d863d8b10dca336a3ca2bf8609f Author: Shankar Prasad Date: 2009-05-04 Updated the Kannda translations M po/kn.po commit 0a6012a48bd71c20d7cd32c05e1976f1127ce230 Author: Jorge Gonzalez Date: 2009-05-03 Updated Spanish translation M po/es.po commit a6f87ffe8133a4f9205dd1ab1d441fa06c40b497 Author: Ivar Smolin Date: 2009-05-02 Updating Estonian translation M po/et.po commit 86cacc2fd60dbed4397567edd08021513c1a60ae Author: Jorge Gonzalez Date: 2009-05-01 Updated Spanish translation M po/es.po commit bcbbc3f7853ab1a3a0f2b226312a41d5987e1d5a Author: Vladimir Melo Date: 2009-05-01 Updated Brazilian Portuguese translation. M po/pt_BR.po commit d6fa64ab439ac900a92a0467f39cdf72afa5870f Author: Cosimo Cecchi Date: 2009-05-01 Add building tips link Mention http://live.gnome.org/Nemo/Development/Nemo in the README file. M README commit 1a8adc87b49603cf14ce139e66bde0fe7bddec8e Author: Cosimo Cecchi Date: 2009-05-01 Remove a reference to SVN Also, update the GIT info page link. M HACKING commit 7e17224a1e68bb755bd281d46e0533b1dcff52d8 Author: Claude Paroz Date: 2009-04-30 Updated French translation M po/fr.po commit c51ac9926e012267d305711b949a937d917f075b Author: Gabor Kelemen Date: 2009-04-30 Mark strings as translatable, fix bug #579769 M src/nemo-file-management-properties.ui commit 23ff2a21d2925945dde6e04a47190ebfa27ae8c7 Author: Gabor Kelemen Date: 2009-04-30 Update POTFILES.*, close bug #580784 M po/POTFILES.in M po/POTFILES.skip commit a1a501224999d7abda06e9a2f7eb6da64c17d089 Author: Shankar Prasad Date: 2009-04-30 Updated Kannada translation M po/kn.po commit 90e5e1720d09188f3eabb67e502272a549c63dec Author: Maxim V. Dziumanenko Date: 2009-04-28 Updated Ukrainian translation M po/uk.po commit 48ed43f32668e5615ac64a3de55ec7ab2f254ef7 Author: Cosimo Cecchi Date: 2009-04-27 Reverse the order for folder icons overrides Use the correct order for folder icons overrides, so that we can keep track of things like "folder-visiting" or "folder-drag-accept". Patch by Krzysztof KosiÅ„ski (#567254). M libnemo-private/nemo-file.c commit 43c9802d618bcb0d035b4fb0dea4807367d893ea Author: Cosimo Cecchi Date: 2009-04-27 Don't display accelerators in Tabs menu Set use_underline == FALSE for items in the "Tabs" menu, so that folders with underscores in their names will be displayed properly in the menu items (#580392). M src/nemo-navigation-window-menus.c commit 9c0dddfbaddfe251814ff473d9f0a734c385d931 Author: Cosimo Cecchi Date: 2009-04-27 Display the application icon in the popup menu If available, display the application icon next to the "Open with" item in the file manager window menus (#546916). M src/file-manager/fm-directory-view.c commit fe4ca76584061215547edb55b8a0bab4cdb8e034 Author: Cosimo Cecchi Date: 2009-04-27 Fix DOAP file Add "mailto:" prefixes to email addresses in the DOAP file. M nemo.doap commit 7f404a39f63ceb8d906809c2092cecca7b785574 Author: Ivar Smolin Date: 2009-04-25 Updating Estonian translation M po/et.po commit cffb9cf70254086a3737b37e8fad786a6e6de414 Author: Cosimo Cecchi Date: 2009-04-23 Don't show autorun hints for Win32 software media Now that shared-mime-info supports "x-content/win32-software" vs "x-content/unix-software", use this distinction to inhibit autorun prompts/hints for media containing Win32 software (#524270). M libnemo-private/nemo-autorun.c M src/nemo-window-manage-views.c commit 7f74d06e270d89b6de1a3f23fe3388830f2c25ab Author: Olav Vitters Date: 2009-04-23 doap: Add desktop category M nemo.doap commit 9f1c7d03c45298701320f5503e8ba1afec9fb523 Author: Cosimo Cecchi Date: 2009-04-23 Add shave to the autotools setup Use shave to have some more meaningful build messages. It can be turned off by using 'make V=1'. M Makefile.am M configure.in A m4/Makefile.am A m4/shave-libtool.in A m4/shave.in A m4/shave.m4 commit 06dda37076c6e5b222f868a46fe84c070a04d680 Author: Cosimo Cecchi Date: 2009-04-23 Move desktop files into data/ Move desktop files into data/ subdirectory, so that they not clutter the top source dir. M Makefile.am M configure.in M data/Makefile.am R100 nemo-autorun-software.desktop.in.in data/nemo-autorun-software.desktop.in.in R100 nemo-browser.desktop.in.in data/nemo-browser.desktop.in.in R100 nemo-computer.desktop.in.in data/nemo-computer.desktop.in.in R100 nemo-file-management-properties.desktop.in.in data/nemo-file-management-properties.desktop.in.in R100 nemo-folder-handler.desktop.in.in data/nemo-folder-handler.desktop.in.in R100 nemo-home.desktop.in.in data/nemo-home.desktop.in.in R100 nemo.desktop.in.in data/nemo.desktop.in.in commit dd10aa3618b195a127014ba033eb522f907077a1 Author: Cosimo Cecchi Date: 2009-04-23 Fix typo in ChangeLog generation script Set the right name for the start tag in the ChangeLog generation script. M Makefile.am commit c0b27cce8d33ea8220434cf59b1e504fc9d2bcea Author: Matej Urban Date: 2009-04-22 Updated Slovenian translation M po/sl.po commit 9826f177cb72fc9f595356b773f51059bef6cd1e Author: Andrew Walton Date: 2009-04-22 Let forward/back mouse buttons work Install a handler to link forward/back mouse buttons to forward/back actions in NemoNavigationWindow, with a preference to set the right X button number in GConf. Signed-off-by: Cosimo Cecchi M libnemo-private/apps_nemo_preferences.schemas.in M libnemo-private/nemo-global-preferences.c M libnemo-private/nemo-global-preferences.h M src/nemo-navigation-window.c commit b02ef0a7ec2d0de3064d322f5da103a8dfd492d3 Author: Cosimo Cecchi Date: 2009-04-22 Remove useless function Remove nemo_has_valid_failed_thumbnail(), as that's not used anymore after the last commit. M libnemo-private/nemo-thumbnails.c M libnemo-private/nemo-thumbnails.h commit 20f4389f7cd22bd001ebf17c0c3c459cca5483ad Author: Matthias Clasen Date: 2009-04-22 Avoid duplicate function call Don't call nemo_has_valid_failed_thumbnail, as nemo_can_thumbnail will eventually call the same gnome_desktop function (#574205). Signed-off-by: Cosimo Cecchi M libnemo-private/nemo-file.c commit 3ffebcdbf5b5ba7e6b018f542fdc39522a42d1b2 Author: Cosimo Cecchi Date: 2009-04-22 Remove some more GTK+ deprecated macros Remove some other bits (hopefully the last) of deprecated GTK+ macros. M src/nemo-history-sidebar.c commit c308f7f3e96094c4d5077655960a0910dbaa605c Author: Cosimo Cecchi Date: 2009-04-22 Remove other deprecated GTK+ symbols There were still some references to deprecated GTK+ symbols in some files, or in some comments. Let's drop them all. M eel/eel-editable-label.c M eel/eel-gdk-pixbuf-extensions.c M libnemo-private/nemo-cell-renderer-text-ellipsized.h M libnemo-private/nemo-directory.h M libnemo-private/nemo-file.h M libnemo-private/nemo-saved-search-file.h M libnemo-private/nemo-undo-signal-handlers.c M src/file-manager/fm-empty-view.c M src/file-manager/fm-empty-view.h M test/test-eel-background.c commit 4485d32d41f1519313ad49d43914bbd0b78d104b Author: Jorge Gonzalez Date: 2009-04-21 Updated Spanish translation M po/es.po commit 7da1601ba6288e48dc6ed3023de03fff04d20b2d Author: Cosimo Cecchi Date: 2009-04-21 Check for NULL when sorting columns Check for a NULL value of the order array when sorting the columns. This might help when dealing with strange GConf setup issues (#524341). M libnemo-private/nemo-column-utilities.c commit 3b5af96a5f41640d447f7215a758d4de4c0220fb Author: Cosimo Cecchi Date: 2009-04-21 Update EggSMClient from libegg Re-apply the reverted string freeze break commit now that we branched. Don't check if the desktop file exists ourselves, as the Egg code will take care of that itself. Thanks to Christian Persch (#576619). M cut-n-paste-code/libegg/eggsmclient.c M src/nemo-main.c commit 60e58366e06f42b03072e06a19f8adeece0ded6a Author: Nelson Benitez Date: 2009-04-21 Use g_timeout_add_seconds where appropriate Use g_timeout_add_seconds instead of g_timeout_add where appropriate. Fix bug #574033. Signed-off-by: Cosimo Cecchi M libnemo-private/nemo-icon-container.c M libnemo-private/nemo-thumbnails.c M libnemo-private/nemo-tree-view-drag-dest.c M libnemo-private/nemo-users-groups-cache.c M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-icon-view.c M src/file-manager/fm-list-view.c M src/nemo-notes-viewer.c M src/nemo-spatial-window.c commit 99e66a93605e056c80cebb4c3ac9b6b58167ad1c Author: Matthias Clasen Date: 2009-04-21 Avoid delays in background switching Don't delay background switching, so that users will immediately see it changing when browsing the background list (#330168). Signed-off-by: Cosimo Cecchi M libnemo-private/nemo-directory-background.c commit 979d877c1803034be8a3ff69437974a1cfdbff30 Author: Cosimo Cecchi Date: 2009-04-21 Enforce {GDK,GTK}_DISABLE_DEPRECATED cflags Now that we build cleanly without deprecated symbols, widen the deprecated check policy to GDK/GTK+. M configure.in commit b695c970182bbf19f2c38bf7405db506e7c23bb0 Author: Cosimo Cecchi Date: 2009-04-21 Remove deprecated GDK/GTK+ symbols Remove all uses of deprecated GDK and GTK+ symbols, replacing them with the currently supported equivalents. Based on a patch from Tal Benavidor (#565038). M eel/eel-background-box.h M eel/eel-background.c M eel/eel-background.h M eel/eel-canvas-rect-ellipse.h M eel/eel-canvas.c M eel/eel-canvas.h M eel/eel-debug-drawing.c M eel/eel-editable-label.c M eel/eel-editable-label.h M eel/eel-gtk-extensions.c M eel/eel-gtk-extensions.h M eel/eel-gtk-macros.h M eel/eel-image-table.c M eel/eel-image-table.h M eel/eel-labeled-image.h M eel/eel-stock-dialogs.c M eel/eel-types.c M eel/eel-wrap-table.c M eel/eel-wrap-table.h M libnemo-private/nemo-autorun.c M libnemo-private/nemo-bookmark.h M libnemo-private/nemo-cell-renderer-pixbuf-emblem.h M libnemo-private/nemo-clipboard-monitor.h M libnemo-private/nemo-column-chooser.h M libnemo-private/nemo-desktop-directory-file.h M libnemo-private/nemo-desktop-directory.h M libnemo-private/nemo-desktop-icon-file.h M libnemo-private/nemo-desktop-link-monitor.h M libnemo-private/nemo-desktop-link.h M libnemo-private/nemo-directory.h M libnemo-private/nemo-dnd.c M libnemo-private/nemo-entry.h M libnemo-private/nemo-file.h M libnemo-private/nemo-horizontal-splitter.h M libnemo-private/nemo-icon-canvas-item.h M libnemo-private/nemo-icon-container.h M libnemo-private/nemo-keep-last-vertical-box.h M libnemo-private/nemo-merged-directory.h M libnemo-private/nemo-metafile.h M libnemo-private/nemo-open-with-dialog.c M libnemo-private/nemo-progress-info.c M libnemo-private/nemo-search-directory-file.h M libnemo-private/nemo-search-directory.h M libnemo-private/nemo-trash-monitor.h M libnemo-private/nemo-undo-manager.h M libnemo-private/nemo-undo-transaction.h M libnemo-private/nemo-vfs-directory.h M libnemo-private/nemo-vfs-file.h M src/file-manager/fm-desktop-icon-view.c M src/file-manager/fm-desktop-icon-view.h M src/file-manager/fm-directory-view.c M src/file-manager/fm-directory-view.h M src/file-manager/fm-icon-container.h M src/file-manager/fm-icon-view.c M src/file-manager/fm-icon-view.h M src/file-manager/fm-list-model.h M src/file-manager/fm-list-view.c M src/file-manager/fm-list-view.h M src/file-manager/fm-properties-window.c M src/file-manager/fm-properties-window.h M src/file-manager/fm-tree-model.h M src/file-manager/fm-tree-view.c M src/file-manager/fm-tree-view.h M src/nemo-application.h M src/nemo-bookmark-list.h M src/nemo-desktop-window.h M src/nemo-emblem-sidebar.c M src/nemo-emblem-sidebar.h M src/nemo-history-sidebar.c M src/nemo-history-sidebar.h M src/nemo-image-properties-page.h M src/nemo-information-panel.c M src/nemo-information-panel.h M src/nemo-location-bar.h M src/nemo-location-entry.h M src/nemo-navigation-bar.h M src/nemo-navigation-window.h M src/nemo-notes-viewer.c M src/nemo-notes-viewer.h M src/nemo-places-sidebar.c M src/nemo-places-sidebar.h M src/nemo-property-browser.h M src/nemo-query-editor.h M src/nemo-search-bar.c M src/nemo-search-bar.h M src/nemo-side-pane.h M src/nemo-sidebar-title.h M src/nemo-spatial-window.c M src/nemo-spatial-window.h M src/nemo-throbber.h M src/nemo-window-menus.c M src/nemo-window.h M src/nemo-zoom-control.h M test/test-nemo-directory-async.c M test/test.c commit e2f711533e1008b62c9db70fb3bcf877191866d4 Author: Alexander Larsson Date: 2009-04-20 Fix broken pofile Lots of duplicated strings that makes msgfmt -c check fail. M po/ha.po commit 42bea16f00e93441a601f3279702d1bd60f07592 Author: Alexander Larsson Date: 2009-04-20 Comment out invalid pofile strings msgfmt -c bs.po said: bs.po:3783: number of format specifications in 'msgid' and 'msgstr[0]' does not match msgfmt: found 1 fatal error which meant branching was impossible M po/bs.po commit f9585e4f4825ab1114cd4185ec8cdca9360da3c9 Author: Jonathon Jongsma Date: 2009-04-20 Allow shift+return during typeahead find Allow shift+rename to close parent + open when typeahead find window is active. (#579551) M libnemo-private/nemo-icon-container.c commit 1f9ed9598a3324278eaef2153b95f22962dd2558 Author: Khaled Hosny Date: 2009-04-17 Updated Arabic translation M po/ar.po commit 9c4c0254d4788ac1d7e10df30fc74cc2d64c5d09 Author: Alexander Larsson Date: 2009-04-17 Preload /desktop/gnome/background from gconf We'll be reading a lot of background settings, so we want to preload (and thus also add_dir) the gconf directory. (Fixes #578993) M libnemo-private/nemo-global-preferences.c commit e61a17f3445be7c77f092b717f1e64a1231e01c0 Author: Cosimo Cecchi Date: 2009-04-17 Fix a copy/paste typo. M README.commits commit bad7749c6cc88009ba5e0f9f96f9ab418a1f7193 Author: Alexander Larsson Date: 2009-04-17 Add .gitignore files A .gitignore A data/.gitignore A docs/reference/.gitignore A docs/reference/libnemo-extension/.gitignore A docs/reference/libnemo-extension/libnemo-extension-overrides.txt A docs/reference/libnemo-extension/libnemo-extension-sections.txt A eel/.gitignore A libnemo-private/.gitignore A po/.gitignore A src/.gitignore commit 8acf8338c97387af3b93793760a3b1d64e752a2c Author: Alexander Larsson Date: 2009-04-17 Add makefile rules to generate ChangeLog M Makefile.am commit 3f4a5c97a23acbca33836d14edb2b5c8798a6dc5 Author: Alexander Larsson Date: 2009-04-17 Add doap file with name, description and developer info A nemo.doap commit a867c35e835128647396ad5b2df498c189944ca4 Author: Alexander Larsson Date: 2009-04-17 Add README.commits, update HACKING for git M HACKING M Makefile.am A README.commits commit 4a78eabc71df08bdf3d71877c3b3cb62d1b80bff Author: Alexander Larsson Date: 2009-04-17 Move ChangeLog to ChangeLog-20090417 With the switch to git we're moving to an autogenerated ChangeLog. R099 ChangeLog ChangeLog-20090417 M Makefile.am commit 6a8673c7806ad7a014feb9bc780e0dfcadb5d71c Author: Alexander Larsson Date: 2009-04-16 Reversed check in last commit, fixed. 2009-04-16 Alexander Larsson * configure.in: Reversed check in last commit, fixed. svn path=/trunk/; revision=15188 M ChangeLog M configure.in commit ab550c223368c4d0bb9b7133e477430a38fe96d6 Author: Alexander Larsson Date: 2009-04-16 Bug 578983 – set_more_warnings check of WARNING_CFLAGS doesn't work 2009-04-16 Alexander Larsson Bug 578983 – set_more_warnings check of WARNING_CFLAGS doesn't work * configure.in: Actually check the options. svn path=/trunk/; revision=15187 M ChangeLog M configure.in commit 9870d42d6709fea0fd3c50d00f5a491902be27e5 Author: Alexander Larsson Date: 2009-04-16 Set typeahead column to the name column. 2009-04-16 Alexander Larsson * src/nemo-places-sidebar.c (nemo_places_sidebar_init): Set typeahead column to the name column. svn path=/trunk/; revision=15186 M ChangeLog M src/nemo-places-sidebar.c commit 3125825a1cb10f38779b926050d4030f45a6003a Author: Alexander Larsson Date: 2009-04-16 Bug 578468 – Change of font DPI setting does not effect desktop icons 2009-04-16 Alexander Larsson Bug 578468 – Change of font DPI setting does not effect desktop icons * libnemo-private/nemo-icon-canvas-item.c: (nemo_icon_canvas_item_invalidate_label_size): Invalidate pango layouts since the context could have changed For instance the font DPI. svn path=/trunk/; revision=15185 M ChangeLog M libnemo-private/nemo-icon-canvas-item.c commit 4323f9b47229312a60093587724e1aa102a8c926 Author: Alexander Larsson Date: 2009-04-16 Bug 579086 – Excessive white-space on right-hand side in icon view 2009-04-16 Alexander Larsson Bug 579086 – Excessive white-space on right-hand side in icon view * libnemo-private/nemo-icon-container.c: (nemo_icon_container_update_scroll_region): When using at allocation->width, take zoom into account svn path=/trunk/; revision=15184 M ChangeLog M libnemo-private/nemo-icon-container.c commit 649c39c7d8f6b3162e6f9142f3201eb254f26c8f Author: Alexander Larsson Date: 2009-04-13 Post release version bump 2009-04-13 Alexander Larsson * configure.in: Post release version bump === nemo 2.26.2 === svn path=/trunk/; revision=15183 M ChangeLog M configure.in M eel/ChangeLog M po/ChangeLog nemo-4.4.2/INSTALL000066400000000000000000000366101357442400300135200ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command `./configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. nemo-4.4.2/NEWS000066400000000000000000000011151357442400300131560ustar00rootroot00000000000000Development: 1/22/2013: - Breadcrumbs: Stylable by themes, see src/nemo-styles-fallback.css for default style information. Border radius, color, background color, and text color can be customized through that. - Sidebar Disk Indicators: Stylable by themes, again, see src/nemo-styles-fallback.css for default style information - you can customize the two colors (fore- and background), the thickness of the bar, the corner radius, the maximum length of the bar, and an amount of extra padding from the bottom of the cell.nemo-4.4.2/README.md000066400000000000000000000001451357442400300137400ustar00rootroot00000000000000Nemo ==== File Manager for Cinnamon Nemo is the file manager for the Cinnamon desktop environment. nemo-4.4.2/THANKS000066400000000000000000000001371357442400300133750ustar00rootroot00000000000000Nemo started as a fork of Nautilus 3.4: https://gitlab.gnome.org/GNOME/nautilus/tree/gnome-3-4 nemo-4.4.2/config.h.meson.in000066400000000000000000000033401357442400300156240ustar00rootroot00000000000000#pragma once // config.h.in. Generated from configure.ac by autoheader. // Define to the version of this package. #mesondefine VERSION // Enable debug code #mesondefine ENABLE_DEBUG // ***** Enable features // define to enable the empty view that is used for performance measurement #mesondefine ENABLE_EMPTY_VIEW // Define to enable xmp support #mesondefine HAVE_EXEMPI // Define to enable EXIF support #mesondefine HAVE_EXIF // Define if libselinux is available #mesondefine HAVE_SELINUX // Define to enable pango-1.44 fixes #mesondefine HAVE_PANGO_144 // ***** Localisation // always defined to indicate that i18n is enabled #mesondefine ENABLE_NLS #mesondefine HAVE_GETTEXT // the gettext translation domain #mesondefine GETTEXT_PACKAGE // Define to 1 if you have the header file. #mesondefine HAVE_LOCALE_H // path for translations #mesondefine LOCALEDIR #mesondefine LOCALE_DIR // Define to 1 if you have the header file. #mesondefine HAVE_MALLOC_H // Define to 1 if you have the `mallopt' function. #mesondefine HAVE_MALLOPT // Define to 1 if you have the header file. #mesondefine HAVE_SYS_MOUNT_H // Define to 1 if you have the header file. #mesondefine HAVE_SYS_PARAM_H // Define to 1 if you have the header file. #mesondefine HAVE_SYS_VFS_H // Define to 1 if you have the header file. #mesondefine HAVE_X11_XF86KEYSYM_H // Define to 1 if statx is supported by the kernel (defined in // /usr/include/stat.h). Lack of support by the build machine // does not preclude support at runtime (under a valid kernel,) // we just construct the definitons ourselves instead. Runtime // support is still checked at runtime (safely.) #mesondefine NATIVE_STATX nemo-4.4.2/cut-n-paste-code/000077500000000000000000000000001357442400300155315ustar00rootroot00000000000000nemo-4.4.2/cut-n-paste-code/README000066400000000000000000000011711357442400300164110ustar00rootroot00000000000000README for nemo/cut-n-paste-code The code in this directory hierarchy was cut-n-pasted from somewhere else. In the soon to come, Star Trek future, this code will be available as part of standard libraries. For example, the code in libegg will be one day available as part of Gtk+. Until that happens, DON'T HACK the code, unless you are updating from the original cut-n-paste source. Instead of hacking the code in cut-n-paste-code, create subclasses and put them in libnemo-extensions. If you have any specific questions, comments or complaints about this setup, send mail to the nemo mailing list at: nemo-list@gnome.org nemo-4.4.2/cut-n-paste-code/libegg/000077500000000000000000000000001357442400300167625ustar00rootroot00000000000000nemo-4.4.2/cut-n-paste-code/libegg/eggtreemultidnd.c000066400000000000000000000266261357442400300223250ustar00rootroot00000000000000/* eggtreemultidnd.c * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "eggtreemultidnd.h" #define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString" typedef struct { guint pressed_button; gint x; gint y; guint motion_notify_handler; guint button_release_handler; guint drag_data_get_handler; GSList *event_list; } EggTreeMultiDndData; /* CUT-N-PASTE from gtktreeview.c */ typedef struct _TreeViewDragInfo TreeViewDragInfo; struct _TreeViewDragInfo { GdkModifierType start_button_mask; GtkTargetList *source_target_list; GdkDragAction source_actions; GtkTargetList *dest_target_list; guint source_set : 1; guint dest_set : 1; }; GType egg_tree_multi_drag_source_get_type (void) { static GType our_type = 0; if (!our_type) { const GTypeInfo our_info = { sizeof (EggTreeMultiDragSourceIface), /* class_size */ NULL, /* base_init */ NULL, /* base_finalize */ NULL, NULL, /* class_finalize */ NULL, /* class_data */ 0, 0, /* n_preallocs */ NULL }; our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0); } return our_type; } /** * egg_tree_multi_drag_source_row_draggable: * @drag_source: a #EggTreeMultiDragSource * @path: row on which user is initiating a drag * * Asks the #EggTreeMultiDragSource whether a particular row can be used as * the source of a DND operation. If the source doesn't implement * this interface, the row is assumed draggable. * * Return value: %TRUE if the row can be dragged **/ gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list) { EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); g_return_val_if_fail (iface->row_draggable != NULL, FALSE); g_return_val_if_fail (path_list != NULL, FALSE); if (iface->row_draggable) return (* iface->row_draggable) (drag_source, path_list); else return TRUE; } /** * egg_tree_multi_drag_source_drag_data_delete: * @drag_source: a #EggTreeMultiDragSource * @path: row that was being dragged * * Asks the #EggTreeMultiDragSource to delete the row at @path, because * it was moved somewhere else via drag-and-drop. Returns %FALSE * if the deletion fails because @path no longer exists, or for * some model-specific reason. Should robustly handle a @path no * longer found in the model! * * Return value: %TRUE if the row was successfully deleted **/ gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, GList *path_list) { EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE); g_return_val_if_fail (path_list != NULL, FALSE); return (* iface->drag_data_delete) (drag_source, path_list); } /** * egg_tree_multi_drag_source_drag_data_get: * @drag_source: a #EggTreeMultiDragSource * @path: row that was dragged * @selection_data: a #EggSelectionData to fill with data from the dragged row * * Asks the #EggTreeMultiDragSource to fill in @selection_data with a * representation of the row at @path. @selection_data->target gives * the required type of the data. Should robustly handle a @path no * longer found in the model! * * Return value: %TRUE if data of the required type was provided **/ gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, GList *path_list, GtkSelectionData *selection_data) { EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); g_return_val_if_fail (iface->drag_data_get != NULL, FALSE); g_return_val_if_fail (path_list != NULL, FALSE); g_return_val_if_fail (selection_data != NULL, FALSE); return (* iface->drag_data_get) (drag_source, path_list, selection_data); } static void stop_drag_check (GtkWidget *widget) { EggTreeMultiDndData *priv_data; GSList *l; priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); for (l = priv_data->event_list; l != NULL; l = l->next) gdk_event_free (l->data); g_slist_free (priv_data->event_list); priv_data->event_list = NULL; g_signal_handler_disconnect (widget, priv_data->motion_notify_handler); g_signal_handler_disconnect (widget, priv_data->button_release_handler); } static gboolean egg_tree_multi_drag_button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data) { EggTreeMultiDndData *priv_data; GSList *l; priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); for (l = priv_data->event_list; l != NULL; l = l->next) gtk_propagate_event (widget, l->data); stop_drag_check (widget); return FALSE; } static void selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **list_ptr; list_ptr = (GList **) data; *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path)); } static void path_list_free (GList *path_list) { g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL); g_list_free (path_list); } static void set_context_data (GdkDragContext *context, GList *path_list) { g_object_set_data_full (G_OBJECT (context), "egg-tree-view-multi-source-row", path_list, (GDestroyNotify) path_list_free); } static GList * get_context_data (GdkDragContext *context) { return g_object_get_data (G_OBJECT (context), "egg-tree-view-multi-source-row"); } /* CUT-N-PASTE from gtktreeview.c */ static TreeViewDragInfo* get_info (GtkTreeView *tree_view) { return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info"); } static void egg_tree_multi_drag_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time) { GtkTreeView *tree_view; GtkTreeModel *model; TreeViewDragInfo *di; GList *path_list; tree_view = GTK_TREE_VIEW (widget); model = gtk_tree_view_get_model (tree_view); if (model == NULL) return; di = get_info (GTK_TREE_VIEW (widget)); if (di == NULL) return; path_list = get_context_data (context); if (path_list == NULL) return; /* We can implement the GTK_TREE_MODEL_ROW target generically for * any model; for DragSource models there are some other targets * we also support. */ if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) { egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list, selection_data); } } static gboolean egg_tree_multi_drag_motion_event (GtkWidget *widget, GdkEventMotion *event, gpointer data) { EggTreeMultiDndData *priv_data; priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); if (gtk_drag_check_threshold (widget, priv_data->x, priv_data->y, event->x, event->y)) { GList *path_list = NULL; GtkTreeSelection *selection; GtkTreeModel *model; GdkDragContext *context; TreeViewDragInfo *di; di = get_info (GTK_TREE_VIEW (widget)); if (di == NULL) return FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); stop_drag_check (widget); gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list); path_list = g_list_reverse (path_list); model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list)) { context = gtk_drag_begin (widget, gtk_drag_source_get_target_list (widget), di->source_actions, priv_data->pressed_button, (GdkEvent*)event); set_context_data (context, path_list); gtk_drag_set_icon_default (context); } else { path_list_free (path_list); } } return TRUE; } static gboolean egg_tree_multi_drag_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data) { GtkTreeView *tree_view; GtkTreePath *path = NULL; GtkTreeViewColumn *column = NULL; gint cell_x, cell_y; GtkTreeSelection *selection; EggTreeMultiDndData *priv_data; tree_view = GTK_TREE_VIEW (widget); priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING); if (priv_data == NULL) { priv_data = g_new0 (EggTreeMultiDndData, 1); g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data); } if (g_slist_find (priv_data->event_list, event)) return FALSE; if (priv_data->event_list) { /* save the event to be propagated in order */ priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); return TRUE; } if (event->type == GDK_2BUTTON_PRESS) return FALSE; gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, &column, &cell_x, &cell_y); selection = gtk_tree_view_get_selection (tree_view); if (path && gtk_tree_selection_path_is_selected (selection, path)) { priv_data->pressed_button = event->button; priv_data->x = event->x; priv_data->y = event->y; priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); priv_data->motion_notify_handler = g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL); priv_data->button_release_handler = g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL); if (priv_data->drag_data_get_handler == 0) { priv_data->drag_data_get_handler = g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL); } gtk_tree_path_free (path); return TRUE; } if (path) { gtk_tree_path_free (path); } return FALSE; } void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view) { g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL); } nemo-4.4.2/cut-n-paste-code/libegg/eggtreemultidnd.h000066400000000000000000000061451357442400300223240ustar00rootroot00000000000000/* eggtreednd.h * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __EGG_TREE_MULTI_DND_H__ #define __EGG_TREE_MULTI_DND_H__ #include G_BEGIN_DECLS #define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ()) #define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource)) #define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE)) #define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface)) typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */ typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface; struct _EggTreeMultiDragSourceIface { GTypeInterface g_iface; /* VTable - not signals */ gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source, GList *path_list); gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source, GList *path_list, GtkSelectionData *selection_data); gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source, GList *path_list); }; GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST; /* Returns whether the given row can be dragged */ gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list); /* Deletes the given row, or returns FALSE if it can't */ gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, GList *path_list); /* Fills in selection_data with type selection_data->target based on the row * denoted by path, returns TRUE if it does anything */ gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, GList *path_list, GtkSelectionData *selection_data); void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view); G_END_DECLS #endif /* __EGG_TREE_MULTI_DND_H__ */ nemo-4.4.2/cut-n-paste-code/libegg/meson.build000066400000000000000000000003601357442400300211230ustar00rootroot00000000000000 egg_lib = static_library('egg', 'eggtreemultidnd.c', dependencies: [ gtk, ], install: false ) egg = declare_dependency( include_directories: include_directories('..'), link_with: egg_lib, dependencies: [ gtk, ], ) nemo-4.4.2/cut-n-paste-code/libegg/update-from-egg.sh000077500000000000000000000006261357442400300223100ustar00rootroot00000000000000#!/bin/sh function die() { echo $* exit 1 } if test -z "$EGGDIR"; then echo "Must set EGGDIR" exit 1 fi if test -z "$EGGFILES"; then echo "Must set EGGFILES" exit 1 fi for FILE in $EGGFILES; do if cmp -s $EGGDIR/$FILE $FILE; then echo "File $FILE is unchanged" else cp $EGGDIR/$FILE $FILE || die "Could not move $EGGDIR/$FILE to $FILE" echo "Updated $FILE" fi done nemo-4.4.2/data/000077500000000000000000000000001357442400300133725ustar00rootroot00000000000000nemo-4.4.2/data/dbus-interfaces.xml000066400000000000000000000033631357442400300171770ustar00rootroot00000000000000 " nemo-4.4.2/data/freedesktop-dbus-interfaces.xml000066400000000000000000000027631357442400300215130ustar00rootroot00000000000000 nemo-4.4.2/data/icons/000077500000000000000000000000001357442400300145055ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/000077500000000000000000000000001357442400300161445ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/actions/000077500000000000000000000000001357442400300176045ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/actions/16x16/000077500000000000000000000000001357442400300203715ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/actions/16x16/menu-bullet.png000066400000000000000000000002771357442400300233360ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDùC» pHYs  šœtIMEá  òq¬LIDAT8Ëc`4l ­  ¸…•Zþ£áfR xŒÅ€‡Ø2á0à?‘b8 XD¤NÀ õóC(n$5G ׳ x3IEND®B`‚nemo-4.4.2/data/icons/hicolor/actions/16x16/menu-none.png000066400000000000000000000003541357442400300230020ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEá & $O‘yIDAT8Ëí‘1Ä ×R^Aewü‡òZÓPð‰M‰‹.„;)m¦Ã«YYxyŒœ$ÿ“ä£mç ÷Ž”ZkS1„€œó}3I¸;Ìì’™j­ë-IŽUsU…»|ÉwÉ/YîJ ”AŒñr¼eÁìGfòËÁ ½Orilº®Cq*„€ápŸ!ÃÒ !Nu]ÇÑf³”r+j·Ûp8{,—Ë7ÚÍfƒ£^¯‡³³³g8??Ç!4›MëøÜëõ`ë÷ûRÞ[³ý;opßï÷¡œœ ›Ízìvûà€>|ãjµ ¦Óé)›ÏçRþŽD"œˆ®˜hKÓ4oŠÅâC£Ñxub·Û…ßïï¸\®©RêÛ7®LÓ¼iµZwù|þu‡¬žêõ:Öëu'c‚ˆ¾ÑW"’DÔ%¢âb±ø^.— …”Rÿ–i^¯Ñh†a@×uÀËË Æã11™LÞèÿi|€Ú•IEND®B`‚nemo-4.4.2/data/icons/hicolor/actions/32x32/000077500000000000000000000000001357442400300203655ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/actions/32x32/nemo-eject.png000066400000000000000000000025041357442400300231220ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs|4k¡tIMEÞ ÐrÑIDATXÃÕWÍKcWÿ½$潘—LÃÄ4[$~Æ7¥ EÝ¥õpçн»še]2¸‘~í„ÆUA Sü(I hÍ HM1cyIš1‰ïÞw»è}iŒ/NªSJx<î½çw~çœ{Îþcþáú&" €…+®%eê«iÐ6555´»»ûE:>Èd2Éç\2™L2Nìíí}9555 ïîjÜ  urròA2™|šË娢(ìüüÜPEa¹\Ž&“ɧ“““´ò3n;€¶ÕÕÕ‡††2ÆdÆXc” A(D"‘ÏÆÇÇ—¤¼0Zk®sƽ‰‰‰·×ÖÖ¾ ©ª*jšÆXCªi4M³vtt¼7==ý~*•Ú?>>Îóüx)voœœ|k³Ù:õú&6ŠÅbª³³óÉZ&L1oÛØØx$Šb!”Òkªi  Âçó€á:J)!E±cccãONk=€û333#@`BUպƋÅ"|>ŠÅ"Àçó¡T*AÓ4Ã=ªª"LÌÌÌŒ¸_Í|ulß477ûëQJ)EWWDQD¹|5¤±X f³¹n8...ø@±–×òòò´$IþztêÆm6Û5ãÐÕÕ…r¹\w¯$Iþåååi®Ú4½^ï°QÜyVW<ש7’¾¾¾Ê£|ðz½Ãdn³@ôxÇãæWz€466ÖÉ“jQ3ÆÐÛÛ (•J/-;þþ~0Æ`pž466ÖÉûI€Åív·Å- Þúƒ†¹àv»[õF¦w3‹(Š.½¾u!„ܹ“]^^Âb±\ù'Š¢«R©T–Rz­äî*”RÂÕ 7•JeõïJ?ÇãéZA@$¹3ˆÚsãñxšÏˆF£§Š¢œN§lÄBSSÓ+ñ>ŸÏ¢Ñèi-€!¤‹ÅŽßÕ«ªŠÑÑÑ;y¿¹¹y|,;"„øôT©‚2€l8ŽB®ÔÿMWk#RÕžAA8ŽÈê­Y („B¡'Ñhô¨¶l»Ý»Ýn]£ÑèQ(z  Ïך‘ßï™››ûÔårÙë•¢×ÚYA„Ê?>ÁdúËGEQ^ÌÎÎ~’H$~¨nFÕüR¦l6K-‹ÔßßÿŽ~ÈmU©ª*VVVB;;;ßø•‡Àp$»`:<<Ìôôô ´´´¼®r[%„`ÿ`qqñ1ŸˆÎ¸³†¨žÛÛÛ1‡Ãáòz½oZ­VÓmŒçóy²¾¾þýÂÂÂcÆX À3=ûoJU—Œ±ÒÞÞÞωD"ÓÞÞîw8ŽFÙ „ Ÿ---}¾¶¶ö57þ€?ŠË.\že¶¶¶~’eùž,Ën“Éd­Ž¯®”R”J%œŸŸvvvÂóóó §§§?rÚŸoäifå3\ €6³ÙüÆððð`wwwÐét:eY– P(òù|þøøø0ïSJŸñ·Às¿óܺõÛPà½ÛÅ'™×øèÞÌK¼¤.øÈåu®ðx³ÿýãô_•?þ‡Ãpûû7IEND®B`‚nemo-4.4.2/data/icons/hicolor/actions/scalable/000077500000000000000000000000001357442400300213525ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/actions/scalable/location-symbolic.svg000066400000000000000000000013651357442400300255270ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/actions/scalable/mount-archive-symbolic.svg000066400000000000000000000041711357442400300264760ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-auto-arrange-symbolic.svg000066400000000000000000000041371357442400300272400ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-desktop-scale-symbolic.svg000066400000000000000000000043351357442400300274110ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-horizontal-layout-symbolic.svg000066400000000000000000000045141357442400300303560ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-horizontal-layout-wide-symbolic.svg000066400000000000000000000052361357442400300313060ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-vertical-layout-symbolic.svg000066400000000000000000000045401357442400300277750ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/hicolor/actions/scalable/nemo-vertical-layout-wide-symbolic.svg000066400000000000000000000050141357442400300307200ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/actions/scalable/sidebar-hide-symbolic.svg000066400000000000000000000006611357442400300262350ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/actions/scalable/sidebar-places-symbolic.svg000066400000000000000000000006651357442400300265770ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/actions/scalable/sidebar-show-symbolic.svg000066400000000000000000000006621357442400300263050ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/actions/scalable/sidebar-tree-symbolic.svg000066400000000000000000000013021357442400300262540ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/actions/scalable/view-compact-symbolic.svg000066400000000000000000000004161357442400300263110ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/apps/000077500000000000000000000000001357442400300171075ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/16x16/000077500000000000000000000000001357442400300176745ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/16x16/nemo.png000066400000000000000000000010021357442400300213310ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÜ 6R?ÀH‚IDAT8Ë¥“¿nA‡¿Éº„„„ÄCðÔ)Ü厖àxJ*Dá?²ÒYT¼F¤ÔD‰ÅÄæì»ÛŠ8Ÿ}‰"±ÕîÎü¾™™…ÿ\0™LNÝý-à-£È¼ßï¿y0N…Þçy~$IË85I’«]‘»ŸçyþND\†Ãaèõzi–e{ôõzªîÝÏf³< šdYÆço¨êòIï6ÓÔÜŠO_Ž.Ó&ZU0è}ì.ÒÝNZ–ÃÇ__§Û>ªÊïùI@šƒ»a®àFQÞÞWÌ"1Öû)oDfŠc¸+æJQüñtKOÔHˆ0ÌnÔ· mîÍ”åz+µHˆ«òuÅ,b®D èF„;HkTîËbΪ\0_žß\q÷Î:t®¬ª%ËÅhwAvàĨëD:‚µÕ‚îé¶KÔH*ÙÍ´QŠ4ó ੈ\ŽF£ÉÁá³ãŸßåÉßÐÝAÎî/Wí'=º"p\ÿ2wãÑ4óÀ³IEND®B`‚nemo-4.4.2/data/icons/hicolor/apps/16x16/nemo.svg000066400000000000000000000053551357442400300213630ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/apps/22x22/000077500000000000000000000000001357442400300176665ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/22x22/nemo.png000066400000000000000000000014501357442400300213320ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÜ  ((»¨IDAT8ËÕ•½n$E…¿[ÓH°?é+"b§#˳ÍIÈyRÃðH<‡‘ ìБÚ€W ˜õzlOOwÝ?‚ê­Ñ+oDI­–®ª¾>uî©.ø¿ ÈL9==}wNY–RžÌçóÛ×wGGG²¿¿ÿøàà`礳³³·Tõ}àõÁ'''?¹ûG"bîÞíšTJ)îþëñññ¿±*ðñáááϪ~8ŸÏ)¥tî¾sÅÞÞÞÛÿ¥ðüü¼_­VO€vwqw2“¯¾ùs}h¿>¾ÿüë§ µÙ¹;p„óÉÓϘ• "™dF›“AFàéíA„³–,nž³¸¾ä·Ë?ßí"3£”2%`Æ//.(¥c6Õ2ÇÝ07< wÅÌp7ª¨ŽT¨:r×/¥sw"š€"B)…n6kÊKÁÝH 3"sC½ÔFFQêÀݰÌÎÌÄÝÛÖH&[p2ŒC­¢6Nê*ê“Â:Pmd¬kªŽ uͪ_JlÀ‰…2èšÒ|!³ùi6R­¢6 :2N0«¨UÌu%£%kÛ<áný’õxÇÍj$IBž­AñŠÏæÚ¼žêA†“’HÒ¶ WËßY·ÜöW)ˆx%±mâ½gS G²ý(¶VÐìE½RuD¤Em"o£áȧt4õæ61„L²33Ì ¡P0WÆ:PD@dÓÏ{ªwÁ7#3°ÎÝ·`ÓJÕA¶µl+Úáø|Ó{à"ÚEÄ6n"u¥ÖaR+÷lUgüóÁÎ$sRÜzÇubVžIEND®B`‚nemo-4.4.2/data/icons/hicolor/apps/22x22/nemo.svg000066400000000000000000000073531357442400300213550ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/apps/24x24/000077500000000000000000000000001357442400300176725ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/24x24/nemo.png000066400000000000000000000015321357442400300213370ustar00rootroot00000000000000‰PNG  IHDRàw=øsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÜ  \ +ßÚIDATHÇÕ•Ïj$UƧ»& Ä'Üù­àVðܺÌÆ½àd#Ì2†$.BnWJÆÅš˜ÉdÒªîý¾ã¢ª«;š ÎÌÆÛ4·«¾¯¾ß¹ç4üßWdfœžžžKzüÐÓéôéööö‡¯å²¿¿?=::ʇ–¤<>>.¯£Ý?“ôx2™TIÍ}7e&™‡‡‡ùo‚ÓéôÙîîî#¢ƒƒƒÜÙÙykÌONN8;;›îíí ‘„$¾üæloæò>úüëhË캱$2>ýø3bq‘³âÒ8=`3ÎÄÍlyÍÍü‚ëÙ%ç¿üúÞ†† ¿]?eADÐûšt"‹L!gŸÜi,¡–)n)µ¥ªc±œE# ÛØ‚&@B1™™Èƒ ‰3IáÕ…ª‚T(ꨵPÕQU˜/nÈÆ3Òã¢?=kT»•ªµX­kƒR;ª:æí-M­u0Idã08±{þ²Ê(,—ñmK-­Ðôû’hË2Ƕ©îÝ—Ý-ýÇ UäB©-²(*¨äÞÜZ]5€š¡SC®Ì7´Ý-¯æ/0†ì‹¯tb¼¾Ú}j_ {^ýžI9Yׯ.Xt3fËë;½c7{H´6Ùׯž-2r]äZ 1™ŒE ‚U+ôuΡî1ÉDZ'‹„ÆvJж[ðhº5-V³6W)r5“Ö˜F³‚×G^ª£bÙÎyÔlQj7$øçÀcÕ&›fk<½„FD˲ i¶èjK­Ý=u)‡QáLè' @ml§mº²¤iJm)¥ãN„\‘º‹éï5¹óB$”1Álñ._>§¬Ä*÷ƒ ƒøC«GËFR½ººšþüüGŠgüþâ|m0ÆÈÿ<±UE—MÛ¶_}ÿÓ/~úóÛ-€‹Ë?Þæþw›¤ßÞ¶ÞP´fÀà/Þý÷M àIEND®B`‚nemo-4.4.2/data/icons/hicolor/apps/32x32/000077500000000000000000000000001357442400300176705ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/32x32/nemo.png000066400000000000000000000020601357442400300213320ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÜ "Qþ%t°IDATXÃíWËnd5=åÛâØ $Ä:½JYBšàKXð³âWØe•]Ä6!!„4“Nw__WÕaa_Ûô00 ‰qdÙ¾}»ëÔ9ÇexÝ^·ÿ{“~qqqñµ»¯DòcÁóæËåò«³³³Oÿ.€E¿p÷Õùùù ¿DWWWŸ¼ ]ö߇€å iÁ0 vyyÉCìü{!†.NNN>Ú@ò½ÓÓSüSÈW«Õâe2&)×××>`@Dpssóï˜ðóÇžøàUü ÓAwÌóÒìæŽ òÓ—_\¾»:Þôñg8Z¼ „aÀ  aÀúÃFƒ»ÂÜ`žÚh ÉÔ&¨%$`1iDÒµˆ¤e"¾ûæÇwª œà<þåÙB " ³z%+ÂÝàn°:jMaœšÂ]¡®°y®ùó¤É55“¹!Bˆ DD2un‚ðÜiðÒ ó\s÷ÖÍó3£B5A5M0§7©iÉVJu’2#DPõ# ôˆT df>3P‚ù¡ž0i„yÜu xTS NÈz»„ Á™×…ëúLs¥{leÝuõSER…ªŽ€Óã”F„e6” ‘½:Mô&´ˆÂÌjPóµ.°ÍžHy^Ø‚ 1 ¦»qÚâ( H>åÀ"p¶_þsÏ»g]i0ëw…–ÝPt·fPÒ@zNÅÙVæi;Æ ÂòÉÆê‚<°îop–Á«ž5{oÌäÏ­.»ÇYæùûl:ÝíâË7)EHZ’IÁìæ@6$»õÌŒƒ¶wÛûwæg``jw›ñGQu›_A ÊP¹`ˤ¯vî]ÀbÖÜðú®”» àéö·§ÏÖ¿âè-©ˆ”m¸ïÄ Œlc©¹@y—ù=Þu#_WâXOi„§æÀRÍØeôšî×ù™>`£˜˜£ÝÆ4×l…È|®Ë¡µžÙðÃ@HB/Ò:Aãm; ([ÑSŠ!ïÑFÿ=ª 3 ³'rf­`±—¤<››9V¨¾ÛŤã¸;"YXÏ ÜS Àè˜)ï˜è”¬ûfÉÚ"#Ç”ÔbŒ]öò°Ÿ}•„Ý®àÁÀsÓä®ÎVŠÍ0McÄnŒÈÞ{D@»µq’ù´|p Û_§dpEÀO6e³þyúËw¼—ºB|´oï§·ð6€á¾€5ýOügô;å5²üà_ÁªIEND®B`‚nemo-4.4.2/data/icons/hicolor/apps/32x32/nemo.svg000066400000000000000000000076261357442400300213620ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/apps/scalable/000077500000000000000000000000001357442400300206555ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/apps/scalable/nemo.svg000066400000000000000000000074751357442400300223510ustar00rootroot00000000000000 nemo-4.4.2/data/icons/hicolor/categories/000077500000000000000000000000001357442400300202715ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/categories/scalable/000077500000000000000000000000001357442400300220375ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/categories/scalable/nemo-prefs-behavior-symbolic.svg000066400000000000000000000046411357442400300302540ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/categories/scalable/nemo-prefs-display-symbolic.svg000066400000000000000000000051261357442400300301210ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/categories/scalable/nemo-prefs-plugins-symbolic.svg000066400000000000000000000045001357442400300301300ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/categories/scalable/nemo-prefs-preview-symbolic.svg000066400000000000000000000036421357442400300301360ustar00rootroot00000000000000 image/svg+xml nemo-4.4.2/data/icons/hicolor/categories/scalable/nemo-prefs-toolbar-symbolic.svg000066400000000000000000000023031357442400300301100ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/hicolor/devices/000077500000000000000000000000001357442400300175665ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/devices/scalable/000077500000000000000000000000001357442400300213345ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/devices/scalable/drive-removable-media-usb-symbolic.svg000066400000000000000000000071331357442400300306270ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/hicolor/emblems/000077500000000000000000000000001357442400300175705ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/emblems/16x16/000077500000000000000000000000001357442400300203555ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/emblems/16x16/emblem-note.png000066400000000000000000000010261357442400300232660ustar00rootroot00000000000000‰PNG  IHDR‘h6 pHYs  ÒÝ~ütIMEÓ : èDÇ>tEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3ïXkIDATxÚ’=K\A…Ïsæ‚ZDBüÀ"M°J)’@¶6B¥U¾ ó4VVY„6©£AÙM ›]A‹ F×p×\‹{ïîu‹€žbfžóžÃ0Ò5…¤æñîÿ¡ÛÃâŸS­½;ƒ³[Qzô£úlçkÁÖøäëöÑt¼Ó÷¬Ôä,(§mÛºBÿšŠwúŸo4߬ïu !)j›(£ÿ~tþyàéÆïµ÷_¶7$EÅ„t*O.Ÿí?<« /¾=,•+õêR«Õ.V :Ø’TûöøÅ‡z©\i|}€®$é{Ës3#÷Ÿ¬HÊiR23Ø&‰°H*:ªW—èHÈîzT;xÙÙ£¼R„! Àù¦¨ÞJ€ò{ P§]ÃÐÝùí 7ñ1ú%¥™Ÿf†åÕ§ùéÿ0’,ÔyÖ±Ñ[y°°³XV$ NÎu]ÜtEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3ïXÔIDATxÚÝ–ÉkQ‡¿ª×Ét›™ Îh4<˜‹"‚ ®AÁ«… 'EðˆâöOhDTTTT$.7/^¼¸ƒA0*¸o‰Cœ%3Óýƒ@ðëRdT±˜ªEQYƒˆeþ²ƒä­ w/A×å¯ôôõsêÈfRÉDuyÀS>9ä§ð’oxõ|{¯ÐÓ×Ïé£[˜•M2·%#J@ßÔo²*Dépµ ÎX°¼›Mëg³°ó §n!›i¢­µ×k/§jž3­b-åŠÀÕ›Cœ8ÔICƒ!›™A[kšl¦‰JL9·^À€úÑêÄl0Vò¹~aÃÃ9Œ1¤ÓsZRd3Mx®C¾Pžž€Z‰‹ j5$Ùl’™Í.©”G²ÉÅu°Â¥2‡–ö­ø•"JP {R¹4LcÊ'‘|ž›¦±ÑÁÄíCOs¿¸uó0Ÿ¿ S™hº{#(ЍDÕ/µ}ùg­³]i®‚G^uŽFÇØ*(#X+|-þ³ÎbÀ›*˜ù?ÅêZš"†Æ©ªû7GU³ý?þ$~R²ûšÕ®´IEND®B`‚nemo-4.4.2/data/icons/hicolor/emblems/48x48/000077500000000000000000000000001357442400300203675ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/emblems/48x48/emblem-note.png000066400000000000000000000046261357442400300233110ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÓ "4Ü9rl #IDATxÚí™kpTåÇï{ÎÞ“ÍîæNHDn^Zp¬ZLm?رíX­½M§_ìtúE?ØŽµýÐŽÓN;~pÔ2Õ©(TTŠJ½´U!Ü $å’Ëæ¶ÙÍž=÷~ÈY\"ÐDÀú!ÏÌ;;³gÏÙÿÿyþÏó¼Ï{`Æ>73.˜‰À ‰ûBIiFN3v9¤$®>Ïgî•` ¯øj`Kiiéfà>@ñþGù"'Ÿð@Þ¹lqÅÖÍoýáã÷ßyþÀœÚØZ`=ð „Ä• ÷äkâRÈ P_Qyàå~óÕë—ÄÃföRÂHJK>¹z×é ›õ÷%3ÿþX€í=Ë-x¦{¹Ü< øµÀi 8\ðpp-píïÿéüÆ[/šÁÈEJR"…@HB°yÛ±¡¦æÓgþüìî­ÀÀNŒã­i“¹ßn\ûă˖ß=¸Gnû®Ã>r<(„°›÷R±"¥¢,|&Qlžüå¯Y<§&2 ×$7Ú‚”!& E")¤1qýõ·ÚFš÷w·¯yµcp,mn‘—ŸÜ3Ô×â ád‡Ô4n«ñœ©{ùrN$.F â­`6ð\8äó=ùûÄ]÷ÜWéóÕtr¹T'RD T~Ф˜D2/%¤À±,“¸¶N´²±Oø[UéÍÛß2@® z ^„€åÝ ½ÀgUß™ˆ.8¹Nµt‡Ùõ÷-[N.}‚ôàv\$¸àâ×u&J¾®tÀ•\\Wx&®»¸ŒgÆI ¦(*.Fo º§ª KËcŒx0'ËèbP¼›ƒÀæHØ9´óçq)(×4“\NÇ4,LÃfÎ’Ÿ • (Cë#ÓÿÁ9R‘rb×"'I)ŸK½Cè¹q• ÈjE£eÑј1r€PÉ,¢ 9ÜåU©1À(”ÑÅ"àxQxéáŸÝtæ±_?z‡ëEÏ!ààªw¢Úì\ƒ®[(Š`ÞÒû)©ûVö$ùÒêNö¼ã‚$û†Ðr9\gŒPÉ ]ÏºÅ¡áØØ‰MÄæÞƒ5Þ‘ßîø'uð)I(oá#]Ci!Cc¾È5Q| { ÜH¡¢( ë.ª¢`š]íÏáÚ6u·RTRK´öG8f?ƒ'Þ%•Ê d2YM#° |%7ë•"4ÙžwHÌ¿‡Ì©MW.üŸŒ˜Âþæ6à©îÖ_,¡kDªuW-ÂNû-½mx ®ëb&–ecY6¶m“ÓM\ÇÁ0lLË&5–#PÂE PUˆüñF#¤˜„}ý~;¹•ؼï2žl¥ìª[hß³¡å+?ܾçåá¨'!g*ÊÛÀÕ| ×uèùhs žEI¢œc„«~,]3©Ê¡wAeIlKð ,ÛF“.AGð…&d„ƒë8„ƒ jì6C±²„Ô~¿1°…ØÜ»I쥼n%-M¯µ¯¼·y!ð´—¼öùšÙT|° ­ð¨™w;Rqé9Þ„èõ—U^…¨5Mw•ögÃæÈ{èz?Š¢àXŸ –e´–=Q‰ÅEWÓ{,”Ý~3ÕMbÞ]Œö6S5çFö6½ÒñµU-1àoÀ[€VИjÊK(ìî?þ׆DÕ-èÚ™ÑãD¢µøü~’§w“ËTÌ^†?'=ÈJÒ>'½Å§gŽbY6Ží`B¸¸Žƒæûf:*;‹ÍÌ)0Ç(©YAz …ª«oeߎW;n»¿%¼éíú€¤W>Õ”) <XvôhWOEèHEyõ¢P¼b)¶m“r˜“­Dc _(Qdd…e) Z$\äÖ TEà•£ûÓ1ÙVlŽŸ!ôŽÏGi§¬n%ûw½–ÿ<ð¾|ØkbºþSµ~*ƒÊ‡Gº’‘7´gŽùë'¢E%sÔDõõX†ÁH+ÑÒÊf]K.}œdOª°e¢´Ô¯FиnL„—Ú†ÊÆÔΨ>Ü/XL(:] ^µŒ¶=ó²ù'ðAø±Ir§C Ä  ­µ½Ç]ýâ^; ùbþãxY½¯ºS×M¶‰-"QÙ€®õÒwºS ¼ª&.®õùµæ`ºk=Áø‚‘ã#G)­^Æþ]ov4®j)¶¼¦5¤ À;çÛ*Óœ\àc ùÃ]æê5»#ÂS¾xù5VÑ€ešŒ&Û)Š×“¨¬ÇµRôÜG(’`üðã„*—(ªE$Q½”–ov4Nx~°î<àÍɺŸn ;³í=к€mÛw}d¬~aglvyV™ _)‰êå˜Fš±áN"ñzUK#gÅ%›I-›Ë¾¦7:Wµæe³aºà§CÀ- `y /±Ž[ß~¯ƒ5¯ì.-‹å¬º²áˆôW¨¼SÏK#Õù9Ó¤¤²a2øMŸüt#ÀEHÀá¬f¼÷öÚä ëw–—Ç ­®|´H TQ\þeTÕŵ(J,doÓë«Zã— þ³œ·‹‚OÅ[~¯W„" ê­ÊJ‹o|cí#‰úWEKI·=Ä¡FüóÀ®K9N‡ït"ä >•ÀÕÞL}3p7°~ÑÂÙ=ÍÏ oéK­ÞéÆÓÀíÀrï÷ ïêt*. NÞÔ D¤ø>°xH{5~äR=/.cD& ‰xV¼üÉz *ã7.Tç?ïwNâ<òò{dòC‰í%~îBcâá¥Ùd"jÁá®[PÉìK?c36c3öÿ·ÿÿ1õü‰-9IEND®B`‚nemo-4.4.2/data/icons/hicolor/status/000077500000000000000000000000001357442400300174675ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/status/48x48/000077500000000000000000000000001357442400300202665ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/status/48x48/progress-0.png000066400000000000000000000032131357442400300227740ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß4§Ì˜ÛIDAThÞí™ÏoiÆ?ó¾3ã{Ë™Úi`·qâJ”V ›¶„î ¶«î¥¤Jˆ½,¨°´h9TB”h…@@½ò€àÐ B⌊lô†ZQ)-Í&®œÄ?âñ̼ïËÁöÔi›ÓBAÈôjdëÕèy¾¿ßw`ŠÿXSL1ÅÓÊ2Å/)î-~@~¸÷YK —œp‰çÍ7ëyöÿþ¿»jÛâg¶´K<ý c ZŒÑÄq‚Öjð[k´yüÔZc´AÆýøû_÷?ÌR€¸qãFýÄ©ãÖkŸò+•Š#¥ÄƒeYcä5Zkúý>qcŒÁC.—#Žc”R(¥è÷ûXÿp}h<3‰ÄÇzà·¤³åÙo/-—Íf“;wîP*•2«§iš-¥aòðáC666h44›MÚí6õz}O™³­­-šÍ&§NžÒ–—‡9idüIˆwÞ~gqf¦tÜu]Õj•v»½‡ôHȨòT*fgg)—ËYµ'=î!½^/óØ+Ÿ|eæâÅ‹_:ˆ×Ä—Þ_ùÜŠlµZÄqL†Ø¶Í¨‰ yRÔ(„FkÜúZk …J)êõ:B:çÎ³çææ®À+Ïu•Vê«KKuÖÖÖPJaŒÁ¶m’$¡P(à8išÒï÷³F5²ô8YÇqð}Ïó°,‹N§ƒ1×u‘RÇ1õz^¯÷Æ™3gÂÕÕÕõI’xßD¹|ùò[¯«RJ¶¶¶²†eYJ)¢(BA¡P \×ÅqœŒÐHH’$ôû}¢(bww—F£R Çq2oJ)BËå8{ö¬ ‚àýÕÕÕë“Ø·ù¾÷£“Ÿ>)nÞ¼‰ëºÔj5šÍ&¶mgd¢(H)3b¶m¤”xžÇ‘#GPJe]|´üž”Ò7ÆX·þxkÏè°Æw|öyÖ`÷ì"[Íš¿üwœÈ^æ€ à½ÈùuB˜a“ÚÖ»/* ø€;<€óŒDô€`?qsð2nḛ̈°¤Ãõ‚W(÷½¬«Fó„7¦÷¡SL1ýF1Åÿì© ö‡35Áÿü ðuZÃàVIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-10.png000066400000000000000000000035621357442400300230640ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEßìÈLœÿIDAThÞí˜_h\YÇ?÷œ{ïÌ?’I&ͶÛL:…­-«›¶ÆîŠ¨Û¥ ±baÙ}Y¥Z[©¬±>)˪((EôI|QÔÒ}Ђ îƒTE7öaYiÙbRÓ)3ÉüÉܹ÷žs|ÈÌí¤mì$éÖ­æ?†¹s¸óýþþŸlÉÿŽX÷z8}zÚ#À œG‚ÑôéiÆ*u¸Áoñ¿á'v9À}1,a¨ahbX¤Á;ü‰Ÿr(lÔ+â¡0Q@„@´Eš<‡ø?b–7øŸ†û½IÀÜ¡:&c‘e/'9ÏÛ¼Î3<$ß[L‡ÄZÚ–Œòa~Åï§OO·€ì†+Ç¿›Íæ—ô8_>ÿCö°gØG‰ $òžç_›æâ.ZÃc;/ò ^çmê\ÇtµSrqæ£|ŸßñÂG |¯x¼ÀÞõŽz×™¯’ꜽ—ŠŽÊ>Uôù¿{×ù‹¿ýõ)Ûß¶¥±Äݯ0Æ µÁM„h­V¾k6·?µÖmÐFGA;øÊg^þìw×›°ë% Î;WÚ³o÷›¥âÞÈȈ#¥ÄƒeY=à5ZkÚí6A`ŒÁC"‘ ”R(¥h·Ûܺu ˲ԕwþ¾¼T©äÌ™3—×CÂ^'Y™Í}n$?j g~~ž¡¡!„¸ÝN,ËBk ‚ÏóPJqóæMÂ0D)EEA@EH)¥—H‰%Q;|©Óæú"!Ö^ ÏM~zçÎbªR©000°ò!B µÆ÷}Z­ËËË(¥RÒh4¨Õjh­WÍf³d2¶nK¥^>räHr=‘!V•µûœ}õÕ¯},‘L dÒ¤”±¥ƒ  ÙlÒl6iµZø¾€Öš0 WbÝÜmP¥…B­5™L/“O>õä'{ŠÁº„÷ñ€Ο˜üÀdÒ÷}”R„aÈââ"õz˲°mÇqp'mYÖ]à»9áû~7xêý“é¤ë|q=#Žè7|><ày©ç …mV­Vcqq‘f³‰çy¸®'f7L<Ïcpp|>O>Ÿ'›ÍÆà{èÙlÆ$‹ãEÇ=pìØ±b¿$ì"zÍS'I==ú¡¦¦¦lc ø¾ÏØØQÅì†ÍÜÜccccbRApõêU&&&btÉX–E½^' Cž}ö9ùÏëóŸÎö3‰>ŸçÆ,,,P.—©T*ÔëuJ¥Òª2ÛfÕj•J¥Â¾½û„´åñNNZ÷3~?ÄKÏ¿410Ûíº.år™B¡@½^_ºK¤[yFFFbpp0®6½ {= „ ÕjÅÛ±}ÇÀÑ£G?~?\}˜Ø5þÊÔ§d­V#òù<¶mÓmb½Dî$Õ ¡nÅêµ¾Öšt:RŠR©„‚F£Á¡C‡ìÑÑѳ÷ÁôæÀt•VêÅ]»JÌÎ΢”ƒmÛ„aH:Æq¢(¢ÝnǪké^°ŽãàyÉd˲h4cp])%AP*•hµZO8p ?333ßO¯™(ÇîñÅŒ”’jµ7,˲PJáû>BÒé4™L×uq'Ô%†!ívß÷Y^^¦\.£”ÂqœØ›RJ„$ <(3™Ì+333gû!°fò¼ä×÷¾o¯¸pá®ëR,©T*ضƒð}¿; ¥ŒÙ¶½jV’R’L&F)wñ®^¿~k×®155Åß._>Õ©F'°´´4îû-Ù¿?ù|>®ÝB,ËZ¥ÝXïMTƒs{ÐëZ<Ãx2”‚Ngî–Ôz­–ë·¬IÀ÷Û©?þù­–ÏÏñ3&''ùækßÂqr¹¹étŠd2I"‘@vÀ9®K6“!‘Lâº.ÉäJÜ·Ûmjµ:7Ëefçfi6—;#¶YùìT¦L&Cñ±mªßN¼&!„•òÒ±0†={öP(RcnoKºÍ,Š""µrˆ"E¤"ÂÎ3¥u'däªÑ¢·K§S)R©”Õ¯Ö”(Š–µÖîøÎqÆÇ-&Š»8yê$H$4 ªÕ*Ú¬TšH©(r îÖ{ËB cÛd3iF #Da„Ö+‹¢;ç½ê­›rÓÊåò÷þú—7¿,¥ôŒ1Ö¥?\Z5:¬¹ êIÜÞÙç^ƒÝ½‹|`UþUùñƒ¸‘=Œv¶ËÉÍÜ_×± €E`¸ºYYÀël‘寢ë%`z¶¨K›%`ß±9x7Á÷’Еp´ùÊís|ïd`6²V|X ·dK¶d+'ÿÅÞ2ÁÚâl™`Kþ òoø)Ôñ­æIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-100.png000066400000000000000000000060121357442400300231350ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß9' ò —IDAThÞíš{Œ\Õ}Ç?÷9ïïÎîxe;ëµÇ 6±›µ!æa(†6V¡8¡È£iÌ£ &‚ѨŠòp "%MJ“*‰PZ *¡& ªjµŠ?0ØC·^¼~íîØ3ã¹wvfî½çžþ1wÆóX£µ³i‚Ô#ýtgîœ{Ï÷{Îïu~gàÿÛï¶)³ø.0уïzð›¸ÁÕ Äý} ` Á“l`˜M$X„ÉLDp)á`áÇb”}<Ç'ÙX@) ôÚ ÍÙÌaöǦˆ¤€ä ’<’’Óä‚{g‚>E$yl³‡³Hïü­7èæQnaŒƒØøœ @ž:O9²ñã r ÐÝ v³®Ba®d€ñ}æqo§EÃç{ø÷°›·òLÕf8D‚ϲŽoóSæp1e gIࢤ[ù0‚רËäLlC™Áï]ü€p !ˆ"ÎÑS 8ÌQ0Æ1N“£Hž";x‹Kèæ}t1È|®d,B;Çäi€ÆÏóŸæY м søwò§‚Ž?M‹m¼Ê.ö’àŸèãmRTx`ÚAu ‡ù\ÃýÜέ\Oœx[/áñ,Ÿå^žò¢™Qà&Nbs ÉÑ9‚ÇìäOy„¿¦ã‚ÀÆâüëó·m‰š¡ }ƒWÔv3’Râû)}ÇÅ÷Eõ»ïã˳Wß÷‘¾Ä—¾çTœG>yÿŸoäIþ“Xƒ]¸@šaæj¾ÉOâ»± ôq€#ÁÅMfèâñ·<ó¹÷îÑ–¯ß9п4ÒÓÓchš†”EQÀûø¾O¥RÁq¤”H) …B8Žƒ!•J…S§N¡(Š8txdêLÖºê¡=õ²…0&W,ÞbŒÁYw¢¶ˆó7ÓÉ ^àŸkò ^ÁäK+{—ßÙ“š«§Óic||œR©„ã8T**• ®ëâºnÓ=MÓP…ÉÉI2™ ™L¦þÙu]„Z$UQåf~‹ü;_mÛ:ä1n†f¯¥¶¹ÍUÜÁ ~ÀÓòX¼Ä <ÎxÄ ¢¯¯?šÍféè¨:UUQUß÷)—Ë”J%¦¦¦B i¶mS(ðý³~XQ‰ñxOïÜÞ˜âã6l³…¿ÁÆnÂ0…Â*îæœ‹€Ì¡›¥MúÀ/ØCˆïå+_¼6ŽvÄcq4MÃ÷}„8ŽC±X¤X,R*•(—«Y€ïû¸®[ÕuÙ„¤Ói|ß'O‰ÇÔKW^z §°ù÷¶áèfi@À˜Ž@„-¬G'Ùæ}‡ÙÏw)¦ºS›‡V …Ëå2B\×%ŸÏcYŠ¢ ë:†a`F´¢(màk6Q.—k6ÀÊ Ŧñ ò<‹h¢“d 냾@‚e܈ג§Œð6qžºþúë;"‘èét¯R(Èçó‹E"‘¦iÖ ³¦&‘H„ÎÎNR©©TŠD"QߨFÅb±N²a?†a®Ú´iS?Ç)s„6añ€eÜ$Z ¨@“Þ&ãÀ;üšï\ñÁ5· ëRJ&&&°,‹P(„çyuBày£££ 2™ 'Oždrr’Ó§O322R_™šÔˆX–…ëº\wÝh]]]w ¯ò|“Þ 2«­Ì6õ‘@S<‹×ÕÙuÿâEiÙl–C‡‘L&ë³ÞJ"•JqâÄ &&&Èd2d³Y,Ëb`` ÉÍ6ªY.—#›Í²ì’eª¦kŸ s° N2ˆÊjc «ˆÒÑ–‚å˜øè]ÔÑ‘¼È4M2™ ét˲êî±1hšFOOOlMµA7®€ªª”J%¤”!X0AÇÆ׿ð«v¶á‰ÒÑH yB$Ú–LrzÑâ…9|ù°V(p‡T*…®ëÔ‚X« Õ>7ÚÅtD|ß'‹!„```UU±m›µk×êsçÎý+ÞÀiÃ"1Ý (€6m®!â qûâÅŒ!„@J‰®ë¸®K,Ã0 <Ï«²ÐVu0 ƒH$B8FQlÛFJ‰išhš†ã8 P*•®X±zE÷ÿ@ë¾£¶kP T÷E,’„û/Ó— ½oA\Ó4r¹\=`)Š‚‚r¹ŒªªÄb1âñ8¦ibFPˆëºT*Êå2SSSd2„†Q_MMÓPU•P(ÄêÕ«µP"ô`V]7ø€C<t7ö¿ljhÝ%_¢nݺÓ4éïï'›Í¢ëz,@¹\Æó¼:0]×›r%MÓ‡Ãtww#„¨Gñš;vŒÑÑQ†‡‡ÙÿúO·Ù@|°ÕôÛ Øä[prN¢\.ÑÙÙÉe—]F*•ªûnUUëF\“š®7ªD‚<›èÕfÜqÝzfê Ad®¹T»`%ÚØïFàǹˆÕýÝ’§ïÞ»‹R©Ì3ÿò4CCC|ý«ßÀ0 ’É$É$±X”p8L(B À¦I"'cš&ápUï+• …‚Åd&ÃØÑ1ŠÅ© Å–Õkà™âñ8 çÍ•ˆ–ŒùÇ ¨ ¦ØÁ®V¿«¨ŠÄ‚´’ÁÁAÒé4ª¦)Ï>RË<ÏÃÕ}€ç <áá÷„ï*£5¥Q:‰EÔ¶8°ƒ]ÀTë Xlc÷“%IWífE©àû> û²p¡Â¢þÅÜsï= ! aÛ6¹\_V='D T­ Яù{EASU ]'Ñ“îÁs=|¿štµæ{ÙÓÍõˆ3dÙÆ¾ $Ù¶#+9ñC\S»ùú’×á—`ú¦D®»êùn­ÑpsŸé»éšƒ£¼¹àMš\û!ÞrÖ6.gÛYÁÕ5?;68ÆØü18Âÿð8_` 1ËUí6îÜÍ,çV’{/$ÛØ”XÜsí‰ólgÙÏ CA讆ù\„Êr¶ðÃß*Í ±‘›™B þ›ýlgGk¨µ:æ 㔸ŽPPQë4UV±†%üœÿà``H³+ÓÍ]l§ˆ‰l[ÀÇã1¾É8/™ÆJÖ¶|à2ŽÃ K™G=ÑP :Ëù—ó"?ãH¡ÏŽü󸉗ɯW[çWØÁ?ó$ðNk½tºú¤(¼Ä8ë&Ö°õ0sWñÏ12+åݧYÃ^á±&x8É>Ï×py+¨“Ψ:]ÆÅáWœ`Ä$ÜDÏFg ·s+þ}¾Ì?âFÛ[,ò|‘/3É^à8´§›Ú9kÍP"G‘ 6—s ZS9ü ]¬£ùcŽó!~=c"OånîâýìDáZŽ£´me]¾Ë·ØÏ¶@uÊV†%\ÉŸðÜG¼¹¤ÑpØI| ý¬b-ÊùeÍ |y¼Ê^¾Í÷(±?(!Z³{FóE,e-ãÃ,å³Ô$#¼Î?òFØ Œ;£3²ó\ì" ô³†«YÏ5,a) :ÏëM91Âñs^bG`¨“¾ÏøøðBgÏ:Þàht—³ŒaVÓË\âĉÓA$(@•°°)`c3Îûx…—9œNãA’vÞ§÷³wR_%” ªÇ‘@Âõ¸R5á`gÀ¿ñIý{þ¿ïùö¿æ_^îú2ì¨IEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-20.png000066400000000000000000000040351357442400300230610ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß;a)"̪IDAThÞí™ml[gÇÏ}óÛMLêÄiÖ®IêJ ­F›¦„nëÔ¡P D¥iãÃ@e¥E&¤Jˆò ´ К /û4ñĵ£i¨Û ýP†ZµZš¦.ŽÛñõ½÷y>Ävì$mÒfŠ:È‘Žl___ýÿÏsÎÿœçÖíÇÄR‡Žià h€ý¡`4t|H3‰fŠ“\eŒ \à÷¼Ìa`3œMÍ4š4%4yŠ\æm~Å }§»b¬  „@ø@$H±/ñKFù?âó@;`ÝôWu2‚vp”aÞã °ˆÞ]t•ÄͼÌbÐÉ'y•7ù&ŸZîX9|¯W›±hŒáìðÏèc°“ ½˜˜KþÀLf9à žä ·Z ¤Y@›xŒïs†÷(0Ž^äWÑü‡€_pøÈÝ*R6í|†Ÿòï0†nòq4yŠÏñ»¹\Äx”op£è&Có>×ØÍ®Û©bE÷|‡xõޥܨº¹B7àAÞa’+è&CówÞª>q'`Ýö¯³,ãyË´\a,~„Ö¥4Z+|?@)9÷Y)”žUJ¡•FiúÿÛ_=õµ?ó2o’Àmz ƒä'<Áó¼”VCÀ8uêT¦oç¶w3=Ûc¶išh­B4€W(¥¨T*ø¾Ö­5‘Hß÷‘R"¥¤R©pãÆ „òâåÍNç Ÿ:ñö‰<ËëØ MþÉ.†€Ñj¹í: 3Õ™|²#Õi¥ÓiûÚµk”Ëe|ß§R©P©T‚€ 𮙦‰‚ëׯ“ÍfÉf³õ÷A ¥4c‘¸¡ð*oðžkª!ÐF?æ м;Æm€7€H̉~eË–žx.—£µµuî!†a(¥ðŸÇ¶m\×E”² ‹á8B‚  \.“Ïç›È!(•Ju’=Ý=ض3pèСžáááËC/ 5µg_<[™…ŒÆÌ^dG‰ßßù‰G-­5“““xžGWWaÖW°6ccctuu¡µFJ‰R ß÷¹té½½½u¢52B …AðÐC›ÿŸø:pòì‹g[ôA Œ$³à mŽoíÝfær9.^¼H2™¬Ëa†u—R’J¥¸zõ*“““d³Yr¹…BL&Ó$³a655E.—c玆i™‡«q.–ë¤WBÀxü‘Ç{[[“ÛÇ!›Í’N§) M kDjÊÓÑÑÁ† hkk««M#èÆ0 ƒr¹\߱͛6·™L†r¹|ÿÀÀ@jdddb¹þœ[>üð½[z\Ó4™ššª¬šòxž‡a$ \×ÅqlÛ®ª ‚€J¥‚çyÌÎÎ’Íf‘RbÛv}7MÓÄ0 "‘{÷î5]×}zddääJÜTb±è÷v|t‡qúôiÇ¡§§‡\.‡eYu°žç†aH ˜eYM½’išD£QÚÛÛ‘RÖ«xÍÇÇǹrå ƒƒƒüãüùcÀêLOOw{^™¶¶6öìÙC*•ªk·a!š¼뉪Ѡç½ÚŠûAPïLC)¡Z™k’Z˜™I®äˆwKžW‰¿õÎ9Êeßüö×ô÷÷óƒç~ˆmÛ$“IZ“I‰8Ñh”H$‚Yg;-®K$Åq¢Ñ¹¸¯T*Ì̸žÍ2:6J©4[m±õÜkU™\×¥çžr¥S‰›0 CÄc‰j[ hM__étÜ«3ZÏOKjÅ, CB9wCI(C‚ê5©T5d̦֢±J'âqâñ¸XéÜÔÂ0œUJ9Ý[ºéîôölåè±£ !‰P,™ššBé9¥ ¥¬‚ܨjz/¦a`[-n‚Žta¢ÔÜ ha¿7u㺹jÙlö…¿ýõÝo™¦ÓZ‹s9×Ô:ÜtÔ¸½ÏRÝÒ"ï‹ÜµÜKÄù÷^ ³:]ŽVÃîvOr·;ó<0\Z-–jûêTà¬Ý0E^-«>9˜Ÿ:¬Å0RU“áêG(ó÷­øÆÎ@ßÉXq­@®Ûº­ÛzNþšµ¾·úÇfÝÖmíí¿|¢@åt?kIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-30.png000066400000000000000000000041411357442400300230600ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß:€‹áîIDAThÞí™kˆ\gÇç=—9sÛífvgc“6›L 1¡¦›Ä5mQÛ¦4²•Bë‡*1µ• ¢~RšªT¤DA´ ¿(¶¡)Æ P*´$-Z/ñR"]²I7Ùdfw®gÎ9ïûúagNfv6Én"!Õ}àafÏž=üÿç}.ÿçYX²ÿ3æ»8ºT·@ì÷£Ñý£šI4EÊL2ÁÞæm~ÃóìV½€ó~  ™F3ƒ¦„¦Šfš ïò?çQ {­§"n „@ø@$ɰ]ü”q~Ï÷ù$ÐX7'=ÇUDÆ Íãïp˜»Y¸7Ý$q9o5ƒÜ˼ÊWø¾æÊ1ç÷úzó îÆ9”?ôcÖ³‚»ÙHŽÕ˜˜óþ ˜Ô8Ì“ìã p½þ›f`ñóe΢»|ÍE~Â~à–›µHÙôóq~Ä+œ&à ºÃÏ¢9G…'ø¸™ÛEœ=|‰·)3Žîð3hNsž;Ù´˜~a,èžo’hÞ;Ÿ‹¦› tÁîåM&Cwø4æx³ñ×¶ëþ£¿;ò¸e‰g,ÓJ¢ûZk”Òh­ðý¥äìÏJ¡ô¥O¥Zi”V¡ßð¿þùƒ_xçy•$©Ž:H~È#<ÃË@õzˆƒæÖo\ûVnh]|``À6M­5†a´W(¥h4ø¾Ö­5±X ß÷‘R"¥¤Ñhpá çÞ=Y›)”?úäO.çG°Ûš”ù›Æ›]dÑ}ÀÌÌ`ï¾Ì •ÍfíóçÏS¯×ñ}ŸF£A£Ñ ‚ è¸fš&†a055E>Ÿ'ŸÏG߃ @JiÆc Ðò"¯ð[žîè!ÐÇz~À§¡ótÄ"À wÜÏÝ~ûP¢P(ÐÓÓ3û!B ”Âó<êõ:µZ )%¦iR©T(•J(¥.=Ð0H§Ó¤R³x–.Oj)yðÁ]ð,*¨æ»V@ ƒ-|vnYeí*áóÔSߺ7æ&zRɦi¢”BJ‰ïûT«UªÕ*õzÏóPJÁl¬ëî^$¥$›Í¢”"•JO%ÅwÞñ.Pá×<ÞA@ý¬k°ç#\å¬LæÑáMîçyH) ‚€ééiÊå2†a`Y¶mcÛvÚ0Œ.ð­œð<¯•Üù¡á¤ëØO‚ç8L€ìÐO½à> ¾˜2±}ûöžx<±#›]n”J%¦§§©V«Äãqlj³&ñxœ¾¾>2™ ™L†t:o£jµ‘Z5„m;[vïÞ=Ä{xœægB`#;Úu’X‘ÇHÜuÏGöŒŒŒXZk&'')—ËÄb1Â0Œ\JI†ŒQ*•Èçóœ;wŽ©©).^¼ÈÉ“'£“iy‹H¹\&î¿ÿsÙ²e_ þÄá.áç°¼Ù™ÅB ¼@¸¬oÙþ5«×š…BS§NÑÛÛ½õ¹$2™ LNN’Ïç) ”Ëer¹\G™m³b±H¡P`ã†Â´Ì½€Í»ü³K†[Ñ'h®D@<¼ãáÕ==½kÇ!ŸÏ“Íf)—ËQylï¦i200m…V;èöBP¯×ÑZ#¥d劕=;wî¼ïÈ?Ž¼Þ¥Cô´XÈ ˆÕkV}yäÃ#f©TÂ÷}2™ –eÑjbsC¨õ½=/æ#¢”"™L"¥$—Ë!„ R©°mÛ6kppðü¿+„b¤ç;+udKIùК59ÆÇÇ‘R¢µÆ²,‚ ™LbÛ6aF¬tn¸Ø¶M<Çu] àR© µÆqLÓÄ÷}r¹õzý®M[7õŸP'º§»Yýd´¸ìÀ°wïÞn»}(eš&Åb1jX†a ¥Äó<„$“IR©Žã`Ûv¨E$žçQ«ÕÈçóH)±m;:MÓ4B‹Åغu«KǾÚE D¹mH¨Ëjݸûí Ü ^zé%ÇahhˆB¡€eYXÏóÃ0ÒfYV‡V2M×uéïïGJuñ–Ÿ={–±±1FFFøëßNìëzµ%¦›Ó´Z™™™UžW§¯¯Í›7“Éd¢Ú-„ˆ’¸å­XoOT}IèµÞ¸‘2 ¥„fgn•ÔJ©œî"PY$Ïk$Ž¿yŒzÝã—¿úÃÃÃ|÷éïaÛ6½½½ôôö’L&p]—X,†Ùg;éTŠ˜ëâ8®;÷FƒR©ÌT>Ïø™qªÕZSbëÙÏfeJ¥R¬ºuP#çäçïµW# „0ñdSZ³~ýz²Ù,€FëKeº¥Â0$”³s@JB4¯I¥š!cvH‹ö.L$H$¢«¼Æ1 ÖÂ|Õy`×®]Å-[7ßâº.k×ä¨Öj !‹Q©T(‹(=[iB)› @˜³U«Þ7? C‚  Þh!JÍ.Šæê½â…) =Žî9 3ø»€¿%²ËçóÏþño}Í4͸ÖÚ8öú±(!¯¸ jKÜví3Ÿ°›Ï||£p¾ðÜñãÇeTËŽr´ØÜí-x"» ln—ÝfØ-v’[ì̦sÀ¿¯w€O7å«Ól ܺm‹:s½¬hspiëp#–‘ª) Ãë_¡\ºïF€oWúZÖŠ7 ä’-Ù’-åäÿ¡YK¯àJÿ±Y²%»ñöD[‚P —PíIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-40.png000066400000000000000000000044311357442400300230630ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß%° Ll¦IDAThÞí™lœuÇ_Ï÷ùqw½»ÖîÚëd£ívæ&”ŽYDåWÀÌ%–ÀÍd 3¢F¢Æ?4€(ÄIjB$ƈp3N#„ QèdY²ºvtmo»v÷ó¹çy¾ß¯ô¹Û]¯ÛÚáf1û$ŸÜõéÓ§ï÷÷óûóÀyùÿc®‹¶mÐÀ@7Ð Äû}Áhö š 4S˜`ŒQö±ßñ$›å@à¼h¦ÑG“GSB3M‘ƒ¼ÊÏØ¤ÏÔ*âœ0‘@ø€TIœë¹™3Ây„O]€µ8 èYªêd ’¬f+Ïò»¸’‹èâ" C'Ó*PFÐÃU<Ë|…OÉ3γ~¯ßkÄ¢1žÍ>»ƒU,ãJÖa&æœ`&evq/wò4{¯þ›bd·òvñ£[t Í1|~Ä6à‹5IÙtñIãá3ŠnÒÃhŽPä>´-ærã¾È> Œ ›tÍ!ƹŒ…Ô c^÷|ƒ¶ðÞ¹T„jÎS—s5¯1Á0ºIGÑüWÂÂgœ Ø–ûÿÜî»-KIÌ‹ÈVÚ®¸êc· YZk&&&( D"‚ ¨«”’ &ŸÏ“Íf9rä“““;vŒýû÷×-SÓ‘B¡€ïû\{íõæ’%Kî þÊ®–ÆÏaiX™Å| +Vö}iè£Cf>ŸÇóÂÍtË®?Ì7yžŸ‡SÙü,L‡»³ñ°€pV laÜDˆ4Dç;¼Éó¼âa!*aÔ‹†­ÃÙ‘ûèe¿`“xx\3áðSžÅ… çpöÀÿ^Öó*G‰658xƒ?ów^²³3¦5}¨>ë»É§XÏ¥ü‰q"³þó8‡xˆÀX˜>9s¿H½„=Œ"šÀ˜æA¾G™·€É¹° þÇ2ðÈ€æßˆzmUõwóÙŒ†qxFkÄsBbï‡ö6÷;;xœWØ ˜y¥ <2 ù5š¢—/kÔb9äù“ˆñY`Í|ßÐ,FÉ,äÙ™¼a9/'}cs^Î˹—ÿ«¿!ýÛõIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-50.png000066400000000000000000000046621357442400300230720ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIME߯\Ç ?IDAThÞ홌eÇ?óÎÌþ¾;ïön¯Òrwí‘P[¡Ô³@P¦6ÁÐ šJ)¤ØIˆM4€ FIK415Ö„ªB@‹… E)HåÒ¤GïÊõî¶Ý»ÛÙ³3óÎë;»Ý½½öîZ ñIžìîììì÷û>?ßç…ÿËGG´™.®Ý¼Vg@+Ì£µ›×*ÆPL`1ÆÃìg?æ16K€ ôa  ˜D1…"‹"b’y™ß°HªUÄûÂDàP$q’¬á:~Á/ð¾´Æ™I@MS¿JF£‰lâIÞf—p.9³¨€Ä‰´tr)Oð<ßä3@Ó)gŽi߫Ӄh$Ê“é'f9‹¹„•ô²}Æè€NÜÉ-<dNÃ{)ðqs?bocqÕ #(Žáò(›©IʤÏòÏq—aTFq„wðy v&—‹(×s;û±BÕé0ŠCŒr«æS/´9Ýó]bÁ½3©TŸ£ .ârö0Æ ªN‡Qü‹—‚§ ؆ûÿòÌÎÛ C<`èFBPJáû ¥|ÇÅ÷eù³ïã«ã¯¾ï£|…¯|Ï)9ßþÚÖ¯ïâ1ž'N¢î!$Û¸™ø?bëÖ­½ËWž³··çÜhGG‡©ë:J)4M«ïãû>¥R ÇqPJ¡”"ã8RJ¤””J%Ž=ЦiòÀÁÂTƺìΗï\Ä=ìĬ)h`ñ_V± ªÈ¼ë€èÉΖ[:’F*•2GGG)‹8ŽC©T¢T*áº.®ëÖ]ÓuMÓ'N“N§«ï]×EJ©GÃ1Py‚çø+÷ÖÕ he9?åZ¨·Ž˜x„£¡ÈW»ºzb™L†æææòC„@ïûضM±X¤P( ¥D×ur¹Ùlß÷?PÓhjj"‘(ãYÔ¹(®¤¼ùꫯŽp’#‡¬µиˆ›¦§UQ—ÖfqŸ»ïþÁåáH¬9O ë:¾ï#¥Äqòù<ù|žb±ˆmÛø¾ëºe_WµHJI*•Â÷}‰&¢‰¸8ï‚ó¾ÈQr<Ímu| sæLÜY,`$Û“ûVõElÛFJ‰ëºLNNbYš¦a¦ibšf´¦i à+1aÛv%¸àü¾x$dÞ~É\d]ÿdÐÂ=|ˆÎÇ…4@\yå•ÍÑhìšTj‘–Íf™œœ$ŸÏF …BÕÀ¬¸I4¥µµ•d2I2™¤©©© ¾Öòù|•dOw¦ºhýúõ=¼‹Í!~UGÀVrMmŸ$æDd±‹/ýôõýýý†Rб±1,Ë"ãy^U¥”xžÇàà Ùl–t:Í‘#GçØ±c T-SÑ ˲p]—+®¸Jokk»Ðx _ˆEAes% ñ8^[kÛæeKÏÑ3™  ¥¥¥ºêÓI$“IFFF#N“Éd°,‹ÞÞÞº4[ëfd2V®X)tCߘä­†6ܨîâ5›‡“7^sãÒææ–sB¡étšT*…eYÕôX[t]§£££ ¶âZµ k- „ X,¢”BJÉ’ÅKš×­[÷¹ÿÙùbC£¹–À\, –.ëÞÒÿ©~=›Íâ8ÉdÃ0¨±é.Ty_3ñ}Ÿx<Ž”’ÞÞ^„är9Ö¬Yctvv~‡7q\(LÓL8YE6|)oX¶¬—¡¡!¤”(¥0 ×u‰Ç㘦‰çyÕBV:Ý]LÓ$‰DÐ4\.‡RŠP(„®ë8ŽCoo/ÅbñâU«Wµïó÷5îîÊý“VKà„† 6\uvWOB×u&&&ªKÓ4¤”ض‚x|˜ÁÁAúûûyý}·4,m–É`7íωÀÔÔT·mimmå /$™LVs·¢Ä­øzm *¨ã^eÅ×­v¦ž”TæJJÍe­¦¹y°íRì¥=»)mþðÇíôõõqß½÷cš&---4·´LjD"„Ãaôœ Ñ”HŽD…BD"e¿/•Jd³ãé4CÃCäó… ÅVå× 3% ºÏêTÈiñ9»µÄl„Z,Úb@)–/_N*•BèP(uÙNŒ6¾ÄÙþ̳¬fqÀü0dŒ"É") Éç}^å—¬’gêõÂD.à6P,ãV~B?/ñ]> ´úùI@Ž3¯JF!Æ\Ö°™÷ØÊÌ‚çé“8™•"*m\É&^äk\ ÄθrŒû¿<Û<ClNm~Š9Lç æÑÍL4´I E¶òwó>[ çréÀǘÎí|‡­¼GŽCÈ vÉqžapÁùZ¤ Z¸†±ƒƒ8 ë쒣乛ðù,!nã^ö‘£YgH2ÈBLE/”†îùaÿÞÉLõMkÐT–p-»¢YgHþÁ+¾ð)gvÂýÛŸß¶V×Õ'tM*êÄGH)ñ<‰”¶íàybìoÏÓ'>=ÏCzOz®]¶úÒ†/ïäY^$B´î&‚rOð p6Ô 6tÏ™wñÞî®Ù¡ÖÖVCÓ4¤”(ŠRÞÃó<Êå2¶m#¥DJI À¶m„!(—Ë;v EQÄ÷÷GÓ¹«xõvaF )@ŽwY@/Ðï«È”u@´D[üîÖD›žL&ÁÁAJ¥¶mS.—)—Ë8Žƒã8u×4MCQ†‡‡I¥R¤R©êwÇqBh¡@XE•«ÙÄþ£u:áÍÌá{ÜõÞQ§^!3øÅŽŽ®p:¦©©iì!ªŠªªxž‡eY”J%ŠÅ"B4M#ŸÏ“Ífñ<ïÄ…X,F4:†§½­="…¸ë¦›n òO’'çïµQXÂã˪ZWÖN>?ü­kÁpS4EÓ4<ÏCmÛ  …¥R ˲ð<ÇqÆb]NÔ"!ÉdÏóˆFc„¢uþÂùŸáyþÄÚ:ÐÂlŸ€1ç4Ð-‰Õ‹, Z–…ÇqÈd2är9EA×u ÃÀ0Œ*hEQ&€¯ä„eY•`á%‹"AÓ¸Pù)[quý“NœG¸M%„@½á†šB¡ðòd²]Éf³d2 …¡PÓ4«‰Y “P(Dss3‰D‚D"A,«‚¯ £B¡P%ÙÕÙ…a˜KV®\ÙÅa,òó:.0åµ}’Ú‘5„/¿ò²Ûzzzt)%CCCär9®ëVMëºôõõ‘ÍfI¥R=z”ááaŽ?Îþýû«ž©X…H.—Ãq®¿þFmÚ´i÷ ¯³uBãgÒî+³Ú(…çp§5O[7kæÅZ:æÀÄãñê®'‘H$8räCCC¤R)Òé4¹\Žîîîº2[f###¤ÓiæÍ§jº¶ 0xŸw&´ázõ§Rsx8õŽåwÌljŠ_lš&©TŠd2I.—«–ÇZ Ð4ÖÖÖ*ØJhÕ‚®õ€ªª”J%¤”!˜1}FÓŠ+®Ûö¯m/OèCÃ4ÕhÄêÌY_é¹´GËf³Ø¶M"‘@×u*"6>„*ßkób2"žç‰DBÐÝݪªäóy–-[¦·µµ}·±'„P€Ød8•"ëž·ÏšÕM?B¤”躎ã8D" ÃÀuݪU€ŽÃ0…BƒAE!ŸÏ#¥Ä4M4Mömº»»)•J—/Xº åMï͉§»±þI©%pÒêU«n¼¨£+ªi###UÁR!–e¡ª*‘H„h4Šiš†QT!â8år˲(‹¤R)„†Qõ¦¦i¨ªJ `éÒ¥Z ¸,¹šCj•€wÒ^7üöÜOÌU·lÙ‚ištuu‘N§Ñu½ À²,\×­©Óu½®WÒ4`0HKK BˆªŠWìСCôõõÑÓÓÃo½y÷„­Í’ñOÓ^CFGG;-«Dss3‹/&‘HTk·ªªÕ$®X%ÖkU"Ažhô*;n;Nµ3u…_™+%5ŸÍÅ&ÈO‘€e•ïìÞE©dñ»ßodÑ¢E¬ô1 à Ó‰„ ƒ4œašÄ¢QÁ ¦i ŽÅ}¹\&›Í1œJÑ?ÐO¡Pô[l9öéW¦h4Jç…m1.?p¸–€z:ªª*áPÄo‹)™3gÉdUS‰”'Êt¥r]WŒ\Wà Ç¿&<Ï­®µ¨UéH8L(R'èÀNvÅñ8ér]·èyžÙÙÑIg§ÂÌ®Y¬Y»$òù<###xr¬Ò¸Bø @ÕÆz•z¯(hªŠ¡ëÄ¢Z“­¸Ž‹ç ŠÆ÷{éãCõåe”4ϳÈÕN N¹R©Ô“¯íÙû ª©a$ìzyW5!O9 ªIÜÚÞg²Æn²ec+ûf쫔ͱu€·¶×ð‰ì"  h%LŒ"â NrSƒÝÃ|’[‰Ók®?Á7y_û§²Æ<düÙÙ Åê0êƒ#°šE¬àŠ@ &;ßã ^`§‡©(ùY¯ÖL>˜õ ¬ä· ¡ñõv,=\~Á³À! ?U¢fÆÀÿŒV³çœ‚ÿ1,ãUެkp$°—¿ñOv©ñSm`.$ku¢w]¯Ë¼ÄFn>ÍȶqÛÈ¥\Ë»dˆãŽ›`æ ëy 8â—ÏÓN§å©µÛ?µ0Ÿ?²ƒõlllŠ<éÚH˜¬g>» @i\ÍÏ’áQ§È[ÀðdØŽçÞu½rûòíõÔ“@”2ÜKšç¸£>>O |Ÿã"ž&O€áI¤ÔÅæ<ÎN6ÿžl÷&л®Wn¿|{†è$“bÃ'Ç#ËoH³‹·)3„ç×k•Ú2Ÿi¬¤‰Ï3ŠÊðIF y2<ÅÓ¼ÂàÀøÊs&XLWñ÷ÓNÇIŸšü™áW‘Jpüz–õuôd:H?ñ}úy8xº÷ˆ„XÈWYË–¡Lí]Vòåò:»ÙÀ3”xëܹ˜DWVÐ×Å™Ìf_à³Ìæ’s  ’ý¼Å¯ØÄ~v}ÀaÀ:W£ôñºqõ]\ÆÕ\Ç5|œÙÄhžÒ“rŒp€ý¼Ä_ù;;ÿø•&ãO€ø Ô¦n3ÐK™GKi§(Q¢4òKl‰y²äÉ3È{ØËk¼ã×öcÀ ß¤9Sr¶î7ý”ù„âþô8ä[åu©å§pÉoF}À¹šVåŒÖ¹ìk Ÿé‡šQÓªT^s»>XûLvû#¹þ PbCpïó6IEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-70.png000066400000000000000000000053631357442400300230730ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß :.»B €IDAThÞíš{pTÕÇ?÷¹»ÙÝ¬ÉæUÀ$(Tˆ@À÷³b‘©:ŽZk;T‹Óvd¦cý£c­cG[j¶3vœvZ:Õ t¤N¡ŽŽ0("ZEÓtL ’lØ$ûÈ>î=÷ôÜ]v³ $˜vÐé™ùÍîžÜ=ûýžßóüNàÿã³3”±&WlX!i@5PøãSÁhņ’^$Ä饛£æ0åyÖ3€`~H‘ !‰!I"$ÁǼÉïX Ôœ­VÔÿ Ø€d ðf«ø5]¼Æ¹¨ôs“€%NžŒBy¬£ØÆe̼çé’O2À0*µ\΋¼Êw¹ žuäõwùIýàåÃ/oâ|*if:—1Ÿ&f¢¡ù Ðf¹‡€è'Å0•C>Çtnçq¶ñqŽ!K¤ÉI,žepÞ¹¤ ª¸šgx…#XEÉ1$'Hp?7eçrºðq÷q˜8]È"9Šä=,dÁdò…2¡g¢Ì}v,Q]Ñ&(*‹¸†½ôÒ‰,’£HÞå 7ñ)g¶äù—wl_¯ëꓺ¦µt )%Ž#‘Ò!›µp1òÙqpä©WÇqŽÄ‘ŽÍdüÆæoîây^ÅO hAÁϸ›'ù ü$ÔÍ›775ÏŸ½¿©q®¯ººÚÐ4 )%Š¢€wp‡L&C6›EJ‰”ÇC6›E‚L&C?Š¢ˆŽÛ‡‡¢ñ+7¾¹±ŽMlÇ(Hh çC°èr³È¤ó€háÚÐ=ÕáZ½¦¦Æèéé!•J‘ÍfÉd2d2,˲¬¢9MÓP…¾¾>"‘‘H$ÿÞ²,„šÏS¦¢Êµ¼È+üÇŠò„ TÐÌSÜÅÚQ'^<>ÓûõúúƲh4JyyùÈ"ªŠªª8ŽC:&•J1<<ŒMÓH$Äb1Ç9µ ¢  FðÔÕÖù¥wßxã^6ñ$pܽv€aqçè°ª…µ3˜Ï£>|Ç[VðÐ4 ÇqBÍfI&“$“IR©étÇq°,kÄÖei.BPSSƒã8A|¿zÑ‹n¥Ÿ/±¾ˆ€T1×%`ŒEÀ:ƒôpUxmË‚o:FeY ÇQ]×1 Ã0ò E)Ÿó‰t:ó^Üâ÷šÆý€Êo؆…(ªŸtBlâZÀ7Rõúë¯/÷ùÊ–×ÔÔ)±XŒÁÁA’É$>ŸÓ4óŽ™3ŸÏGEEáp˜p8L0̃/4£d2™'ÙØÐˆa˜‹V¯^ÝÈqÒá¹"60Ÿå…u’:!"ë(»ôò¥·µ¶¶êRJz{{‰Çãx<lÛ΋Û¶éìì$‹‰D8qâ}}}œ‘倎6Ã0ðù|x½^E!‘H ¥Ä4M4M#›ÍÒÔÔD*•ºtÁâUï9îFê'¥À¸†5kÖÜp~}c@Ó4ò KQ„¤ÓiTUÅï÷0MÃ0ò€rD,Ë"“ÉN§&‰ „À0Œ¼65MCUU<‹/Öâ;Ùå(êƒ1J =¤¸Ž/  ¢æiª,b)sx¿óëHS+ߣлØIÓ=¶(€ƒÍSFßyò²…¥,e?ýø‹àIàGxˆÇ±øÐí“r&i,²¼O7Wp9fA»ÛèÌávVáã‹ì£­xW&<¶PÆ}<Ôâå"*YM9_e•¾qZ ù%¿â ¶£#Ïdï*ê¹’y€:êÇ}2”»=£@¿Âšbn¯€ï¡‹'xš.vGÎt?0Ñxêñ±ï°žE,C™Ü]ÖÒ—Í;ìe3Ï’â€ÛBŒOE':7¼Àt`&sYÆ×ø s¹x ’š¤ƒüžig/Ðé:lzªZé£oXÎs­¾‘¥\ŵ\Íæ¤bR+Å ƒv^ãuÞb—ë¨}®½ÛSy0öíÊÈ­{{5:%̧•ÅÔQK€Êñ¹ ¨qÄH ‡^ö±Ÿ·ùèú·H³¦äß&1L×eƒ.¡Û=ö¹âÍç•N `Èwç²g `*‹2Ã%dº¦f‹¹knÛ›=›ÝþLŽÿ,!F‚ñIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-80.png000066400000000000000000000055161357442400300230740ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß gbõ* ÛIDAThÞíš{ŒTÕÇ?÷93;3;îξ  euU\Á߯V-’ÚJcÔZÛXߘÖhh¬4FѶôi›Ø˜6­MÕH#ÝJ4bP| [¬ÈËîÌ,óž{ï¹§ÌñÎÌ¢€ÛFMOòË,wÏ\¾ßó{ÿÎÂÿ×çg)“=\ºb©¦í@ ŒÏ£¥+–JƤÈ0Æ»ØÆ6þÆ£\ Ìb€ùY ™@rIIÉYÞçE~ϵ@Ç‘jEýŸ0€Ø€A˜8K¸„ß0̳<ÀE@ : È:q«d¢Ëõ<É»¬áTæÁOé‘8˜”€<*œÆ<Ã-œ D8rÔý^~R?Ü6¸Š£i¥—éœJ=ÌFC›ô  ‘g ·q ÉOŠa*—|é\ƽ¬á]2ìF6È’ýØ<Ì à¨Ok2hã,~Îvb³ Y#»‘ì%ËÍ\4}šÓEˆK¹‘mdFÖÈ.$;åDN¾PiÏ4y{'ÕíEe!g³™1v kd’×yÁK|Ê‘€mØ?¸ní º®Þ¯kzDQ_!¥Äu%RºX–ëŠò¿]W~øéº.Ò•¸Òu¬’uûwVw#ò a"5/4üŒ«¸Ÿ¿¹OB@]½zuOoßÜW{ºç‡ÚÛÛ MÓR¢(м‹ëº”J%,ËBJ‰”’@ €eY!BP*•Ø·oŠ¢ˆíïå$3gÜöâm]¬b-†/¡)@†wXÀR`ØË"y`åÊ•r銥råÊ•ò §¯Å;c×´Ç;õŽŽctt”B¡€eY”J%J¥¶mcÛvÍ3MÓP…ññq‰‰D¢ú³mÛ!´P IE•×òø;÷Ôä h¡—¹jµÓÈ6\½­ù­Ô©Øu d¿=sfwS2™¤¹¹¹üUEUU\×¥X,R(Èçó!Ð4l6K:ÆuÝOCQˆF£D"e<]]a)ÄUçŸ~Uü„,Y\ï¬] ÂB®¨«jMX¬€u`pÅ ƒ+«D*{ï¾ûγÁ¦æH8‚¦i¸®‹˲Èårär9 …Åb×u±m»lë²Q©B:::p]—H$J(V?ñø¯±,OsC hc¾GÀ˜Œ@èØ· «Ô+ƒ7 2xã ð4 ÇÛâ×ö/è‹E„ضÍÄÄ™LEQÐuÃ00 £ ZQ”ðŸ(‹àÄúÃAÓ¸Pù-k°5õ“NŒUœ„&#¥ pꊮ!þÍíwÞyç5‡BMttt)étš‰‰ r¹¡PÓ4«ŽY1“P(DKK ñxœxÇimi]1gö\-™L²}ûvb±XõÔëIÄãqFFF#‘HL&Éd2ôôôÔ„Y¿™¥R)’É$}Çö©š®] ¼ÏÖÂ5ð$°—ÜÁ½Ø¼ãÍIù8El,Þf„Ó9 Ó7îv€,:ó¸ŒKñ^æÉÚS9äõMÜÈ]ôð;vc4¼%Ãwrãlö@c¹©}ÄD¿@Š ²œÌ)(hÕ3ÀZ9™ÜÊWÙÃE¼wÈD£‰ë¸’/ò< g³¥¡•µ±ø±…užédŒx0Sù:7q#‘I&ņwAÃ%ÍIò$EޢĮ¯UBè$Èñ´²œf¾ÉTÆý±®Þù¿æž¶×GžÃ½hf1“3¸[ébæAwFfof`øô+<  íåуMüGæ>b˜çw?p¨ñ< Ì$ĉ|ŸXÈ”ûË:„ôåð›YÍÃØâ3S1‰®¬ 0˜Í|–ð-¾Á|N˜‚¤&âMþÀ ±Øá9lqªFéõ7,GyVßÍbÎäÎbó‰ÒrXoÊb;C<Ës¼ÄFÏQÇ={w¦ò.`òÛ•ò­{—w5:“éc€EtÑI„š y¨²¤É’e”1^æU^a+0ìF½"Íž’?8Œez.õżéqÈ“`5¯”]¸dàŒ÷Ì:RSY”!Ó35ÃW,V®¹¬u$§ý¹\ÿšÙí·ÛÝIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/48x48/progress-90.png000066400000000000000000000057221357442400300230740ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEßË׺& _IDAThÞí™}Œå}Ç?3³3û~뻽ۻخ}öal°Á>lÎ&€Á1Vi!B„д%Lš"”¤R•‡FD´”T$B‰RP ±#Š”4v ÆjÞ®—b|¶Ï··çÝõÎîíîÌ<óô]Ïï0ªŠòH?ÍÞÜÌ3ßïóüÞøãøð eº›·l”À\ è¢€þÿ‚ÑÆ-%i$9LÒŒq˜àg<έÀ| ÿØô䑜@R@RB’§È;¼È¹ HÍvWÔY°gô´ï- (‚(IÖq=ßc”_ñM®ºÀE äéó̇d‹¸ 2 qÎåžæm¶óQ–¡3M ÎXÿÜß=71+Ò#q*©S¨ôr1OñK¾Àz ~¦Â]\Ã1ŠAr¸Eá¼oOÖÍe|‡ç9„Ý6ÿ$Ç(rב™Nn°Š•bœÃHF[ä- |ž'ÏKs#wr³í;µ…g+g/`>¯ò‡‘l‘}Lð×|‡¯ñžNTO´Ó•Õ\Î^Òmß;ŒäU^ðŸ2N¶«Î½¬'ÅVËŠ˜<ÆO¶ß¸m8bÓ«1Em·1)%®+‘ÒŲl\WÔþv]\yòêº.Ò•¸Òu¬ªõ¥¿ÚòÙM<Î/‰kŠ8)†¸—õ<ÀOÒ{å/*°€×xŽ8ç ›B—Ã?óäÏþâ7?¾bÃîþ¥ážž]Ó4¤”(Šâïâº.Õj˲R"¥$ bYB„T«U&''QEŒ¼3Ý“ì ¤R)}||œr¹ŒeYT«UªÕ*¶mcÛvÓ=MÓP…‰‰ 2™ ™L¦ñÛ¶m„Z8QQåm<Åóüœ¯7}Û:Yƃ\¾Ý™†ÀVs3S(¸OÈcòÏòmÆÃFè/,èd³Y:::j“¨*ªªâº.•J…r¹ÌÔÔB4M£X,R(p]÷ä¢* ñxœX¬†§¯·/*…øÌUW]b+ߢH± à «¹¹Õ­ª- ÚºYÚô¢ ü† ò½ûîûêåÁP¤#¡i®ë"„À²,J¥¥R‰r¹L¥RÀu]lÛ®éºlBR©®ë‹Å Ç¢êy«Îû3&)ò ›Ûpt³Ô# OG ÌV6 Ñ’³Þa?SJv'o\9ªT*!°m›|>iš(ŠB @×ut]o€V¥ |Ý&*•JÝXuþ`4dèw*ÿÊvlD– ¶²OG Îr®ÆiIº†ùbüøÊ+¯ì‡#W§R}J¡P ŸÏS*•‡Ã†Ñ0̺š„Ãa:;;I&“$“Iâñx¼_J¥RƒdÿÂ~tÝX}à 7ôs” ‡ø~XÎÕþÃõç>Ó%vÓ K90ÿM®}„7€œ‡µ€ äÙÁNV²¾îgG—2:oñß|›¿g ñ~{5° v;7³‚ëIøk/$;Ø äý­ÍÖš8ÏNv±‰ý,cРݵ°1³PYÁV¾ÿ¸A6qS@ÐGàmö³“]ÆÐ¦iÚ*ŒSæ >Ž‚ŠÚ ©²šµ,á×ü‚·Í T&NqÖS$Ïwù^`0ÒêyfB@º€…,àR¾ÄÝô±à”OƯg ûöWx@Ë@Á‹£§jÎ3Ê7xˆQv‡<½—³%p²c ³ŠÏ³™Õ¬C™ÙYÖi„/‡ß²—âQÊì÷Zˆæ¬ÎvOuF̱”uüŸd)矠&æu~ÄS ³8èleÖ‡Óà„eާõý¬e=¸Œ%,%NçŒf2É1Â0¿â×¼Ä.ÏP'<}?íÓٮžîº÷yG£s¹å ±†>z‰#Fa¯UƤH"EÆI³Wx™·€1`÷’4{¦@ÞïöžÉÆ=B ¯{ö$Ôˆ+5.Eà„ØôîY³p&“2Ý#dxª¦û’Åú1·ãµf³ÚÊñ¿+86òA£ÊIEND®B`‚nemo-4.4.2/data/icons/hicolor/status/scalable/000077500000000000000000000000001357442400300212355ustar00rootroot00000000000000nemo-4.4.2/data/icons/hicolor/status/scalable/nemo-bookmark-not-found-symbolic.svg000066400000000000000000000142201357442400300302440ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme nemo-4.4.2/data/icons/meson.build000066400000000000000000000056101357442400300166510ustar00rootroot00000000000000publicIcons = [ 'hicolor/apps/16x16/nemo.png', 'hicolor/apps/22x22/nemo.png', 'hicolor/apps/24x24/nemo.png', 'hicolor/apps/32x32/nemo.png', 'hicolor/apps/scalable/nemo.svg', 'hicolor/actions/16x16/nemo-eject.png', 'hicolor/actions/16x16/menu-bullet.png', 'hicolor/actions/16x16/menu-sort-up.png', 'hicolor/actions/16x16/menu-sort-up-free.png', 'hicolor/actions/16x16/menu-sort-down.png', 'hicolor/actions/16x16/menu-sort-down-free.png', 'hicolor/actions/16x16/menu-sort-right.png', 'hicolor/actions/16x16/menu-sort-right-free.png', 'hicolor/actions/16x16/menu-sort-left.png', 'hicolor/actions/16x16/menu-sort-left-free.png', 'hicolor/actions/16x16/menu-none.png', 'hicolor/actions/32x32/nemo-eject.png', 'hicolor/actions/scalable/view-compact-symbolic.svg', 'hicolor/actions/scalable/location-symbolic.svg', 'hicolor/actions/scalable/mount-archive-symbolic.svg', 'hicolor/actions/scalable/sidebar-hide-symbolic.svg', 'hicolor/actions/scalable/sidebar-show-symbolic.svg', 'hicolor/actions/scalable/sidebar-tree-symbolic.svg', 'hicolor/actions/scalable/sidebar-places-symbolic.svg', 'hicolor/actions/scalable/nemo-auto-arrange-symbolic.svg', 'hicolor/actions/scalable/nemo-desktop-scale-symbolic.svg', 'hicolor/actions/scalable/nemo-horizontal-layout-symbolic.svg', 'hicolor/actions/scalable/nemo-horizontal-layout-wide-symbolic.svg', 'hicolor/actions/scalable/nemo-vertical-layout-symbolic.svg', 'hicolor/actions/scalable/nemo-vertical-layout-wide-symbolic.svg', 'hicolor/devices/scalable/drive-removable-media-usb-symbolic.svg', 'hicolor/status/48x48/progress-0.png', 'hicolor/status/48x48/progress-10.png', 'hicolor/status/48x48/progress-20.png', 'hicolor/status/48x48/progress-30.png', 'hicolor/status/48x48/progress-40.png', 'hicolor/status/48x48/progress-50.png', 'hicolor/status/48x48/progress-60.png', 'hicolor/status/48x48/progress-70.png', 'hicolor/status/48x48/progress-80.png', 'hicolor/status/48x48/progress-90.png', 'hicolor/status/48x48/progress-100.png', 'hicolor/status/scalable/nemo-bookmark-not-found-symbolic.svg', ] privateIcons = [ 'hicolor/emblems/16x16/emblem-note.png', 'hicolor/emblems/24x24/emblem-note.png', 'hicolor/emblems/48x48/emblem-note.png', ] noInstallIcons = [ 'hicolor/apps/16x16/nemo.svg', 'hicolor/apps/22x22/nemo.svg', 'hicolor/apps/32x32/nemo.svg', ] foreach icon : publicIcons nameParts = icon.split('/') theme = nameParts[0] context = nameParts[1] size = nameParts[2] file = nameParts[3] install_data(icon, install_dir: join_paths(get_option('datadir'), 'icons', theme, size, context) ) endforeach foreach icon : privateIcons nameParts = icon.split('/') theme = nameParts[0] context = nameParts[1] size = nameParts[2] file = nameParts[3] install_data(icon, install_dir: join_paths(get_option('datadir'), 'nemo', 'icons', theme, size, context) ) endforeach nemo-4.4.2/data/meson.build000066400000000000000000000040441357442400300155360ustar00rootroot00000000000000 ################################################################################ dataConf = configuration_data() dataConf.set('VERSION', meson.project_version()) desktopFiles = [ configure_file( input : 'nemo-autorun-software.desktop.in', output: 'nemo-autorun-software.desktop', configuration: dataConf, ), configure_file( input : 'nemo-autostart.desktop.in', output: 'nemo-autostart.desktop', configuration: dataConf, ), configure_file( input : 'nemo.desktop.in', output: 'nemo.desktop', configuration: dataConf, ) ] install_data(desktopFiles, install_dir: join_paths(get_option('datadir'), 'applications') ) ################################################################################ dataConf = configuration_data() dataConf.set('bindir', join_paths(get_option('prefix'), get_option('bindir'))) dbusFiles = [ configure_file( input : 'nemo.service.in', output: 'nemo.service', configuration: dataConf, ), configure_file( input : 'nemo.FileManager1.service.in', output: 'nemo.FileManager1.service', configuration: dataConf, ), ] install_data(dbusFiles, install_dir: join_paths(get_option('datadir'), 'dbus-1', 'services') ) ################################################################################ mimeFile_translated = custom_target('nemo.xml', input : ['nemo.xml.in'], output: 'nemo.xml', command: ['intltool-merge', '--quiet', '--xml-style', '--utf8', po_subdir, '@INPUT@', '@OUTPUT@' ], install: true, install_dir: join_paths(get_option('datadir'), 'mime', 'packages'), build_always: true, ) ################################################################################ dataConf = configuration_data() rootPolicyFile = configure_file( input : 'org.nemo.root.policy.in', output: 'org.nemo.root.policy', configuration: dataConf, ) install_data(rootPolicyFile, install_dir: join_paths(get_option('datadir'), 'polkit-1', 'actions') ) ################################################################################ subdir('icons') nemo-4.4.2/data/nemo-actions/000077500000000000000000000000001357442400300157665ustar00rootroot00000000000000nemo-4.4.2/data/nemo-actions/90_new-workspace.nemo_action.in000066400000000000000000000004441357442400300237070ustar00rootroot00000000000000[Nemo Action] Name=Jump to new workspace Comment=Create a new workspace and activate it Exec=sh -c 'dbus-send --dest=org.Cinnamon --print-reply /org/Cinnamon org.Cinnamon.JumpToNewWorkspace >/dev/null' Selection=None Extensions=any; Conditions=desktop;dbus org.Cinnamon; Active=false nemo-4.4.2/data/nemo-actions/91_delete-workspace.nemo_action.in000066400000000000000000000005221357442400300243560ustar00rootroot00000000000000[Nemo Action] Name=Remove workspace Comment=Remove the currently active workspace Exec=sh -c 'dbus-send --dest=org.Cinnamon --print-reply /org/Cinnamon org.Cinnamon.RemoveCurrentWorkspace >/dev/null' Selection=None Extensions=any; Conditions=desktop;dbus org.Cinnamon;gsettings org.cinnamon number-workspaces i gt 1; Active=false nemo-4.4.2/data/nemo-actions/92_show-expo.nemo_action.in000066400000000000000000000004471357442400300230600ustar00rootroot00000000000000[Nemo Action] Name=Manage workspaces (Expo) Comment=Open Expo to add, remove, or organize workspaces Exec=sh -c 'dbus-send --dest=org.Cinnamon --print-reply /org/Cinnamon org.Cinnamon.ShowExpo >/dev/null' Selection=None Extensions=any; Conditions=desktop;dbus org.Cinnamon; Active=false nemo-4.4.2/data/nemo-actions/action_i18n_strings.py000066400000000000000000000025611357442400300222310ustar00rootroot00000000000000 ''' This is a dummy file for translating Nemo Action files It was generated by the extract_action_strings script on 2019-11-16 14:32:22.650217 UTC. ''' 92_show-expo_nemo_action_in_Name = _("Manage workspaces (Expo)") 92_show-expo_nemo_action_in_Tooltip = _("Open Expo to add, remove, or organize workspaces") 91_delete-workspace_nemo_action_in_Name = _("Remove workspace") 91_delete-workspace_nemo_action_in_Tooltip = _("Remove the currently active workspace") mount-archive_nemo_action_in_Name = _("Mount archive") mount-archive_nemo_action_in_Tooltip = _("Mount %f to browse its contents") add-desklets_nemo_action_in_Name = _("Add Desklets") add-desklets_nemo_action_in_Tooltip = _("Add Cinamon desklets") change-background_nemo_action_in_Name = _("Change Desktop _Background") change-background_nemo_action_in_Tooltip = _("Change the Cinnamon desktop background") set-as-background_nemo_action_in_Name = _("Set as Wallpaper...") set-as-background_nemo_action_in_Tooltip = _("Set the selected image as your Cinnamon desktop wallpaper") new-launcher_nemo_action_in_Name = _("Create a new l_auncher here...") new-launcher_nemo_action_in_Tooltip = _("Create a new launcher in this folder") 90_new-workspace_nemo_action_in_Name = _("Jump to new workspace") 90_new-workspace_nemo_action_in_Tooltip = _("Create a new workspace and activate it") nemo-4.4.2/data/nemo-actions/add-desklets.nemo_action.in000066400000000000000000000003511357442400300231530ustar00rootroot00000000000000[Nemo Action] Name=Add Desklets Comment=Add Cinamon desklets Exec=cinnamon-settings desklets Selection=None Extensions=any; Icon-Name=cs-desklets-symbolic Dependencies=cinnamon-settings; Conditions=desktop;dbus org.Cinnamon; nemo-4.4.2/data/nemo-actions/change-background.nemo_action.in000066400000000000000000000004201357442400300241460ustar00rootroot00000000000000[Nemo Action] Name=Change Desktop _Background Comment=Change the Cinnamon desktop background Exec=cinnamon-settings backgrounds Selection=None Icon-Name=cs-backgrounds-symbolic Extensions=any; Dependencies=cinnamon-settings; Conditions=desktop;dbus org.Cinnamon; nemo-4.4.2/data/nemo-actions/extract_action_strings000077500000000000000000000041731357442400300225010ustar00rootroot00000000000000#!/usr/bin/python3 import os import glob import datetime import sys import codecs from gi.repository import GLib GROUP = "Nemo Action" class Main: def __init__(self): if len(sys.argv) > 1: action_files = glob.glob(os.path.join(sys.argv[1], "*.nemo_action.in")) else: action_files = glob.glob(os.path.join(os.getcwd(), "*.nemo_action.in")) if len(action_files) > 0: dt = datetime.datetime outstring = """ ''' This is a dummy file for translating Nemo Action files It was generated by the extract_action_strings script on %s UTC. ''' """ % (dt.utcnow()) outstring += "\n" for fn in action_files: keyfile = GLib.KeyFile.new() if keyfile.load_from_file(fn, GLib.KeyFileFlags.NONE): if keyfile.has_group(GROUP): friendly_fn = os.path.split(fn)[1].replace(".", "_") try: name = keyfile.get_string(GROUP, "Name") name_line = '%s_Name = _("%s")\n' % (friendly_fn, name) outstring += (name_line) except GLib.GError: name = None try: tooltip = keyfile.get_string(GROUP, "Comment") tooltip_line = '%s_Tooltip = _("%s")\n' % (friendly_fn, tooltip) outstring += (tooltip_line) except GLib.GError: tooltip = None if len(sys.argv) > 1: outfilename = os.path.join(sys.argv[1], "action_i18n_strings.py") else: outfilename = os.path.join(os.getcwd(), "action_i18n_strings.py") if os.path.exists(outfilename): os.remove(outfilename) outfile = codecs.open(outfilename, 'w', 'utf-8') outfile.write(outstring) outfile.close() print("Extraction complete. Run makepot now") if __name__ == "__main__": Main() nemo-4.4.2/data/nemo-actions/merge_action_strings000077500000000000000000000056771357442400300221400ustar00rootroot00000000000000#!/usr/bin/python3 import os import glob import polib import codecs from gi.repository import GLib GROUP = "Nemo Action" class Main: def __init__(self): self.in_keyfiles = {} self.mo_files = {} action_files = glob.glob(os.path.join(os.getcwd(), "*.nemo_action.in")) if len(action_files) > 0: for fn in action_files: keyfile = GLib.KeyFile.new() if keyfile.load_from_file(fn, GLib.KeyFileFlags.KEEP_COMMENTS): if keyfile.has_group(GROUP): self.in_keyfiles[fn] = keyfile if len(self.in_keyfiles) > 0: for root, subFolders, files in os.walk("/usr/share/locale"): for file in files: if file == "nemo.mo": path, junk = os.path.split(root) path, locale = os.path.split(path) try: self.mo_files[locale] = polib.mofile(os.path.join(root, file)) except: print("merge_action_strings - Failed to load .mo file: %s" % (os.path.join(root, file))) if len(self.mo_files) > 0: for locale in self.mo_files.keys(): for entry in self.mo_files[locale]: self.check_name(locale, entry) for locale in self.mo_files.keys(): for entry in self.mo_files[locale]: self.check_comment(locale, entry) for fn in self.in_keyfiles.keys(): action_fn = os.path.split(fn)[1].replace(".in", "") action_path = os.path.join("..", "..", "files", "usr", "share", "nemo", "actions", action_fn) outstring, length = self.in_keyfiles[fn].to_data() if os.path.exists(action_path): os.remove(action_path) outfile = codecs.open(action_path, 'w', 'utf-8') outfile.write(outstring) outfile.close() print("Merge complete - .nemo_action files in ../files/usr/share/nemo/actions should contain translations now.") def check_name(self, locale, entry): if entry.msgstr != '': for kf in self.in_keyfiles.keys(): try: name = self.in_keyfiles[kf].get_string(GROUP, "Name") if name == entry.msgid: self.in_keyfiles[kf].set_locale_string(GROUP, "Name", locale, entry.msgstr) except GLib.GError: pass def check_comment(self, locale, entry): if entry.msgstr != '': for kf in self.in_keyfiles.keys(): try: name = self.in_keyfiles[kf].get_string(GROUP, "Comment") if name == entry.msgid: self.in_keyfiles[kf].set_locale_string(GROUP, "Comment", locale, entry.msgstr) except GLib.GError: pass if __name__ == "__main__": Main() nemo-4.4.2/data/nemo-actions/mount-archive.nemo_action.in000066400000000000000000000007401357442400300233720ustar00rootroot00000000000000[Nemo Action] Name=Mount archive Comment=Mount %f to browse its contents Exec=/usr/lib/gvfs/gvfsd-archive file="%U" Selection=s Mimetypes=application/x-7z-compressed;application/x-cd-image;application/x-cpio;application/x-rar;application/x-rar-compressed;application/x-7z-compressed-tar;application/x-bzip-compressed-tar;application/x-compressed-tar;application/x-tar;application/zip; Icon-Name=mount-archive-symbolic Dependencies=/usr/lib/gvfs/gvfsd-archive; Selection=s nemo-4.4.2/data/nemo-actions/new-launcher.nemo_action.in000066400000000000000000000004211357442400300231750ustar00rootroot00000000000000[Nemo Action] Name=Create a new l_auncher here... Comment=Create a new launcher in this folder Exec=cinnamon-desktop-editor -mnemo-launcher -d"%P" Selection=None Icon-Name=list-add-symbolic Extensions=any; Dependencies=cinnamon-desktop-editor; Conditions=desktop; nemo-4.4.2/data/nemo-actions/set-as-background.nemo_action.in000066400000000000000000000003601357442400300241200ustar00rootroot00000000000000[Nemo Action] Name=Set as Wallpaper... Comment=Set the selected image as your Cinnamon desktop wallpaper Exec=gsettings set org.cinnamon.desktop.background picture-uri "%U" Selection=s Mimetypes=image/*; Conditions=dbus org.Cinnamon; nemo-4.4.2/data/nemo-autorun-software.desktop.in000066400000000000000000000131571357442400300216620ustar00rootroot00000000000000[Desktop Entry] Name=Autorun Prompt Name[af]=Autorun Prompt Name[am]=Autorun Prompt Name[ar]=محث التنÙيذ التلقائي Name[as]=অটোৰান সংকà§à§°à¦¾à¦¨à§à¦¤ পà§à§°à¦®à¦ªà§à¦Ÿ Name[ast]=Programa d'autoexecución Name[az]=Autorun Prompt Name[az_IR]=Autorun Prompt Name[be]=ПацвÑрджÑнне аўтаматычнага запуÑку Name[be@latin]=Zapyt aÅ­tamatyÄnaha Å­ruchamleÅ„nia Name[bg]=Питане за автоматично Ñтартиране Name[bg_BG]=Питане за автоматично Ñтартиране Name[bn]=অটোরান সংকà§à¦°à¦¾à¦¨à§à¦¤ পà§à¦°à§‹à¦®à¦ªà§à¦Ÿ Name[bn_IN]=অটোরান সংকà§à¦°à¦¾à¦¨à§à¦¤ পà§à¦°à¦®à¦ªà§à¦Ÿ Name[bo]=རང་འགུལ་གྱིས་འà½à½¼à½¢à¼‹à½¦à¾à¾±à½¼à½‘་ལ་གསལ་འདེབས་ Name[br]=Pedadenn emerounit Name[ca]=Pregunta d'execució automàtica Name[ca@valencia]=Pregunta d'execució automàtica Name[crh]=KendiliÄŸinden Çalışma Sorusu Name[cs]=Výzva automatického spuÅ¡tÄ›ní Name[da]=Autokørselsforespørgsel Name[de]=Autostart-Nachfrage Name[de_CH]=Autostart-Nachfrage Name[de_DE]=Autostart-Nachfrage Name[dz]=Autorun Prompt Name[el]=Ειδοποίηση αυτόματης εκτέλεσης Name[en@shaw]=Autorun Prompt Name[en_AU]=Autorun Prompt Name[en_CA]=Autorun Prompt Name[en_GB]=Autorun Prompt Name[eo]=AÅ­tomata lanĉinvito Name[es]=Pregunta de autoejecución Name[es_AR]=Pregunta de autoejecución Name[es_CL]=Pregunta de autoejecución Name[es_CO]=Pregunta de autoejecución Name[es_CR]=Pregunta de autoejecución Name[es_DO]=Pregunta de autoejecución Name[es_EC]=Pregunta de autoejecución Name[es_ES]=Pregunta de autoejecución Name[es_GT]=Pregunta de autoejecución Name[es_HN]=Pregunta de autoejecución Name[es_MX]=Pregunta de autoejecución Name[es_NI]=Pregunta de autoejecución Name[es_PA]=Pregunta de autoejecución Name[es_PE]=Pregunta de autoejecución Name[es_PR]=Pregunta de autoejecución Name[es_SV]=Pregunta de autoejecución Name[es_UY]=Pregunta de autoejecución Name[es_VE]=Pregunta de autoejecución Name[et]=Automaatkäivituse küsimus Name[et_EE]=Automaatkäivituse küsimus Name[eu]=Autoexekuzioaren galdera Name[fa]=اعلان اجرای خودکار Name[fa_IR]=اعلان اجرای خودکار Name[fi]=Automaattisuorituksen kehote Name[fr]=Invite d'exécution automatique Name[fur]=Autorun Prompt Name[fy]=Autorun Prompt Name[ga]=Autorun Prompt Name[gl]=Preguntar polo autoarrinque Name[gu]=પà«àª°à«‹àª®à«àªªà«àªŸàª¨à«‡ આપમેળે ચલાવો Name[gv]=Roie choonee hene Name[ha]=Autorun Prompt Name[he]=בקשה להפעלה ×וטומטית Name[hi]=सà¥à¤µà¤¤à¤ƒ चलाà¤à¤ पà¥à¤°à¤¾à¤‚पà¥à¤Ÿ Name[hr]=Autorun Prompt Name[hu]=Automatikus futtatás Name[hy]=Autorun Prompt Name[id]=Sapaan Jalan Otomatis Name[ig]=Autorun Prompt Name[io]=Autorun Prompt Name[is]=Sjálfkeyrslukvaðning Name[it]=Conferma esecuzione automatica Name[it_IT]=Conferma esecuzione automatica Name[ja]=オートランã®å•ã„åˆã‚ã› Name[ka]=áƒáƒ•ტáƒ-გáƒáƒ¨áƒ•ების შემáƒáƒ—áƒáƒ•áƒáƒ–ებრName[kk]=Autorun Prompt Name[km]=Autorun Prompt Name[kn]=ತಾನಾಗಿಯೆ ಚಲಾಯಿಸà³à²µ ಪà³à²°à²¾à²ªà³à²Ÿà³ Name[ko]=ìžë™ì‹œìž‘ í™•ì¸ Name[ku]=Autorun Prompt Name[li]=Autorun Prompt Name[lt]=Automatinio paleidimo raginimas Name[lv]=AutomÄtiskÄs palaiÅ¡anas uzvedne Name[mai]=Autorun Prompt Name[mg]=Autorun Prompt Name[mi]=Autorun Prompt Name[mk]=ÐвтоматÑко извршување Name[ml]=Autorun Prompt Name[mn]=Autorun Prompt Name[mr]=पà¥à¤°à¥‰à¤®à¤ªà¥à¤Ÿ आपोआप चालवा Name[ms]=Desakan Lari auto Name[ms_MY]=Desakan Lari auto Name[my]=Autorun Prompt Name[my_MM]=Autorun Prompt Name[nb]=Dialog for automatisk kjøring Name[nds]=Autorun Avfrage Name[ne]=Autorun Prompt Name[nl]=Autorun dialoogvenster Name[nl_NL]=Autorun dialoogvenster Name[nso]=Autorun Prompt Name[oc]=Demanda d'execucion automatica Name[or]=ସà­à­±à­Ÿà¬‚ଚାଳନ ପà­à¬°à­‹à¬®à­à¬ªà¬Ÿ Name[pa]=ਆਟੋ-ਰਨ ਸਵਾਲ Name[pl]=Pytanie o automatyczne uruchamianie Name[ps]=Autorun Prompt Name[pt]=Questão de Execução Automática Name[pt_BR]=Pergunta de execução automática Name[pt_PT]=Questão de Execução Automática Name[ro]=Solicitare pornire automată Name[ru]=Предложение автозапуÑка Name[si]=Autorun Prompt Name[sk]=Výzva automatického spustenia Name[sl]=Poziv samodejnega zagona Name[sr]=ÐутоматÑко покретање Name[sr@Latn]=Automatsko pokretanje Name[sr@ije]=ÐутоматÑко покретање Name[sr@latin]=Automatsko pokretanje Name[sv]=Automatisk körning Name[ta]=தானியஙà¯à®•ி தூணà¯à®Ÿà®¿ Name[ta_LK]=தானியஙà¯à®•ி தூணà¯à®Ÿà®¿ Name[te]=à°¸à±à°µà°¯à°‚చాలకంగా à°…à°¡à±à°—à± Name[th]=คำถาม Autorun Name[tk]=Autorun Prompt Name[tr]=KendiliÄŸinden Çalışma Sorusu Name[ug]=ئۆزلۈكىدىن ئىجرا ئەسكەرتىشى Name[uk]=ÐŸÑ€Ð¾Ð¿Ð¾Ð·Ð¸Ñ†Ñ–Ñ Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿ÑƒÑку Name[uz]=Autorun Prompt Name[uz@cyrillic]=Autorun Prompt Name[vi]=Há»i tá»± động chạy Name[wa]=Autorun Prompt Name[yi]=Autorun Prompt Name[yo]=Autorun Prompt Name[zh]=自动è¿è¡Œæç¤º Name[zh_CN]=自动è¿è¡Œæç¤º Name[zh_HK]=自動執行æç¤º Name[zh_TW]=自動執行æç¤º Name[zu]=Autorun Prompt TryExec=nemo-autorun-software Exec=nemo-autorun-software %u Icon=application-x-executable NoDisplay=true Terminal=false StartupNotify=false Type=Application MimeType=x-content/unix-software; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=nemo X-GNOME-Bugzilla-Component=general X-GNOME-Bugzilla-Version=@VERSION@ nemo-4.4.2/data/nemo-autostart.desktop.in000066400000000000000000000003421357442400300203530ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Nemo Comment=Start Nemo desktop at log in Exec=nemo-desktop OnlyShowIn=X-Cinnamon; AutostartCondition=GSettings org.nemo.desktop show-desktop-icons X-GNOME-AutoRestart=true NoDisplay=true nemo-4.4.2/data/nemo.FileManager1.service.in000066400000000000000000000001311357442400300205440ustar00rootroot00000000000000[D-BUS Service] Name=org.freedesktop.FileManager1 Exec=@bindir@/nemo --no-default-window nemo-4.4.2/data/nemo.desktop.in000066400000000000000000000172601357442400300163360ustar00rootroot00000000000000[Desktop Entry] Name=Files Name[am]=á‹á‹­áˆŽá‰½ Name[ar]=Ø§Ù„Ù…Ù„ÙØ§Øª Name[bg]=Файлове Name[ca]=Fitxers Name[ca@valencia]=Fitxers Name[cs]=Soubory Name[cy]=Ffeiliau Name[da]=Filer Name[de]=Dateien Name[el]=ΑÏχεία Name[eo]=Dosieroj Name[es]=Archivos Name[et]=Failid Name[eu]=Fitxategiak Name[fi]=Tiedostot Name[fr]=Fichiers Name[fr_CA]=Fichiers Name[he]=×§×‘×¦×™× Name[hr]=Nemo Name[hu]=Fájlok Name[id]=Berkas Name[is]=Skrár Name[kab]=Ifuyla Name[ko]=íŒŒì¼ Name[lt]=Failai Name[nl]=Bestanden Name[pl]=Pliki Name[pt]=Ficheiros Name[pt_BR]=Arquivos Name[ro]=FiÈ™iere Name[ru]=Файлы Name[sk]=Súbory Name[sl]=Datoteke Name[sr]=Датотеке Name[sr@latin]=Датотеке Name[sv]=Filer Name[th]=à¹à¸Ÿà¹‰à¸¡ Name[tr]=Dosyalar Name[uk]=Файли Name[zh_CN]=文件 Name[zh_HK]=檔案 Comment=Access and organize files Comment[am]=á‹á‹­áˆŽá‰½ ጋር መድረሻ እና ማደራጃ Comment[ar]=الوصول إلى Ø§Ù„Ù…Ù„ÙØ§Øª وتنظيمها Comment[bg]=ДоÑтъп и управление на файлове Comment[ca]=Organitzeu i accediu als fitxers Comment[ca@valencia]=Organitzeu i accediu als fitxers Comment[cs]=Přístup k souborům a jejich správa Comment[cy]=Mynediad i drefnu ffeiliau Comment[da]=TilgÃ¥ og organisér filer Comment[de]=Dateien aufrufen und organisieren Comment[el]=ΠÏόσβαση και οÏγάνωση αÏχείων Comment[en_GB]=Access and organise files Comment[eo]=Atingi kaj organizi dosierojn Comment[es]=Acceder a los archivos y organizarlos Comment[et]=Ligipääs failidele ning failipuu korrastamine Comment[eu]=Atzitu eta antolatu fitxategiak Comment[fi]=Avaa ja järjestä tiedostoja Comment[fr]=Accéder aux fichiers et les organiser Comment[fr_CA]=Accéder aux fichiers et les organiser Comment[he]=גישה ×œ×§×‘×¦×™× ×•××¨×’×•× × Comment[hr]=Pristupite i organizirajte datoteke Comment[hu]=Fájlok elérése és rendszerezése Comment[ia]=Acceder e organisar le files Comment[id]=Akses dan kelola berkas Comment[ie]=Accesse e ordina files Comment[is]=Aðgangur og skipulag skráa Comment[it]=Accede ai file e li organizza Comment[kab]=Kcem udiÉ£ suddes ifuyla Comment[ko]=íŒŒì¼ ì ‘ê·¼ ë° ì •ë¦¬ Comment[lt]=Gauti prieigÄ… prie failų ir juos tvarkyti Comment[nl]=Bestanden gebruiken en organiseren Comment[pl]=PorzÄ…dkowanie i dostÄ™p do plików Comment[pt]=Aceder e organizar ficheiros Comment[pt_BR]=Acesse e organize arquivos Comment[ro]=Accesează È™i organizează fiÈ™iere Comment[ru]=Управление и доÑтуп к файлам Comment[sk]=Prístup a organizácia súborov Comment[sl]=Dostop in razvrÅ¡Äanje datotek Comment[sr]=ПриÑтупите датотекама и организујте их Comment[sr@latin]=ПриÑтупите датотекама и организујте их Comment[sv]=Kom Ã¥t och organisera filer Comment[th]=เข้าถึงà¹à¸¥à¸°à¸ˆà¸±à¸”ระเบียบà¹à¸Ÿà¹‰à¸¡ Comment[tr]=Dosyalara eriÅŸ ve düzenle Comment[uk]=ДоÑтуп до файлів та впорÑÐ´ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² Comment[zh_CN]=访问和组织文件 Comment[zh_HK]=å­˜å–與組織檔案 Exec=nemo %U Icon=folder # Translators: these are keywords of the file manager Keywords=folders;filesystem;explorer; Terminal=false Type=Application StartupNotify=false Categories=GNOME;GTK;Utility;Core; MimeType=inode/directory;application/x-gnome-saved-search; Actions=open-home;open-computer;open-trash; [Desktop Action open-home] Name=Home Name[af]=Tuis Name[am]=ቤት Name[ar]=المجلد الرئيسي Name[be]=Дом Name[bg]=Домашна папка Name[bn]=হোম Name[bs]=PoÄetni direktorij Name[ca]=Carpeta de l'usuari Name[ca@valencia]=Carpeta de l'usuari Name[cs]=Domov Name[cy]=Cartref Name[da]=Hjem Name[de]=Persönlicher Ordner Name[el]=ΠÏοσωπικός φάκελος Name[eo]=Hejmo Name[es]=Carpeta personal Name[et]=Kodu Name[eu]=Karpeta nagusia Name[fi]=Koti Name[fr]=Dossier personnel Name[fr_CA]=Dossier personnel Name[ga]=Baile Name[gd]=Dhachaigh Name[gl]=Cartafol persoal Name[he]=בית Name[hr]=Osobna mapa Name[hu]=Saját mappa Name[ia]=Al domo Name[id]=Beranda Name[ie]=Hem Name[is]=Heimamappa Name[ja]=ホーム Name[kab]=Agejdan Name[kk]=Үй Name[kn]=ಮನೆ Name[ko]=홈 Name[ku]=Mal Name[lt]=Namai Name[ml]=ആസàµà´¥à´¾à´¨à´‚ Name[mr]=मà¥à¤–à¥à¤¯ Name[ms]=Rumah Name[nb]=Hjem Name[nl]=Persoonlijke map Name[oc]=Dorsièr personal Name[pl]=Katalog domowy Name[pt]=Pasta Pessoal Name[pt_BR]=Pasta pessoal Name[ro]=Dosar personal Name[ru]=ДомашнÑÑ Ð¿Ð°Ð¿ÐºÐ° Name[sk]=Domov Name[sl]=Domov Name[sr]=Почетна Name[sr@latin]=PoÄetna Name[sv]=Hem Name[ta]=இலà¯à®²à®®à¯ Name[tg]=ÐÑоÑÓ£ Name[th]=บ้าน Name[tr]=Ev Dizini Name[uk]=Домівка Name[ur]=المنزل Name[vi]=Nhà Name[zh_CN]=主目录 Name[zh_HK]=å®¶ Name[zh_TW]=å®¶ Exec=nemo %U [Desktop Action open-computer] Name=Computer Name[af]=Rekenaar Name[am]=ኮáˆá’ዩተር Name[ar]=الكمبيوتر Name[ast]=Ordenador Name[be]=Кампутар Name[bg]=Компютър Name[bn]=কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦° Name[bs]=RaÄunar Name[ca]=Ordinador Name[ca@valencia]=Ordinador Name[cs]=PoÄítaÄ Name[cy]=Cyfrifiadur Name[de]=Rechner Name[el]=Υπολογιστής Name[eo]=Komputilo Name[es]=Equipo Name[et]=Arvuti Name[eu]=Ordenagailua Name[fi]=Tietokone Name[fr]=Poste de travail Name[fr_CA]=Poste de travail Name[gd]=Coimpiutair Name[gl]=Computador Name[he]=מחשב Name[hr]=RaÄunalo Name[hu]=Számítógép Name[ia]=Computator Name[id]=Komputer Name[ie]=Computator Name[is]=Tölva Name[ja]=コンピュータ Name[kab]=Aselkim Name[kk]=Компьютер Name[kn]=ಗಣಕ Name[ko]=컴퓨터 Name[ku]=Komputer Name[lt]=Kompiuteris Name[ml]=à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ Name[mr]=संगणक Name[ms]=Komputer Name[nb]=Datamaskin Name[nn]=Datamaskin Name[oc]=Ordenador Name[pl]=Komputer Name[pt]=Computador Name[pt_BR]=Computador Name[ru]=Компьютер Name[sk]=PoÄítaÄ Name[sl]=RaÄunalnik Name[sq]=Kompjuteri Name[sr]=Рачунар Name[sr@latin]=RaÄunar Name[sv]=Dator Name[ta]=கணினி Name[tg]=Компютер Name[th]=คอมพิวเตอร์ Name[tr]=Bilgisayar Name[uk]=Комп’ютер Name[ur]=کمپیوٹر Name[vi]=Máy tính Name[zh_CN]=计算机 Name[zh_HK]=電腦 Name[zh_TW]=電腦 Exec=nemo computer:/// [Desktop Action open-trash] Name=Trash Name[af]=Asblik Name[am]=ቆሻሻ Name[ar]=سلة المهملات Name[ast]=Papelera Name[be]=Сметніца Name[bg]=Кошче Name[bn]=টà§à¦°à§à¦¯à¦¾à¦¶ Name[bs]=Smeće Name[ca]=Paperera Name[ca@valencia]=Paperera Name[cs]=KoÅ¡ Name[cy]=Sbwriel Name[da]=Papirkurv Name[de]=Papierkorb Name[el]=ΑποÏÏίμματα Name[en_GB]=Rubbish Bin Name[eo]=Rubujo Name[es]=Papelera Name[et]=Prügi Name[eu]=Zakarrontzia Name[fi]=Roskakori Name[fr]=Corbeille Name[fr_CA]=Corbeille Name[ga]=Bruscar Name[gd]=An sgudal Name[gl]=Lixo Name[he]=×שפה Name[hr]=Smeće Name[hu]=Kuka Name[ia]=Immunditia Name[id]=Tempat sampah Name[ie]=Paper-corb Name[is]=Rusl Name[it]=Cestino Name[ja]=ゴミ箱 Name[kab]=Iá¸umman Name[kk]=Себет Name[kn]=ಕಸಬà³à²Ÿà³à²Ÿà²¿ Name[ko]=휴지통 Name[ku]=Avêtî Name[lt]=Å iukÅ¡linÄ— Name[ml]=à´Ÿàµà´°à´¾à´·àµ Name[mr]=कचरापेटी Name[ms]=Tong Sampah Name[nb]=Papirkurv Name[nds]=Papierkorb Name[nl]=Prullenbak Name[nn]=Papirkorg Name[oc]=Escobilhièr Name[pl]=Kosz Name[pt]=Lixo Name[pt_BR]=Lixeira Name[ro]=CoÈ™ de gunoi Name[ru]=Корзина Name[sk]=Kôš Name[sl]=Smeti Name[sq]=Koshi Name[sr]=Смеће Name[sr@latin]=Kanta Name[sv]=Papperskorg Name[ta]=கà¯à®ªà¯à®ªà¯ˆà®¤à¯ தொடà¯à®Ÿà®¿ Name[tg]=Сабад Name[th]=ถังขยะ Name[tr]=Çöp Name[uk]=Смітник Name[ur]=ردی Name[vi]=Thùng rác Name[zh_CN]=回收站 Name[zh_HK]=垃圾桶 Name[zh_TW]=回收筒 Exec=nemo trash:/// nemo-4.4.2/data/nemo.service.in000066400000000000000000000001041357442400300163120ustar00rootroot00000000000000[D-BUS Service] Name=org.Nemo Exec=@bindir@/nemo --no-default-windownemo-4.4.2/data/nemo.xml.in000066400000000000000000000010451357442400300154570ustar00rootroot00000000000000 <_comment>Saved search <_comment>A Nemo action definition file nemo-4.4.2/data/org.Cinnamon.xml000066400000000000000000000013451357442400300164470ustar00rootroot00000000000000 nemo-4.4.2/data/org.nemo.root.policy.in000066400000000000000000000014771357442400300177370ustar00rootroot00000000000000 Nemo Project https://github.com/linuxmint/nemo Run Nemo with elevated privileges Files gksu-root-terminal no no auth_admin_keep /usr/bin/nemo true nemo-4.4.2/debian/000077500000000000000000000000001357442400300137035ustar00rootroot00000000000000nemo-4.4.2/debian/changelog000066400000000000000000002552101357442400300155620ustar00rootroot00000000000000nemo (4.4.2) tricia; urgency=medium [ leigh123linux ] * meson.build: Disable GLib deprecation warnings [ Leigh Scott ] * file-operations: fix copying from the trash [ Michael Webster ] * list view: Don't remove the dummy (Loading) entry except during post-loading updates. * nemo-tree-sidebar.c: Don't free the NemoFile after setting up the context menu for showing, it is owned by the tree model. [ leigh123linux ] * Remove tracker [ Leigh Scott ] * nemo-icon-canvas-item.c: Don't hyphenate long filenames * eel-editable-label.c: Don't hyphenate long filenames [ Michael Webster ] * nemo-program-choosing.c: Remove unused variable that was causing a warning during the build. [ Leigh Scott ] * Use meson for pango-1.44 check -- Clement Lefebvre Thu, 12 Dec 2019 11:43:40 +0000 nemo (4.4.1) tricia; urgency=medium [ Michael Webster ] * nemo-desktop-metadata.c: Remove a key when the metadata string is null instead of attempting to set the key to null (which doesn't work for GKeyfiles). * nemo-window.c: Disconnect thumbnail settings handlers when the window is destroyed. -- Clement Lefebvre Thu, 28 Nov 2019 20:00:39 +0000 nemo (4.4.0) tricia; urgency=medium [ Michael Webster ] * nemo-query-editor.c: Don't allow activation when there is no valid search string. * nemo-window-slot.c: Don't try to set anything on query if it's NULL. * nemo-main-application.c: when parsing options, don't try to use part of an array that has already been freed, make a copy instead. * nemo-main-application.c: Fix variable name for consistency and spelling. * nemo-program-choosing.c: Update how desktop files are launched - launch_uris_as_manager does a better job, and this also replaces a previous patch for a pkexec issue in desktop files, and is a more complete fix. * preferences: Reveal the default sort direction setting. [ AO-LocLab ] * Correction to the French translations (#2228) [ Michael Webster ] * context menu: Make individual menu item visibility configurable in preferences, and eliminate the simple/complex menu option. * gsettings: re-add old context menu entry to prevent crashes with old nemo-fileroller verions. [ Clement Lefebvre ] * l10n: Fix some msgids * l10n: Update POT * l10n: Generate files -- Clement Lefebvre Sat, 16 Nov 2019 15:34:24 +0100 nemo (4.2.2) tina; urgency=medium [ Clement Lefebvre ] * l10n: Update POT [ Michael Webster ] * nemo-desktop-link.c: Don't allow an attempt to rename mounts. -- Clement Lefebvre Thu, 25 Jul 2019 10:28:21 +0200 nemo (4.2.1) tina; urgency=medium [ Clement Lefebvre ] * l10n: Fix msgid * l10n: Fix msgids [ gm10 ] * Fix nemo_global_preferences_get_size_prefix_preference getting set to the wrong value (#2165) [ Michael Webster ] * nemo-file-operations.c: Add comment for unused singular translation, make the string obviously unused. * nemo-view.c: Always show the pin/unpin actions. * various: Fix a couple leaks * nemo-list-model.c: When the last child of a node is removed, Handle re-adding a dummy row (or not) in the file removed handler, instead of always adding one, then removing it on parent's subsequent changed call. * nemo-list-view.c: When triggering a rename using the 'slow double click' trigger, check whether the file is a folder to determine whether to select all or only non-extension text. * nemo-view.c: Use the stack for running the action visiblity cycle. * nemo-*-view.c: Update the selection info when a view has finished loading. [ Clement Lefebvre ] * Toolbar: Don't show thumbnail button by default -- Clement Lefebvre Wed, 10 Jul 2019 12:10:27 +0200 nemo (4.2.0) tina; urgency=medium [ Michael Webster ] * nemo-view.c: Don't ignore non-symbolic extension menu icons. * nemo-icon-view.c: Don't apply the 'ignore metadata' mode to the desktop, this prevents the icon size from loading or saving properly when that setting is active. * nemo-icon-info: Use different text widths for the desktop than for windowed mode. [ Leigh Scott ] * Update URL (#2045) [ Michael Webster ] * nemo-query-editor.c: Ignore leading and trailing whitespace in search query text. * misc: Fix some memory leaks revealed by valgrind. * Add keyboard shortcuts page * nemo-bookmarks-window.c: Fix support for Computer/Bookmarks section separator. * nemo-bookmarks-window: Remove help button, fix some breakpoint accounting during dnd. * nemo-view.c: Never have more than one connection to an action's 'activate' signal. * actions: Monitor gsettings condition changes and trigger menu updates when these or any dbus conditions change. * application: Add debug flag to command line options, remove environment variable-based verbose mode for actions. * nemo-action: Cleanup * nemo-blank-desktop-window.c: Fix initial popup menu failure due to a not-fully-initialized action manager. * nemo-action.c: Allow discovery of tokens in any order in an action line. * nemo-action.c: Queue gsettings condition updates (same as dbus updates). This should have been done in 92c58403f12436c65a1c. [ JosephMcc ] * Update nemo-style-fallback-mandatory.css [ devlearner ] * Add Move to Trash confirmation option [ Michael Webster ] * nemo-file-operations.c: Remove unused translatable string. [ Max Sistemich ] * nemo-window-manage-views.c: ignore cache when thumbnails are disabled [ Michael Webster ] * nemo-window-manage-views.c: add a weak pointer to the window slot's bad cache bar when spawned. * preferences: Finalize our settings instances using the eel_call_at_shutdown function. This occurs at a point closer to exit, and allows handlers to disconnect cleanly. [ Lars Mueller ] * Reimplement thumbnailing-per-folder and add inheritance for view type * A couple of bugfixes [ Michael Webster ] * nemo-main-application.c: Make sure any command-line geometry option takes precedence over the saved window geometry. [ Clement Lefebvre ] * nemo-window-slot: Remove trailing spaces * Navigation: Fix go to parent action for Samba [ Michael Webster ] * nemo-window-slot.c: Use GString for manipulating samba uris, it makes what's being done to the uri a bit more explicit. * nemo-window-slot.c: (samba) When navigating up from a host, load network:/// instead of smb:///. * nemo-icon-container.c: Wait to un-freeze canvas updates until the renaming operation has completed. * nemo-file.c: Check for NULL when converting the raw file timestamp to a GDateTime. [ JosephMcc ] * desktop-prefs: Change to match the new cinnamon settings style [ Michael Webster ] * nemo-desktop-overlay.glade: Update to match new settings format. (mostly) [ steve ] * Nemo desktop entry - ensure caret-color matches text color [ okaestne ] * nemo-mime-application-chooser.c: escape file names in Open With tab [ Tcc100 ] * nemo-view.c: Open Terminal in parent if a file is selected [ Clement Lefebvre ] * Start implementing exec support * Optimize nemo_action_get_visibility() [ Michael Webster ] * nemo-action.c: Support multiple selection and action path for exec condition checks. * nemo-action.c: Support tokens in exec condition calls. * sample action: Update to include exec conditions, new correct method to enable debugging. * Revert "nemo-file-operations.c: Remove unused translatable string." * Remove some unused code, optimize some frequently-used settings. * nemo-view.c: Clear a source id at the end of the rename delay callback. * Remove the context menu toggle (the +/- button) for displaying additional menu items. * Add a mechanism for pinning a file to the top of a view. * Improve pin icon. * pinned emblem: try to improve (again) * icon view: Use bold text instead of an emblem for pinned files. * nemo-places-sidebar.c: Workaround incorrectly-sized popup menus when right- clicking on a currently-unselected item. [ Simon Brown ] * move code after early return statements where possible (#2149) [ Clement Lefebvre ] * l10n: Update POT * l10n: Generate additional files [ Clement Masci ] * Option to open uri in tabs at startup [ Clement Lefebvre ] * l10n: Update POT -- Clement Lefebvre Sun, 23 Jun 2019 17:20:47 +0200 nemo (4.0.6) tessa; urgency=medium [ Clement Lefebvre ] * Packaging: Depend on cinnamon-l10n [ Michael Webster ] * nemo-program-choosing.c: add a wrapper for simple .desktop files that invoke pkexec. * nemo-desktop-overlay.c: Don't respond to slider value-changed signals when syncing *from* the view. * nemo-list-view.c: Always display at the default list view zoom level during a search. * nemo-icon-view.c: Don't rely on the default icon zoom level for the grid desktop, hardcode to normal instead. -- Clement Lefebvre Sat, 15 Dec 2018 14:00:23 +0000 nemo (4.0.5) tessa; urgency=medium [ Michael Webster ] * nemo-icon-view.c: Correctly initialize to the default view zoom level when ignore-metadata mode is active. * per-folder thumbnails: Remove toolbar thumbnail button preference, instead base visibility on the show-image-thumbnails preference. -- Clement Lefebvre Tue, 11 Dec 2018 11:26:20 +0000 nemo (4.0.4) tessa; urgency=medium [ Michael Webster ] * nemo-window.c: Fix hidden menu alt-key activation. * nemo-places-sidebar.c: Keep the selected bookmark scrolled into view when a selection is made on a bookmark. * nemo-list-view.c: Ignore triple-clicks and reset the double-click last_click_time when the current double-click succeeds. * nemo-extension-config-widget.c: Allow description to be multi-line instead of reverting to a horizontal scroll bar. * nemo-list-view.c: Don't use fixed-height mode, it does not work well with zoom changes. -- Clement Lefebvre Thu, 06 Dec 2018 13:18:32 +0000 nemo (4.0.3) tessa; urgency=medium [ Michael Webster ] * nemo-action.c: Don't include previously inserted characters/text in subsequent token matching - skip ahead based on the inserted text length, so we avoid potentially parsing escape codes that are part of a file's uri. * places and tree sidebars: Listen for action manager reloads, rebuild popup menus when needed. * places sidebar: Enable actions to work properly even when the item being right-clicked/context-menu'd is not the currently loaded view. * nemo-tree-sidebar.c: Fix memory leak. -- Clement Lefebvre Tue, 27 Nov 2018 17:20:40 +0000 nemo (4.0.2) tessa; urgency=medium [ Michael Webster ] * nemo-file-management-properties.c: Don't drop builder object ref until the window is closed, as callbacks to setting changes refer to it still. [ itzexor ] * desktop/extension config: remove incorrect tooltips [ Michael Webster ] * nemo-desktop-overlay.c: Don't use g_clear_pointer to destroy a widget, this causes build warnings in newer glib. * nemo-properties-window.c: If the icon picker is spawned on a file that has an existing custom icon name or path, display it initially in the picker. * nemo-window-manage-views.c: When clearing thumbnails for a view refresh, drop the NemoIconInfo cache as well. -- Clement Lefebvre Mon, 19 Nov 2018 09:51:30 +0000 nemo (4.0.1) tessa; urgency=medium [ Michael Webster ] * nemo-application.c: Check for "nemo" in the current theme, instead of "nemo-window". Remove unintentional additions to nemo-style- application.css which were made in 21a960712bf4d7688. * nemo-desktop: Simplify view layout preferences, other changes. * desktop overlay: Use normal window hints instead of hidden. Allow resizing, assign an icon (and use XAppGtkWindow so the icon isn't blurry). Make sure all the action names are not marked as translate. Show the monitor plug name and dimensions when displaying view settings. [ Clement Lefebvre ] * l10n: Update POT -- Clement Lefebvre Mon, 12 Nov 2018 15:10:50 +0000 nemo (4.0.0) tessa; urgency=medium [ Michael Webster ] * Version bump for dev. * libnemo-extension: Refactor a bit, replace a lot of boilerplate with macros, simplify doc generation. Documentation needs more work at some point. * nemo-file.c: Do a better job of figuring out the mimetype for empty files. * Add creation time (btime) support. * preferences window: Add toggle for creation date in tooltips. * nemo-file-info.h: Don't use G_DECLARE_INTERFACE - it doesn't allow us to properly use NemoFile for its vtable - it works but throws a ton of build warnings and isn't safe. * misc: Clean up build warnings * icon view: remove some deprecated paths (gtk doesn't return anything useful anymore.) * nemo-icon-canvas-item.c: Insert some space between the icon and label bounds in compact view. * nemo-statusbar.c: Remove custom scroll handler. The gtk one works correctly now. * menus: Respect the gtk-menu-images preference for the primary 'open/ open-with' menu item. * meson.build: Add option to disable omit-frame-pointers from build (useful for perf profiling.) * icon container: Generate tooltips for icon items on-demand, instead of when the view loads. * meson.build: show profiling flag status in config summary. * nemo-icon-info: Optimize icon lookups by GIcon. * search: Respect the current state of the 'show hidden files' setting when calculating results. * nemo-query-editor.c: don't intercept keys when hidden. * nemo-view.c: Decrease minimum update interval. * nemo-view: Optimize *_get_selection(), don't create deep copies when not necessary. * nemo-file: Remove pixbuf cached in NemoFile. * nemo-list-model.c: Improve accounting for dummy expander row, so it more reliably removes the expander for empty folders. * nemo-file.c: Cache some heavily used values from date construction, particularly caching of the GTimeZone object for use in GDateTime construction. * icon view: Remove "tighter layout" option. * nemo-icon-info: don't implement as a gobject. * nemo-mime-actions.c: Don't offer the 'Make executable and run' option by default. * nemo-mime-application-chooser.c: Remove hacks for file-picker button. * nemo-icon-canvas-item: Remove some unused code for embedded text * Icon containers: Improve spacing, increase icon sizes. * nemo-icon-view-container.c: Connect the tooltip signal per container instance, rather than once overall. * nemo-icon-info.h: Tweak text width a bit for the zoom levels. * nemo-icon-container.c: Turn on hover prelight by default. This helps label text overlapping adjacent items (during hover) to have a clean background for better legibility. * emblems: Use cached parent pointers when checking for can't-write emblem condition, instead of looking it up for each file. * nemo-file.c: Load file-roller mimetype cache upon first demand, instead of at startup. This has a noticeable impact on startup time. * nemo-list-model.c: Reduce number of icon info lookups when creating icon surfaces for the model. * preferences: Use the new XApp sidebar switcher, and use an ordinary GtkWindow instead of a GtkDialog to clean up the look. This includes removing the close button as well (we already don't use one in the plugins window.) * preferences: Add the plugin manager as a preferences page. Refactor to remove unnecessary code and allow the prefs window to open on a particular page. * preferences: Use togglebuttons instead of checkbuttons for toolbar button switches, and show the action's icon in the button. * nemo-icon-container: Remove some unused code. * eel-graphic-effects.c: Lessen the effect eel_create_spotlight_pixbuf. [ JosephMcc ] * prefs: Restyle the visible buttons page a bit * prefs: Move the custom icons to xapps [ Michael Webster ] * meson_update_icon_cache.py: Print the icon cache folder when running. * nemo-widget-menu-item.c: Fix allocation warnings. * nemo-extension-config-widget.c: Improve look of extension list. * nemo-places-sidebar.c: Fix a few issues with mounting/ejecting - some incorrect _finish functions and some assumptions of error always being set. * nemo-thumbnails.c: Generate large thumnails to accomodate the larger icon sizes we have now. * nemo-list-view.c: use the subclass selection changed callback instead of NemoView's directly - this makes sure the cached selection list is up-to-date before triggering view/menu updates. [ Germán Franco ] * Add some keywords to the desktop entry (#1939) [ Michael Webster ] * nemo-window-menus.c: Block split pane view in desktop windows. * nemo-action.c: g_file_test here should be checking the *dependency* path, not the path to the action file. [ Clement Lefebvre ] * Preferences: Remove separators [ Michael Webster ] * nemo-thumbnails.c: Use GTask. * nemo-list-view.c: Start using GtkTreeView's fixed height mode. * meson.build: Remove gthread dependency (no longer used). * nemo-list-model.c: Check for unreadable folders and remove the expander when one is discovered during the async count job. * nemo-icon-container.c: Don't recalculate the layout while renaming a file. * nemo-application.c: Add minimally necessary theme elements to the current theme if they appear to be missing. [ Leigh Scott ] * Fix meson warnings (#1920) [ Tom Schuster ] * Prefer XDS Protocol Type over _NETSCAPE_URL to make DnD work in Firefox. [ Lars Mueller ] * Add option for thumbnails per folder [ Soapux ] * Fix some issues with pkgconfig file [ Michael Webster ] * desktop: Add overlay window for configuring individual monitor views as well as global desktop preferences. * nemo-icon-dnd.c: Fix warning when initiating a drag from a normal windowed icon view. * Remove desktop settings action (replaced by 'Customize' fixed entry). * nemo-desktop-window.c: Fix build warning (unused variable). * nemo-desktop: Add smaller and larger icon sizes. The smaller is useful for low res monitors and the larger one will be useful for those using physically large 4k monitors (that do not qualify as hidpi). * nemo-properties-window.c: Use XAppIconChooserDialog to select custom icons. * Update libxapp dependency for icon chooser. [ Clement Lefebvre ] * l10n: Update POT and additional files -- Clement Lefebvre Thu, 01 Nov 2018 13:29:54 +0000 nemo (3.8.5) tara; urgency=medium [ Michael Webster ] * eel-gtk-extensions.c: Fix menu popups when a valid event is not provided. -- Clement Lefebvre Tue, 17 Jul 2018 09:43:41 +0200 nemo (3.8.4) tara; urgency=medium [ Michael Webster ] * nemo-progress-info.c: Emit signals in proper order to prevent an unmatched g_application_hold/release in nemo-progress-ui-handler.c. * eel-gtk-extensions.c: use gtk_menu_popup_at_pointer instead of plain gtk_menu_popup, which is deprecated (and causes a lot of warnings under wayland. Functionality under x11 is unchanged. * nemo-file.c: fix a couple pixbuf leaks, invalidate thumbnails internally when a force refresh is commanded. * various: fix some memory leaks discovered by valgrind. -- Clement Lefebvre Thu, 05 Jul 2018 11:39:39 +0200 nemo (3.8.3) tara; urgency=medium [ Michael Webster ] * trash: Show the correct icon in the pathbar, and fix activation uri for folders located in the trash. * icons: Fix pathbar display of recent and network locations. * Run merge_action_strings (updated icons names) * nemo-query-editor.c: Ignore modifiers (such as numlock) during the favorites menu popup event. * nemo-query-editor.c: use get_default_mod_mask for button state check instead of hardcoded mask. * mounts: Force reload when navigating to a new mount from the sidebar. * thumbnails: Make debug spam a runtime choice, not buildtime. [ NikoKrause ] * Change polkit policy message to "Files" (#1875) -- Clement Lefebvre Fri, 08 Jun 2018 11:54:40 +0100 nemo (3.8.2) tara; urgency=medium [ Michael Webster ] * nemo-places-sidebar.c: Fix potential divide by 0 (found in virtualbox, guest additions CD returns a GFileInfo, but the size fields we use for calculating disk full % come back all 0's.) * nemo-places-sidebar.c: Fix some leaks - GFiles must be unreffed. * nemo-list-view.c: Fix list view column ordering for LMDE (fixes segfault in Gtk 3.22.11) * nemo-icon-container.c: chain the button release event up when ending a rubberband selection. This allows the canvas to 'pick' the icon the release is over, and not cause the background context menu to be used (and all items get deselected) if the very next event is a right-click. [ Soapux ] * Make exempi and libexif dependencies optional (#1849) * Update style of meson build options (#1850) [ Michael Webster ] * Disallow bookmarking of search result views. [ NikoKrause ] * add symbolic for usb and replace bookmark-not-found (#1852) [ Germán Franco ] * Fix some compiler warnings (#1851) -- Clement Lefebvre Sun, 06 May 2018 15:31:26 +0100 nemo (3.8.1) tara; urgency=medium [ Fabio Fantoni ] * update debian/copyright (#1831) [ Eli Schwartz ] * meson: don't install libnemo-private.a [ Clement Lefebvre ] * l10n: Fix typo [ Michael Webster ] * symbolic control icons: Use icon names rather than gicons. The gicon api does not support inherited icon themes. [ NikoKrause ] * Use symbolic icons in nemo-desktop actions * add mount archive symbolic, fix bookmark icon [ Michael Webster ] * mime actions: Fix use of gvfs admin backend. * nemo-view.c: Disallow creation of folders or files in admin:// - it does not properly set file permissions (the same reason copy/paste is not allowed either.) * nemo-file-utilities.c: Improve symbolic icon logic for mounts, drives and volumes. For mounts and volumes, check for too-generic icons and use the backing GDrive's icon instead. * nemo-places-sidebar.c: Handle missing file info more gracefully. Some mounted devices (for example, phones,) don't support GFileInfo. [ NikoKrause ] * fix symbolic for desktop action (#1842) [ Maximiliano Curia ] * Revert license tweak done by db6414a (#1843) [ Salamandar ] * Fix build with old meson (#1844) -- Clement Lefebvre Mon, 30 Apr 2018 15:23:58 +0100 nemo (3.8.0) tara; urgency=medium [ Tobias Göbel ] * also use exec-arg from org.cinnamon.desktop.default-applications.terminal when using "open in terminal" [ Michael Webster ] * nemo-icon-view-grid-container.c: add missing position shift prior snapping a semi-positioned icon. This was causing the free position check to potentially check the wrong grid spot, causing shifting positions. * nemo-icon-dnd.c: when calculating drop position, use the overall canvas item's y center, rather than just the icon's center. This is makes the final aligned position more closely match the drag actor's apparent position. * nemo-desktop-manager: scale the window x and y positions, as well as size when retrieving geometry from cinnamon. * nemo-icon-dnd.c: fix missing semicolon * nemo-icon-view-grid-container.c: Don't allow the vertical adjustment to calculate out to more than half of the grid snap height, this will cause grid checks to evaluate incorrectly. * nemo-icon-container: only mark (pseudo)-desktop icons as transient if keep_align is active. This restores reasonable behavior for non-keep-aligned desktops, and prevents icon movement when refreshing and during startup. [ Jason Hicks ] * Fix left pane in dual pane mode reverting to minimum width * Add g_return_val_if_fail to the beginning of reposition_paned [ Bilal Elmoussaoui ] * Rename Nemo icon from places to nemo (#1687) [ Michael Webster ] * debian/control: remove python3-polib from build deps, no longer needed. * nemo-window.c: listen for a position change on the split-view paned widget when adding a new pane. When GtkPaned's position property hasn't been explicitly set, it auto-adjusts to keep panes equal-sized. * nemo-places-sidebar-.c: Get rid of old hack for the sidebar. It was intended originally to make sure enough vertical height was given to the scrolled container children in their various states (collapsed categories.) It does not appear to be necessary any more, and now causes gtk theme issues. [ Clement Lefebvre ] * Add CI configuration [ Simon Brown ] * nemo-directory-async: correct some signed/unsigned warnings (#1698) * eel-editable-label: remove indentation warning (#1695) * nemo-list-view: remove indentation warnings (#1697) * nemo-list-model: silence indentation warning (#1696) * nemo-bookmarks-window: rename some shadowed variables (#1694) * nemo-file-operations: rename some shadowed variables causing warnings (#1693) * nemo-query-editor: resolve shadow variable and signed/unsigned warnings (#1700) * nemo-script-config-widget: correct some signed/unsigned warnings (#1701) * nemo-action-manager: remove redundant redeclarations (#1702) * nemo-cell-renderer-disk: remove redundant redeclaration (#1703) * nemo-file: fix a couple of signed/unsigned warnings (#1704) [ Naman Kanakiya ] * Add options to preview thumbnails for up to 16GB and 32GB (#1707) [ Simon Brown ] * nemo-icon-info: correct various compiler warnings (#1716) * nemo-navigation-action: stop compile warnings from switch statements (#1715) * nemo-window-pane: correct some indentation causing a warning message (#1709) * remove some redundant redeclarations causing warnings (#1708) * nemo-view: remove some compile warnings (#1710) * correct some signed/unsigned compiler warnings (#1711) * nemo-icon-dnd: add default cases to remove compile warnings (#1712) * nemo-file-management-properties: rename shadow variable (#1717) * change some old style function definitions to avoid warnings (#1718) * nemo-bookmark: remove compile warnings (#1719) [ Michael Webster ] * nemo-places-sidebar.c, nemo-action.c: Replace g_drive_is_media_removable with g_drive_is_removable. [ Simon Brown ] * remove some signed/unsigned compiler warnings (#1720) * nemo-desktop-metadata correct wrong type of variable passed as parameter (#1721) * nemo-search-engine-simple: resolve a couple of compile warnings (#1722) * nemo-job-queue: resolve some compiler warnings (#1741) * nemo-undo-signal-handlers: resolve a couple of compiler errors (#1740) * eel-gtk-extensions: resolve signed/unsigned compile warnings (#1739) * nemo-file-utilities: remove a couple of const compile warnings (#1736) * nemo-icon-canvas-item: treat switch compiler warnings (#1735) * nemo-tree-view-drag-dest: Fix some compile warnings (#1734) * nemo-pathbar: resolve various compile warnings (#1733) * nemo-query-editor: resolve some const compile warnings (#1732) * nemo-list-model.c: resolve various compiler warnings (#1731) * nemo-list-view: resolve some compiler warnings (#1729) * nemo-file: resolve a number of compiler warnings (#1738) * nemo-connect-server-dialog resolve various compiler warnings (#1724) * nemo-window-menus resolve a signed/unsigned warning (#1725) * nemo-desktop-icon-grip-view Treat switch and const warnings (#1726) * nemo-extension-config-widget: resolve some signed/unsigned warnings (#1727) * nemo-icon-view: resolve various compiler warnings (#1728) * nemo-icon-container -remove some switch warnings (#1723) * resolve some const compiler warnings (#1742) * nemo-view: resolve some const warning messages (#1743) * remove a couple of unused variables causing warnings (#1744) * nemo-properties-window: resolve a couple of compile warnings (#1745) * nemo-vfs-file: add default to switch to avoid warning (#1746) [ Michael Webster ] * nemo-window-slot.c: remove padding from extra_location_widgets box. [ Simon Brown ] * nemo-desktop-icon-view: resolve some const warnings (#1757) * nemo-file-changes-queue: resolve a switch warning (#1756) * nemo-desktop-link-monitor: resolve a switch warning (#1753) * nemo-places-sidebar: resolve various compile warnings (#1754) * nemo-mime-application-chooser: resolve misleading indentation warning (#1749) * nemo-file-operations: resolve some switch warnings (#1747) * nemo-tree-sidebar: correct an int to an unsigned (#1752) * nemo-monitor: resolve some switch compiler warnings (#1751) * nemo-icon-view-container: resolve a couple of compile warnings (#1758) * nemo-icon-view-grid-container: resolve a couple of compiler warnings (#1759) * add some default switch statements to avoid warnings (#1760) * resolve some signed/unsigned warnings (#1761) [ JosephMcc ] * [gtk3.22] Pathbar style (#1765) [ Germán Franco ] * Use symbolic icons (#1764) [ Simon Brown ] * nemo-window-slow-dnd: resolve a couple of const warnings (#1763) * nemo-interesting-folder: add additional case to switch to avoid warning (#1762) * nemo-window: check for an active slot when updating cursor (#1767) * nemo-properties-window: use utility functions if available (#1768) * nemo-properties-window: use gdk_pixbuf_scale_simple () (#1766) * eel-vfs-extensions: update filename extensions (#1769) [ JosephMcc ] * nemo-places-sidebar: Cleanup spacing (#1664) [ Félix Piédallu ] * Add Meson Build System support * Modify Autotools build for icons * New debian/rules meson-enabled * Fix sources: use other version macro, fix fn call [ Michael Webster ] * meson: some cleanup, fixes, organizing. * actions: fully support all system data paths, but respect the install prefix for looking up fixed resources. * Fix lmde3 build, don't build empty view by default. [ Leigh Scott ] * Make the libExecPath usable * Fix libexec path * Fix path * Remove hardcoded path [ Michael Webster ] * Fix libdir location to match autotools build (usr/lib), but make sure typelib still goes where it belongs. [ Clement Lefebvre ] * Revert "also use exec-arg from org.cinnamon.desktop.default-applications.terminal when using "open in terminal"" * Fix thumbmails generation [ Simon Brown ] * nemo-file-operations: revert a change that might be backfiring (#1774) [ Michael Webster ] * nemo-view.c: Don't try to update undo menu items in a non-active slot. [ Mochamad Arifin ] * fix open as root error [ Michael Webster ] * debian: Move build dir to debian/build * nemo-list-view.c: Don't clear the editable on focus-out, this will get done properly when we chain up. We need to propagate the focus-out-event signal, which the callback wasn't doing. * Don't build/install gtkdocs by default * oops - gtk_doc option should only affect the reference folder.. * nemo-icon-dnd.c: Fix segfault when dragging from nemo to nemo-desktop * search: Use newer GtkEntry method for focusing search box, remove custom code. * nemo-window-menus.c: Ignore 'go home' shortcut on the desktop. * nemo-view.c: Allow view display of files to commence even while loading is ongoing, instead of waiting until files are entirely finished loading. * eel-editable-label.c: Don't queue a redraw on unrealized labels. * nemo-icon-container.c: Don't perform relayouts on an unrealized container. * nemo-list-view.c: Remove and re-add columns rather than moving them. This prevents negative allocation warnings during the move calls. * eel-canvas.c: Don't update the scroll region when clearing the canvas to destroy it. * query editor: Simplify, remove additional filters, just a simple filename search. * nemo-window.c: Go back to explicitly setting half the width for the split-pane's position property, rather than counting on it to fall that way naturally. The natural position can be affected by sizing demands of the panes' children. * search: Add a more convenient way for saving searches. * nemo-file.c: Avoid recursion when updating symbolic links that point to each other. See inline notes. * nemo-file.c: Small fix and optimization for 40dc6ae1ed9d24b0c - return the full link_file list as before if the target file is not a link, and only check if the file is a link one time. * libnemo-extension: Remove custom enum code for NemoOperationResult - it's not necessary in modern builds due to introspection. * info provider extensions: Improvements to info provider extension operations. * nemo-query-editor.c: Add mnemonic to popup search keys for quick selection. * nemo-query-editor.c: Inhibit faves popup if the list is empty, filter out typical keyboard modifiers during clicks on the favorite icon. * nemo-desktop-application.c: Allow nemo-desktop to provide coverage for the org.freedesktop.FileManager1 dbus interface. * nemo-icon-view.c: Be more selective when updating the scroll region. * refresh/reload: When reacting to a user-initiated view refresh, regenerate any thumbnails as well. [ JosephMcc ] * nemo-properties-window: Stop using stock buttons (#1800) * prefs-window: Don't use stock buttons (#1801) * menus: Convert most icons to symbolic versions (#1798) [ Michael Webster ] * nemo-list-view.c: Re-apply right-click column handler when reloading column settings (see inline notes, this only affects certain Gtk versions.) * nemo-view.c: Add label to directory menu Cut and Copy (needed now that we are no longer using GTK_STOCK_* * nemo-view.c: make mnemonics for Cut, Copy, Paste match Gtk's. [ Mike Tzou ] * Fix function argument order (#1791) [ Michael Webster ] * Check for realized instead of mapped/visible to prevent needless resize calculations (and associated warnings.) * nemo-file-management-properties: Fix 2px border width surrounding content (see comments.) * Use symbolic icons for the places sidebar * places-sidebar.c: Use symbolic for eject button * More symbolic conversion * nemo-trash-monitor.c: Add a new path for the symbolic icon. Our file views need a non-symbolic icon. * More symbolic fixes, cleanup in pathbar. * Missed a few trash icons... * extensions: Show symbolic icons properly, hide the icon if it's not a symbolic name. * Add rubber-band selection to the list view. * nemo-places-sidebar.c: remove vertical padding for headers. This is unnecessary, and looks bad when a theme has increased spacing between all rows. * go menu, bookmarks menu: respect the menu-images setting. * nemo-trash-monitor.c: Fix copy-paste typo. * nemo-icon-info.c: Stop using gtk_icon_theme_has_icon() - it returns false negative when attempting to check for icons that have been added using gtk_icon_theme_append_search_path(). This entire branch of functionality is considered 'legacy' and not recommended, but for dropbox emblems, where more than one package may attempt to provide them, putting them in the (recommended) hicolor icon folder won't work. [ NikoKrause ] * Use media-mount icon for right-click action (#1813) * Eject/unmount icon & new folder icon (#1811) [ Fabio Fantoni ] * debian: wrap-and-sort -bst * update debian/copyright * improve debian/control * Bump debhelper build-dep and compat to 10 * debian: try to restore multiarch with meson without debhelper 11 * add debian/not-installed * Force UTF8 to workaround build error * debian: add missed part of multiarch restore * debian: add a nemo lintian override * debian/rules: list missed files in dh_install * circleci: remove mint18 job * debian/control: remove very old breaks [ Clement Lefebvre ] * l10n: Update POT file and generate files -- Clement Lefebvre Fri, 20 Apr 2018 12:17:46 +0100 nemo (3.6.5) sylvia; urgency=medium [ Michael Webster ] * nemo-desktop-manager.c: Add null checks for GErrors - it seems as though g_dbus calls are not guaranteed to fill the error slot (which seems like a Gio bug to me, but there's no reason to crash here regardless because of a null error.) * nemo-window - Restore inadvertantly removed menu actions for view type selection (and their corresponding shortcuts,) using methods and practices more consistent with currently maintained code. * nemo-window-menus.c: Add a couple guards for the previous commit's view actions for when the window is a NemoDesktopWindow -- Clement Lefebvre Mon, 18 Dec 2017 12:37:52 +0000 nemo (3.6.4) sylvia; urgency=medium [ Michael Webster ] * nemo-window: Restore initial syncing of view buttons. This was inadvertantly removed in d23762640b48d8 while getting rid of some actual unused code related to an old way view types used to be selected. -- Clement Lefebvre Mon, 20 Nov 2017 10:10:17 +0000 nemo (3.6.3) sylvia; urgency=medium [ Michael Webster ] * nemo-desktop-manager.c: Account for scale factor when using cinnamon- supplied monitor info. Cinnamon runs at a scale factor of 1 always, and things are scaled internally. * dnd: Make sure to clear any source_fs pointers after dnd operations. -- Clement Lefebvre Fri, 27 Oct 2017 11:03:15 +0100 nemo (3.6.2) sylvia; urgency=medium [ Leigh Scott ] * add xapps version to configure.ac (#1626) -- Clement Lefebvre Tue, 24 Oct 2017 12:25:45 +0100 nemo (3.6.1) sylvia; urgency=medium [ Ingo Lafrenz ] * send by mail nemo action (#1625) [ Clement Lefebvre ] * Fix permissions on files/usr/share/nemo/actions/send-by-mail.py -- Clement Lefebvre Tue, 24 Oct 2017 10:58:34 +0100 nemo (3.6.0) sylvia; urgency=medium [ brownsr ] * eel_g_list_str_copy: replace contents with g_list_copy_deep May improve performance somewhat for very high volume file copies though I have no way to test with the volumes reported here https://bugs.launchpad.net/linuxmint/+bug/1663186 [ Michael Webster ] * nemo-main-application.c: try to start as a service first, then a client. This allows nemo to be started via dbus (which requires it be run with the G_APPLICATION_IS_SERVICE flag) as well as being able to connect to an already-running instance as we can now. * nemo-main-application.c: Re-add "no-desktop" command line option. We don't use it anymore, but some programs apparently hardcode nemo with this flag rather than use xdg-open or mimetype activation. This allows them to continue working as before. * nemo-view.c: Fix "follow link to original file" action when the link is on the desktop. In these cases, we need to launch a folder handler and pass it the full file name (which for most file managers should open the folder and select the file.) * nemo-query-editor.c: Use a copy of the query text to check if the query is empty (or all spaces.) The function g_strstrip modifies the string in-place, and passing the modified query text causes issues when typing multiple words (separated by spaces) in the query. [ leigh123linux ] * Configure: disable tracker for default [ Michael Webster ] * actions: Escape single and double quotes that are part of a file path. Add "Terminal" key in the nemo_action file, to execute the Exec line in a terminal window. * actions: Update sample action for Terminal keyword, update nemo_action sourceview files. * actions: Only use nemo_launch_application_from_command_array() when Terminal=true. This ensures compatibility with existing actions, which will continue to use g_spawn_async(). * nemo-desktop-icon-grid-view.c: Store layout timestamps any time the layout is changed by a user action. * Desktop: Remove metadata for pseudo-files on the desktop such as Computer and Home when they're removed via preferences. This simulates their deletion with respect to how metadata timestamps are tracked and validated. * nemo-icon-view-grid-container.c: mark the sort as dirty any time a file is added or removed (this determines whether and when the sort direction indicator is shown in the context menu when auto-arrange is not active. * nemo-icon-info.h: Use standard icon sizes for the desktop. [ brownsr ] * nemo-action.c: fixup a few compiler warnings * nemo-icon-private.h: avoid memory padding save a little memory use by rearranging the fields to avoid memory padding in structures * eel-editable-label.h: Avoid memory padding move fields in a structure to avoid memory padding made padding explicit to avoid warning messages if the padding compiler warnings are on [ Michael Webster ] * nemo-file-undo-operations.c: Use GQueue instead of GList for our undo file pair lists. * nemo-file-operations.c: use g_remove for native (path-reachable) files. Allowing the normal g_file_delete involves gvfs whether the file is native or not. * nemo.desktop: Remove DBusActivatable line - we don't actually support it yet, it was an unnecessary change in ad5fcfc747466715d. This ends up just causing issues with getting nemo to launch in more up-to-date distributions. * nemo-icon-container.c: Always treat desktop pseudo-files as semi-placed icons - that is, they can have their positions stored, then restored later, but their position can be adjusted upon placement if their previously stored position is now occupied. * nemo-progress-ui-handler.c: Use XAppGtkWindow for the progress window, so we can pass progress info to Cinnamon. [ Jeremy Bicha ] * Add translatable files to POTFILES.in (#1584) [ Michael Webster ] * nemo-desktop-manager: Refactor and expand to integrate better with cinnamon. * plugin manager: allow launching of an extension's config program from the plugin window, rather than having it in the main menu. * desktop: Handle blank desktop windows properly during monitor change events. * nemo-desktop-manager.c: Don't just try to resize existing desktops if the number of monitors has changed. In this case, do a full re-layout. * nemo-progress-ui-handler.c: Don't update the status icon if it's not being shown. * nemo-file-operations.c: Reduce progress ui update frequency during file operations. [ Leigh Scott ] * update man page for nemo (#1600) [ Alexei Sorokin ] * Fix some warnings in libnemo-private (#1482) [ Michael Webster ] * nemo-desktop-manager.c: Don't run on_run_state_changed() during the init phase when it's a fallback session as it can cause a nasty recursion problem resulting in a crash. * nemo-directory-async.c: hold the directory alive for the duration of an extension provider job, to ensure clean termination to the job when async info providers are used. * dbus services: normalize file names. * Remove some dead code. * desktop: Don't show the "Show hidden files" menu item. We never show hidden files on the desktop, so having this is misleading. [ alexnch ] * Add .rar and .7z to archive mounting action (#1621) [ John Callerame ] * When activating files on the desktop (only), deselect them after activating them (#1608) [ Ján JanÄár ] * nemo-toolbar.c: Add option to hide elevated privileges warning. (#1610) [ Clement Lefebvre ] * Rename show-superuser-toolbar into show-root-warning [ Björn Esser ] * file: Let renames work on Google Drive Renaming an item on Google Drive does not change the actual GVfs path because the path is made up of document-ids, which do not change. A rename operation only affects the title of the entry. In GIO terms, only the standard::display-name changes, but the standard::name remains the same. * file, file-undo-operations: Let renames on Google Drive be undone We really should be using standard::display-name when renaming files - g_file_get_basename is simply not the right thing to use. Moreover, in case of Google Drive, the URI might not change with the display name and we can not get the old display name from the old GFile. * debian: Set version for min. needed libglib2 [ Fabio Fantoni ] * update debian/copyright * debian: remove unneeded postrm [ Clement Lefebvre ] * l10n: Generate additional files * l10n: Update POT file -- Clement Lefebvre Tue, 24 Oct 2017 10:44:41 +0100 nemo (3.4.6) sonya; urgency=medium [ Michael Webster ] * nemo-icon-view-grid-container.c: Reset lazy flag when the icon position is stored in auto-layout mode. * nemo-file.c: Don't check for valid thumbnails if thumbnailing is disabled. * nemo-action.c: Use non-blocking checks for a directory. * css: Treat NemoBlankDesktopWindow the same as NemoDesktopWindow with regards to themes, add a couple fixes to our app css to prevent background issues with certain themes (Blackmate, Ambiance) * Add github issue template * move-to/copy-to dialogs - allow remote locations in the sidebar. -- Clement Lefebvre Thu, 06 Jul 2017 11:21:28 +0200 nemo (3.4.5) sonya; urgency=medium [ Michael Webster ] * search (ctrl-f): Don't search for an empty string. If the user wants to search for every file, they can use the wildcard (*). * nemo-application: Only check/create the config dir at startup for nemo, and have nemo-desktop check both config and Desktop directories. * nemo-window-menus.c: Fix control-n (new window) action callback when used from the desktop process - it should launch the preferred file manager instead of attempting to spawn a window itself. * configure.ac: suppress deprecated warnings * Add --enable-silent-rules to debian/rules, quiet C90 warnings. [ Clement Lefebvre ] * l10n: Generate desktop files -- Clement Lefebvre Mon, 26 Jun 2017 12:14:28 +0200 nemo (3.4.4) sonya; urgency=medium [ Michael Webster ] * nemo-icon-view-grid-container.c: skip default placement if we're in auto-layout mode. We get false lazy flags on new icons since the original desktop did not use auto-layout. We need to handle this because we both store layout timestamps and provide auto-layout. * nemo-window-slot.c: Initialize cache_bar to NULL, this is checked for in nemo-window-manage-views (nemo_window_slot_check_bad_cache_bar) -- Clement Lefebvre Thu, 22 Jun 2017 15:00:12 +0200 nemo (3.4.3) sonya; urgency=medium [ leigh123linux ] * Remove decoration from desktop window (shows in weston) [ Michael Webster ] * Desktop: Relax control of positioning for placed icons. At startup, they are loaded and set to their stored position, but not force-aligned, allowing the layout to ignore fluctuations in the work area during system startup. Fix some logic around 'orphan' icons as well to prevent issues with icons not being shown due to being falsely classified as orphans. * icon container: Be more specific about when to flag icons coming from a different monitor due to a desktop configuration change. (see previous commit) * metadata: Add back cached position values in NemoFile. Be sure to clear the timestamp metadata on files being moved/copied to or from the desktop. This ensures the lazy flag operates correctly. With the desktop becoming a separate process, transfers that include position info need to be handled slightly differently, as the old way of just setting metadata and reacting to it from a new container won't work - the file gets debuted in the other process sooner than (or not reliably after, at least) the metadata is written, resulting in inconsistent positioning. * Add gvfs-info action for inspecting file metadata (for purposes of debugging) - right-click a file and it will send gvfs-info output on that file to stdout. * nemo-icon-view-grid-container.c: improve updates after thumbnail generation. -- Clement Lefebvre Tue, 20 Jun 2017 15:43:53 +0200 nemo (3.4.2) sonya; urgency=medium [ Michael Webster ] * nemo-icon-container.c: don't force a native window for the desktop - fixes prelight hover sticking on the desktop when leaving an icon to pass into another window. * nemo-icon-view-grid-container: don't show bracketed empty spots, it's tacky. * nemo-main.c: remove backend requirement (only needed for the desktop) * icon view/desktop: Fix hidpi scaling on the desktop. This also fixes compact view mode in hidpi, which was semi-broken since hidpi was implemented, and very broken since the desktop grid was added. * nemo-icon-dnd.c: depopulate the dnd grid of the selected icons so insertion marks aren't drawn in the icon's source position. * nemo-window-manager-views.c: simple close the window if the current view has no backward history, instead of jumping home or to the parent folder. The most common time for this to occur is a folder opened from the desktop - if you delete that folder, the window showing it then shows the desktop in a folder, which doesn't make much sense. * nemo-window-manage-views.c: invalidate file info before reloading the view, not after. This fixes mount permissions being incorrect. * dnd: Restore capability of 'moving' files from and to the desktop via drag and drop. * Fetch file-roller mimetype info from a GDesktopAppInfo at startup, instead of a static (and woefully out of date) list. * nemo-file.c: followup to previous commit, retain the old mimetype list for fileroller in the event that, for some reason, there is no .desktop file installed for file-roller. Also added application/x-xz-compressed-tar to the static list. * nemo-file.c: add EFAULT as a valid exception to the access_ok function. This can throw when the file has just been moved or is in the midst of being moved and the internal async updates have not completed yet (usually during a fairly large transfer.) As a result, the icon cache problem bar appears needlessly. * desktop: size thumbnails more appropriately - scale them to our icon size in height only, and allow the width to increase as much as our max text width while maintaining the image aspect ratio. * desktop thumbnails: Pad the thumbnail height when it ends up smaller than the desired height due to aspect ratio and width restrictions. This ensures a nice alignment when keep-aligned is active. * nemo-icon-view-grid-container.c: highlight the current dnd rectangle in debug mode. * desktop grid: use the layout size for determining constraint to the canvas bounds instead of max size - this prevents files with very long names from being pushed out of the grid alignment. * misc: Clean up minor leaks, other issues. * desktop grid: include additional text (Icon Captions) in calculations for the ellipsis limit, and update the desktop when these change - instead of forcing the user to reload or restart to see changes. * cleanup some warnings from recent commits. * nemo-style-application: Remove drop shadow from the selection and pre-light states of desktop icons. The shadows are drawn outside the calculated bounds of these items, and are problematic to account for without doing frequent full screen repaints (something I want to avoid) * DnD: Draw the highlight box around the entire text when an item is prelit and highlighted as a drop target. The highlight box was only drawing as if to surround only the normal, ellipsized text, rather than the full, unellipsized height. * Set a default font for the desktop - this is overridden by distros in most cases, but having something is better than leaving it blank - you could set it to "Unicorn poo 15" and it would still show the labels, even though you lack that actual font. * Add a default to our theme - using the default font was always supposed to be a fallback option, however the check in various places for whether the gsettings key is empty or not is incorrect - g_settings_get_string will always return a string, never NULL, so we need to check if the string is not empty instead. (I left the null check also as a safety - it's possible during startup that this may be null prior to the setting being first fetched. * desktop: Fix missing icons when 'show orphans' is disabled (we were incorrectly interpreting a monitor number of -1 (which means, no previous location) and a missing monitor. * Fix visual sort function - sort function was incorrect for the new grid, and the new order was never set after a sort when running the alignment routine. [ JosephMcc ] * nemo-places-sidebar: Use folder-recents for the recent icon (#1502) [ Michael Webster ] * grid view: Don't re-enable auto-arrange when changing zoom levels. * desktop dnd - Use more sensible behavior when keep-aligned is active. * Fix dnd for netscape url drops. * nemo-file-operations: limit metadata setting to desktop location only (In a previous commit it was re-enabled, but has the potential to cause traffic jams in dbus during a long copy/move operation. * nemo-mime-actions.c: Don't fail for non-local links (like dragged website links) - the check here is for the foreign url, not the local desktop file (link), so it will never succeed, and is not necessary. * DnD: Fix some positioning issues with auto-align local moves, and non-local icon moves (like nemo->nemo-desktop transfers) * nemo-icon-view-grid-container.c: keep the icon list synced with the visual order of the desktop. * dnd: split out some container-specific code that had bled over a bit * Fix application css - font was breaking Gtk 3.22 and is not needed. Change prelight to hover to fix deprecation warnings. [ DaveBlack ] * Modify desktop icon order (#1501) [ Michael Webster ] * nemo-file-operations.c: store the desktop location during a duplicate job, to fix DnD duplicate positioning on the desktop. -- Clement Lefebvre Tue, 23 May 2017 15:54:04 +0100 nemo (3.4.1) sonya; urgency=medium * Revert "split executables into separate packages." -- Clement Lefebvre Fri, 05 May 2017 17:24:21 +0100 nemo (3.4.0) sonya; urgency=medium [ Daniel Schürmann ] * Nemo-Icon-View: Fix missing cast warning * restore prototype lost in c5a513468ee8c3497f0673e3ca019ccd3f409f8b * Add missing include [ Timothy Sharitt ] * Fix quirks with tabs and search widgets [ leigh123linux ] * Don't reload while a reload is ongoing [ Stefan-Olt ] * wildcard search for search-engine-simple [ Daniel Schürmann ] * Remove double definition [ JosephMcc ] * Fix a crash when attempting to delete an empty selection on the desktop [ dg1727 ] * Updated pkexec support [ JosephMcc ] * Fix search never resolving [ Ulrik Sverdrup ] * nemo-dbus-manager.c: Add MoveURIs method [ William Jon McCann ] * Improve date display * Use 24 hour date format when requested [ Frédéric Péters ] * Translate date formats [ Carlos Soriano ] * nautilus-file: implement smarter dates * nautilus-list-view: add a modified column with time * nautilus-file: Clarify translators comments * nautilus-file: fix memory leak * nautilus-file: fix code style * nautilus-file: use const for the date format [ Khaled Hosny ] * Mark time format with xgettext:no-c-format [ Carlos Soriano ] * file: fix wrong date calculation * file: fix previous commit * file: use _() directly for date formatting [ Ernestas Kulik ] * file: fix date string day difference calculation [ Daniel Schürmann ] * Use long day and month names if space allows [ leigh123linux ] * Make libselinux dependency controllable by configure switch * raise tracker version * autogen.sh: don't run aclocal [ Daniel Schürmann ] * location-bar: use a GFile in location-changed signal [ Clement Lefebvre ] * l10n: Generate desktop file via generate_aditional_file * Add Cinnamon panel shortcuts (trash, computer, etc.) to the launcher [ leigh123linux ] * Disable selinux for Debian rules [ Daniel Schürmann ] * Fix compiler warnings in eel folder * nemo-desktop-window: cleanup delete-event handling * nemo-blank-desktop-window: cleanup delete-event handling * window: make NemoWindow a GtkApplicationWindow [ itzexor ] * nemo-file-operations.c: use only template filename for new files [ Denis Golubev ] * nemo-navigation-action.c: Add new_tab_action [ Michael Webster ] * Fix merge fail in previous commit. * configure.ac: Remove CFLAGS line - the optimization is dangerous, and the fatal warnings for unused stuff was just annoying when trying to refactor - warnings are enough. * Use GTimer for tracking startup speed, and also use one to track view loads. * nemo-view.c: Add idle timer for benchmarking. * Split off desktop handling into new process * Update .gitignore * Split off old icon container into the existing subclass NemoIconViewContainer and set up a new subclass - NemoIconViewGridContainer to match with a new NemoDesktopIconGridView class. The old style is accessible via the org.nemo.desktop 'use-desktop-grid' setting. * fix autostart file name so cinnamon session doesn't fail. * split executables into separate packages. * Remove a bunch of comments, fix auto-layout not sticking. * nemo-icon-container: Move debug drawing to the grid container subclass. Trigger it using NEMO_DEBUG=Desktop when running nemo-desktop. * Implement horizontal layout. * General fixes, icons, metadata issues between monitors. Provide per-monitor metadata for desktop containers. * Improve DND during keep-aligned, allow for insertion of items. Implement zoom scaling and allow adjustment. * Improve highlighting of hovered items * Fix desktop folder launching - xdg-open was never intended to be the final answer. * Fix ellipses change listening - the is_desktop flag was being set too late in the view construction process to connect to the correct gsettings key. * Fix regression causing metadata to be inconsistent in nemo client window when navigating to and away from the Desktop folder * Add some gsettings listeners for grid stuff * Fix dnd between monitors - clamp grid values, and ensure we have a grid on the target monitor. * Fix zoom switching, dnd placement, snapping * nemo-desktop-utils.c: Improve how we store the monitor number for a desktop window. * Use black instead of theme color for pre-light label highlighting * nemo-icon-canvas-item.c: extend redraw area slightly for canvas items. This ensures any small shadow we have is cleaned up after an item is de-selected. * nemo-desktop-icon-grid-view.c: Don't trigger a real update while updating menus. * Disable zoom for the desktop window (allow it only via context menu) * nemo-desktop-application: cleanup some commented lines [ leigh123linux ] * fix desktop file error (#1477) [ Denis Golubev ] * nemo-navigation-action.c: Extend, Fix Middle-Click (#1478) [ Clement Lefebvre ] * l10n: Update POT file * l10n: Generate additional files -- Clement Lefebvre Thu, 04 May 2017 13:39:55 +0100 nemo (3.2.2) serena; urgency=medium * l10n: Generate additional files -- Clement Lefebvre Mon, 12 Dec 2016 14:25:13 +0000 nemo (3.2.1) serena; urgency=medium [ Tomasz Sterna ] * Add missing "Desktop" DEBUG flag [ leigh123linux ] * Add space to Name[en_GB] * file-operations: don't recurse for trash operations [ Clement Lefebvre ] * l10n: Update POT file [ leigh123linux ] * Force X11 backend [ Michael Webster ] * remove screen metadata (we only ever have one screen) * nemo-file-operations.c: Don't update position metadata on most file operations - it's costly, and can cause lockups. -- Clement Lefebvre Sat, 10 Dec 2016 12:19:48 +0000 nemo (3.2.0) serena; urgency=medium [ leigh123linux ] * fix GCC pointer signedness warnings [ raveit65 ] * add .view style class on icon view scrolled window [ itzexor ] * window: remove custom get_preferred_width/height implementation We already take care of the default size when we create the window, and these only break assumptions of the default GtkWindow's handlers. * pathbar: avoid gtk+ warnings * pathbar: remove hardcoded width for sliders [ Maximiliano Curia ] * Close open_as_root child on child exit [ Michael Webster ] * nemo-context-menu-menu-item.c: use correct grammar in the context menu toggle. [ leigh123linux ] * Fix GTK 3.21.3 desktop redraw issue (#1231) [ Maximiliano Curia ] * Migrate away from gnome-common deprecated vars and macros [ brownsr ] * replace deprecated gtk_icon_info_free with g_object_unref * remove deprecated and no longer necessary g_type_init [ itzexor ] * file-operations: reduce the time for reliable transfer rate * remove "Show text in icon" preference [ Michael Webster ] * nemo-view.c: unescape uris being passed to file-roller during drag-and-drop (replaces %20 with spaces). [ Chris Allan ] * Expand grid width to canvas * Minimum of one column [ xenopeek ] * Update nemo-file.c [ leigh123linux ] * trash-monitor: change trash monitoring process [ lukefromdc ] * Fix --geometry option when Nemo is already running [ Maximiliano Curia ] * Keep warnings as warnings when building the packages [ Clement Lefebvre ] * Clean up previous PR [ JosephMcc ] * nemo-file-management-properties: Fix an accidental removal [ leigh123linux ] * Add missing build dep [ Clement Lefebvre ] * Fixed build [ Maximiliano Curia ] * Make AX_ macros optional [ itzexor ] * nemo-window.c: save sidebar width 100ms after last change * nemo-application.c: fix maximized window state preservation [ Daniel Schürmann ] * Remove conditional ellipsis code for GTK < 3.12.0 builds. [ darealshinji ] * Add link to Launchpad translations to README [ claudetete ] * bind double left click on blank to go to parent folder * add option to manage double cick in blank area (off by default) because it changes previous behavior [ Clement Lefebvre ] * Rephrased feature introduced in previous commit and regenerated pot file [ Michael Webster ] * nemo-file.c: Only append .desktop to desktop files when they actually need it. Trusted desktop files (ones that typically get made and placed on the desktop) don't show their extension, so when you try to rename them, the new name needs .desktop appended to it. * nemo-file-management-properties.glade: improve the description of the click-to-rename feature. * nemo-thumbnails.c: Don't set a stack size - see: * nemo-application.c: Look for already-existing desktop windows before attempting to manage the desktop. * desktop: Don't rebuild the desktop any time _NET_WORKAREA changes - this can happen fairly frequently in some situations, causing crashes due to the asynchronous nature of nemo's directory loading back-end. * eel-gnome-extensions.c: Use preferred terminal emulator when using "Run in terminal" to execute something. This more or less reverts a75c26d50bba3fec1dc242b9efc03f37a06e7093 but simplifies it somewhat, adapting the function that is used in GDesktopAppInfo and adding a check for our user setting. * nemo-desktop-manager.c: run layout_changed when the widget scale factor changes. This (hopefully) handles regressions with hidpi support due to https://github.com/linuxmint/nemo/commit/c5a513468ee8c3497f0673e3ca019ccd3f409f8b. [ leigh123linux ] * file-undo-operations: change trashed files matching condition [ Michael Webster ] * icon view: Use the correct container size for applying margins to the icon container. Also, make sure icon data is fully loaded before positioning items - desktop pseudo-items don't necessarily have the correct bounding boxes defined by the time layout occurs. Load this data just before trying to position the icon, rather than just after. * nemo-desktop-utils: Adjustments for Gtk 3.22 changes in monitor management. gdk_screen_get_monitor_workarea() no longer returns a valid workarea, it simply returns the geometry - see commit: * nemo-desktop-manager.c: reload the desktop in an idle callback * nemo-application.c: Add a whitelist for ignoring existing desktop handlers by WM_CLASS match. By default 'conky' is in the list [ Clement Lefebvre ] * Generate additional files -- Clement Lefebvre Mon, 07 Nov 2016 13:19:34 +0000 nemo (3.0.6) sarah; urgency=medium [ Clement Lefebvre ] * Generate action files manually (as opposed to during the build) [ Michael Webster ] * nemo-desktop-utils.c: return 0 for monitor index if a widget isn't realized (this can happen during configuration changes and during session startup). * nemo-desktop-icon-view.c: disconnect from the same gsettings instance we connected to. * nemo-desktop-manager, nemo-application: Fix some cleanup issues - disconnect from the correct objects when disposing of the desktop manager, and destroy the desktop manager earlier in nemo's destruction so there are no issues freeing the DesktopInfos. [ leigh123linux ] * notebook: removed unused ifdef code [ Michael Webster ] * nemo-list-view.c: detach the column header menu from metadata when setting it up. Use the actual view's layout instead. When reacting to visible columns being changed, simplify things by iterating through the treeview column to build a new metadata list. * nemo-list-view.c: Don't show trash-specific columns in the header menu. * list view: Make changes to the search results view persistent. gvfs can't save metadata for the search 'folder' so we store it ourselves. * eel-canvas.c: Fix touchscreen selection in icon views. -- Clement Lefebvre Thu, 23 Jun 2016 13:32:32 +0100 nemo (3.0.5) sarah; urgency=medium [ leigh123linux ] * use g_hash_table_remove_all and get rid of some callbacks [ JosephMcc ] * Partially revert c082595 by limiting it to only affecting desktop items -- Clement Lefebvre Tue, 31 May 2016 13:20:18 +0100 nemo (3.0.4) sarah; urgency=medium [ raveit65 ] * add standard settings for EelEditableLabel [ Clement Lefebvre ] * Build-depend on cinnamon-l10n -- Clement Lefebvre Tue, 31 May 2016 11:31:11 +0100 nemo (3.0.3) sarah; urgency=medium [ Clement Lefebvre ] * Updated pot file [ Michael Webster ] * nemo-places-sidebar.c: When gtk overlay scrolling is in effect, add some padding right of the sidebar eject icons, otherwise they are covered by the scrollbar when it pops up. -- Clement Lefebvre Mon, 23 May 2016 12:52:58 +0100 nemo (3.0.2) sarah; urgency=medium [ Clement Lefebvre ] * Fixed build [ Michael Webster ] * debian/control: depend on python3-gi * fix action i18n scripts to write utf-8 [ itzexor ] * nemo-icon-view: include nemo-application.h needed in nemo_icon_view_add_file for: nemo_application_set_cache_flag nemo_application_get_singleton * nemo-pathbar: use gint for slider_width instead of gint16 silences an incorrect pointer type warning. [ Michael Webster ] * nemo-list-view.c: don't explicitly unref columns anymore - they'll get handled when the tree view is destroyed. * nemo-icon-container.c: Re-enable desktop type-to-select feature. Also make a couple fixes on the positioning logic for this little popup. Where possible, it will avoid overlapping panels. * desktop windows: maximize instead of relying on gdk for monitor workarea - it's inaccurate for anything but the primary monitor. * nemo-icon-container.c: special case desktop windows for search popup - now that we can rely on the window being the correct size to account for panels, we can reliably position this popup off of those panels. [ JosephMcc ] * prefs: Don't try to hardcode a minimum size for the preferences dialog [ Michael Webster ] * Use g_themed_icon_new instead of g_themed_icon_new_with_default_fallbacks. * nemo-window.c: As of 9cb9c48f59baa we maximize the desktop containers to make sure they use the correct work area as set by muffin. This started causing the window state 'maximized' key to be set to true when opening a new nemo window. This corrects that issue, using disable_chrome as an indicator to ignore the window - only the desktop windows set this true. * nemo-window.c: fix formatting -- Clement Lefebvre Fri, 20 May 2016 12:26:51 +0100 nemo (3.0.1) sarah; urgency=medium [ JosephMcc ] * pathbar: Always show the pathbar up and down arrows. Dynamically adding and removing these buttons was causing the visual style of buttons in the pathbar to break [ Igor ] * Fix segfault on changing the number of colums when in list view * Fix uninitialized is_desktop flag [ Michal Cyprian ] * Port python scripts to Python 3 - /data/extract_action_strings - /data/merge_action_strings - /files/usr/share/nemo/actions/myaction.py - all Python 2-3 compatible [ Michael Webster ] * nemo-list-view.c: Fix initial column sizing - expand the filename column only to fill available space. Other columns will start with their natural size. * update m4 files [ itzexor ] * nemo-view: switch to nemo_get_file_by_uri so we don't get a NULL pointer if the file isn't already loaded internally. [ Michael Webster ] * Add desktop settings action * nemo-places-sidebar.c: ensure a minimum useable sidebar width when resizing windows or panes. [ Igor ] * Set minimum size for File Management Preferences window * Increase default width of File Management Preferences window [ Michael Webster ] * nemo-list-view.c: Clean up column changes - only add columns and connect to them once, remove some unnecessary checks. * nemo-list-view.c: give the name column a default width that the column-double-click autosize action can use. Otherwise it makes the name column as small as possible (the opposite what it's supposed to do, or what the other columns do) [ Igor ] * Update suggested.gitignore -- Clement Lefebvre Tue, 10 May 2016 16:36:23 +0100 nemo (3.0.0) sarah; urgency=medium [ lukefromdc ] * GTK 3.20-fix wrong desktop size [ Daniel Schürmann ] * Added missing includes * Fix pointer types, to avoid warning * Respect dbus_satisfied flag for menu enties on blank desktops * Fix printf format specifier * Don't draw the desktop on a cloned monitor * Fix some missing cast warnings [ Balló György ] * Fix fallback style for GTK 3.20 [ raveit65 ] * add style class nemo-window-pane * add style class nemo-properties-dialog to glade file [ Dustin Falgout ] * add style class in nemo_desktop_window_init (same as nautilus) * add style class to places sidebar * add style class to nemo-window * use more specific class name for places sidebar [ Michael Webster ] * nemo-icon-info.c: remove invalid GTK_ICON_LOOKUP_GENERIC_FALLBACK flag (triggers warnings in gtk 3.20.x). (credit to @itzexor) [ itzexor ] * nemo-window: add new flag NEMO_WINDOW_OPEN_FLAG_SEARCH and use the same slot if this flag is passed to nemo_window_slot_open_location_full to avoid opening a new window (and a crash) when starting a search with the open in new window preference enabled * fix typo [ Clement Lefebvre ] * Updated makepot and pot file -- Clement Lefebvre Sun, 24 Apr 2016 12:41:50 +0100 nemo (2.8.7) rosa; urgency=medium [ Michael Webster ] * improve context menu toggle: - shows separate distinct regions of the menu item now - tooltip manifests as right-justified text next to the toggle icon [ monsta ] * use g_strcmp0 instead of unsafe strcmp [ itzexor ] * file: don't crash when the original file path has reserved characters https://git.gnome.org/browse/nautilus/commit/?id=d69885bd67edc1fae76c790f6162807817d63b2f * file-operations: Make sure to use correct filename when restoring from Trash https://git.gnome.org/browse/nautilus/commit/libnautilus-private/nautilus-file-operations.c?id=ecee8be850b8342c804de2ecc3e613b99a20a010 * file-utils: ensure directories exist before restoring from trash https://git.gnome.org/browse/nautilus/commit/?id=f1cb32831df32009f7e8bd5fcc35c5ccdf64eee4 -- Clement Lefebvre Mon, 07 Mar 2016 17:19:06 +0000 nemo (2.8.6) rosa; urgency=medium [ Michael Webster ] * nemo-view.c: Fix Open context menu entry not updating its label when a new selection is made. Also, fix tracking the context toggle when the menu has scroll bars. * nemo-view: fix invalid View reference when view types change, and the tooltip is updated for the context menu toggle. -- Clement Lefebvre Fri, 27 Nov 2015 09:59:44 +0000 nemo (2.8.5) rosa; urgency=medium [ Michael Webster ] * list view, icon view: Don't trigger click-on-rename until button release, in order to preserve the possibility of dragging an already-selected single item. * icon-view/container: fix click-to-rename issue where selection count was not up-to-date, requiring an extra click to trigger a rename after selecting a single icon from having no selection previously. * bookmarks: Fix crashing and inconsistent behavior when working with remote bookmarks. * nemo-icon-container: prevent interactive search on the desktop. -- Clement Lefebvre Fri, 20 Nov 2015 17:27:57 +0000 nemo (2.8.4) rosa; urgency=medium [ Michael Webster ] * nemo-file-operations.c: Handle NULL NemoFiles when deciding queue - this happens in both directions when dragging/copying files to and from a Virtualbox guest or host. [ Clement Lefebvre ] * Removed context menu option from preferences -- Clement Lefebvre Thu, 12 Nov 2015 09:38:15 +0000 nemo (2.8.3) rosa; urgency=medium [ Michael Webster ] * Add control to context menu to toggle simple/complex menu * nemo-list-view: Implement click-to-rename * remove nemo-directory-view-ui-light.xml (no longer needed) [ Clement Lefebvre ] * Updated pot file -- Clement Lefebvre Wed, 11 Nov 2015 18:55:34 +0000 nemo (2.8.2) rosa; urgency=medium [ Michael Webster ] * file operations queue: refactor slightly to make it easier to manage what gets queued and what gets started immediately. * nemo-window-pane.c: prevent search from appearing on desktop * preferences: move context menu toggle to the top of the Display page * file operations window: raise the window when another operation is added, if the window is visible (not status-iconed). * click-to-rename: move logic to earlier in the click event, in a way similar to how double-clicks are handled. Also, handle the preference change in nemo-view - this way it can be re-used later to handle list views as well. Also, this keeps us from interacting with GSettings so much. * icon view: fetch click-to-rename preference when the view is loaded, don't allow click-to-rename on read-only files. * thumbnails: detect and throttle back thumbnail generation for files that are being actively updated on disk. * file queue: Add some additional checks for determining whether or not to start a file operation immediately. * Add option to disable queueing * job queue: Refactor to reduce duplication, add debugging info, add filesystem comparison to detect false "local" paths (local paths to non-local or non-native filesystems and mounts). * nemo-query-editor: fix some casts to prevent build warnings. * click-to-rename: Fix accidental rename triggering with multiple selection in icon view * click-to-rename: Fix previous commit (broke double-click upon initial selection.) * list view: Don't clear the rename widget twice [ Clement Lefebvre ] * Fixed nemo crashing when quickly clicking on two unmounted volumes in the sidebar -- Clement Lefebvre Mon, 09 Nov 2015 09:55:12 +0000 nemo (2.8.1) rosa; urgency=medium [ Michael Webster ] * nemo-list-view.c: Fix editable not being destroyed after a canceled rename in certain instances. This would cause the action bindings for cut/copy not to be released from the text entry box, breaking cut/copy/paste until nemo was restarted. * src/nemo-extension-config-widget.c: Make "No extensions found" un-clickable like the other two lists. (Would crash nemo when clicked) -- Clement Lefebvre Mon, 26 Oct 2015 11:44:59 +0000 nemo (2.8.0) rosa; urgency=medium [ Daniel Schürmann ] * pathbar: use a private struct and use use nemo_is_[home/root/desktop]_directory() * Fix compile errors * Don't use hardcoded script and action paths, remove unused sys script path * Used definitions from nemo-global-preferences * Moved action key definition to nemo-action.h to be external usable * Show comment as tooltips for actions in action config, and improve comments for some actions. * all: remove nemo_window_slot_go_to() * Combine the search bar and query editor * Added search_is_not_empty, to fixe a segfault in treelist [ Jonathan DePrizio ] * Only include the domain if the method is SMB [ Monsta ] * bumped some deps and build-deps [ AlirezaNaghizadeh ] * quick rename * quick rename [ pyecs ] * Fix default sort order bug in list view [ Michael Webster ] * nemo-places-sidebar.c: Fix a couple of drag-and-drop issues when there are no bookmarks, or when the xdg-bookmark area is empty. * nemo-places-sidebar.c: Fix a memory leak. * connect-to-server: remember the last connection type. * nemo-list-view.c: Fix column sorting when default sort type is "Detailed type" * nemo-connect-server-dialog.c: Fix previous commit. * fix build warning, missing prototype. * Fix some build warnings * nemo-window-pane.c: Fix crash during location entry. * fix indentation [ Clement Lefebvre ] * Don't assign the position of the last closed window to the first opened window (it would be really confusing if it worked.. and it didn't really work since gtk_application_get_windows() seemed to also count the desktop window) * Prefs: Rephrase quickrename option * nemo-action-config-widget.c: Localize non-localized comment string * Updated pot file [ Corbin ] * Re-add revealer animation on search bar * Fix Query Editor Row not displaying -- Clement Lefebvre Tue, 20 Oct 2015 10:32:51 +0100 nemo (2.6.7) rafaela; urgency=medium [ Michael Webster ] * progress window: simplify slightly, have info widgets manage themselves more, to prevent having a race condition at certain stages of the file operation. -- Clement Lefebvre Mon, 22 Jun 2015 23:35:49 +0200 nemo (2.6.6) rafaela; urgency=medium [ Michael Webster ] * Switch from .svg to .png format for the file operation tray icon. Scalable/symbolic isn't supported in gtk 3.12(+?) * open-with dialog: Fix focus and user interaction issues - - Focus defaults to the custom entry box - Enter key (or double-clicking in the list) will now 'OK' the dialog, and open the file with either the selected program, or the custom command. - The ok button now greys out if there is an invalid custom entry - Removed misleading program-picker button label and image. * preferences: tweak style a bit to match c-s * nemo-extensions-list: Don't hardcode lib path * nemo-view, nemo-sidebar: quiet warnings when looking for network locations -- Clement Lefebvre Sun, 14 Jun 2015 12:42:06 +0200 nemo (2.6.5) rafaela; urgency=medium [ leigh123linux ] * add runtime requirement for libcinnamon-desktop4 [ mtwebster ] * Fix a couple build warnings * nemo-application: register with org.gnome.SessionManager - this should fix the race condition where c-s-d dies before nemo does, causing all of our icons to revert to fallbacks briefly. -- Clement Lefebvre Wed, 27 May 2015 10:25:57 +0200 nemo (2.6.4) rafaela; urgency=medium [ Michael Webster ] * menus: Always show icons in Open With and Templates submenus. * nemo-bookmark-list: make sure to keep the bookmarks file writable by the user (and not just root) when running nemo as root. * fix build warning, fix prototype name. [ leigh123linux ] * Update version for cinnamon-desktop build dep -- Clement Lefebvre Mon, 25 May 2015 10:40:14 +0200 nemo (2.6.3) rafaela; urgency=medium [ leigh123linux ] * update cinnamon-desktop min version * bump it again -- Clement Lefebvre Thu, 21 May 2015 12:44:03 +0200 nemo (2.6.2) rafaela; urgency=medium [ Clement Lefebvre ] * Gettext fix: Due to genre/plural, in many languages, adjectives are not translatable on their own. They need to relate to a noun. * Gettext: Simplified msgids in file operation queue to make them easier to translate * Updated pot [ Michael Webster ] * Adapt Nemo to deal with problem situations with the user thumbnail cache: - Added --fix-cache command line option (must be run as root) - Added quick check at startup to detect major problems and disable thumbnailing until fixed. - Individual thumbnailed files are checked on the fly for permission issues. - When a problem is detected, an infobar appears, offering to fix the problem, or ignore it. * Have 'dismiss' last for Nemo's lifespan. * thumbnails: Remove an orphan comment from previous commits, fix wording of the --fix-cache command-line option. -- Clement Lefebvre Thu, 21 May 2015 11:06:16 +0200 nemo (2.6.1) rafaela; urgency=medium * Packaging: Fixed hardcoded gir typelib path -- Clement Lefebvre Wed, 20 May 2015 09:26:24 +0200 nemo (2.6.0) rafaela; urgency=medium * 2.6.0 -- Clement Lefebvre Tue, 19 May 2015 17:34:50 +0200 nemo (2.5.1) unstable; urgency=medium * 2.5.x -- Clement Lefebvre Mon, 19 Jan 2015 16:55:00 +0100 nemo (2.4.4) rebecca; urgency=medium * list-view: Don't reset zoom level when syncing statusbar zoom widget state. -- Clement Lefebvre Mon, 24 Nov 2014 09:11:57 +0100 nemo (2.4.3) rebecca; urgency=medium * Never allow root nemo to manage the desktop. -- Clement Lefebvre Sat, 22 Nov 2014 17:17:30 +0100 nemo (2.4.2) rebecca; urgency=medium * icon-container: Fix regression when renaming files in certain views - * Revert "places sidebar: set cells to a fixed height, seems to prevent residual" -- Clement Lefebvre Tue, 11 Nov 2014 22:35:46 +0100 nemo (2.4.1) rebecca; urgency=medium * Show UP button by default in the toolbar * Re-enabled the right click context menu on nemo toolbar navigation buttons * Recent files: show same open-with entries as normal folders * Sidebar: Fix expander state * Sidebar: workaround for icon render issue. Don't allow the tree view to be unrestrained vertically. * Places sidebar: set cells to a fixed height, seems to prevent residual render issues -- Clement Lefebvre Tue, 11 Nov 2014 11:07:57 +0100 nemo (2.4.0) rebecca; urgency=medium * 2.4.0 -- Clement Lefebvre Fri, 31 Oct 2014 16:23:56 +0100 nemo (2.3.0) unstable; urgency=medium * 2.3.0 -- Clement Lefebvre Fri, 27 Jun 2014 14:44:35 +0100 nemo (2.2.3) qiana; urgency=medium * Merging debian/patches * Show unmount progress notifications when ejecting a drive * Fix #627 - crash when unmounting archives. This is a temporary fix - pull request coming for permanent fix. * places-sidebar: render eject icon correctly in hidpi * Open-with dialog: Bugfix (Fixes #631) and a few improvements * nemo-links: add desktop file hack for desktop session names. * Fix sample nemo action to work with filenames with spaces. * Really fix the sample action * Clean up orphaned gtk bookmarks at startup. * Revert "Clean up orphaned gtk bookmarks at startup." * nemo-actions: Add flag to escape spaces in file paths. * Use GtkRevealer for search bar. * nemo-file: compare_by_display_name - handle null strings gracefully. -- Clement Lefebvre Fri, 27 Jun 2014 14:43:10 +0100 nemo (2.2.2) qiana; urgency=medium * 2.2.2 -- Clement Lefebvre Wed, 21 May 2014 12:36:20 +0100 nemo (2.2.1) qiana; urgency=medium * 2.2.1 -- Clement Lefebvre Thu, 01 May 2014 14:35:34 +0100 nemo (2.2.0) qiana; urgency=medium * 2.2.0 -- Clement Lefebvre Sat, 12 Apr 2014 15:50:14 +0100 nemo (2.0.8) petra; urgency=low * 2.0.8 -- Clement Lefebvre Mon, 25 Nov 2013 18:37:31 +0000 nemo (2.0.7) petra; urgency=low * 2.0.7 -- Clement Lefebvre Sat, 23 Nov 2013 13:39:58 +0000 nemo (2.0.6) petra; urgency=low * 2.0.6 -- Clement Lefebvre Mon, 11 Nov 2013 13:42:09 +0000 nemo (2.0.5) petra; urgency=low * 2.0.5 -- Clement Lefebvre Sun, 03 Nov 2013 15:53:05 +0000 nemo (2.0.4) petra; urgency=low * 2.0.4 -- Clement Lefebvre Thu, 31 Oct 2013 13:32:20 +0000 nemo (2.0.3) petra; urgency=low * 2.0.3 -- Clement Lefebvre Tue, 29 Oct 2013 10:40:51 +0000 nemo (2.0.2) petra; urgency=low * 2.0.2 -- Clement Lefebvre Tue, 22 Oct 2013 14:20:41 +0100 nemo (2.0.1) petra; urgency=low * 2.0.1 -- Clement Lefebvre Fri, 18 Oct 2013 15:57:39 +0100 nemo (2.0.0) petra; urgency=low * 2.0.0 -- Clement Lefebvre Wed, 02 Oct 2013 16:36:43 +0100 nemo (1.9.1) petra; urgency=low * 1.9.1 -- Clement Lefebvre Mon, 30 Sep 2013 14:21:12 +0100 nemo (1.8.5) olivia; urgency=low * 1.8.5 -- Clement Lefebvre Tue, 20 Aug 2013 14:07:52 +0100 nemo (1.8.4) olivia; urgency=low * 1.8.4 -- Clement Lefebvre Tue, 09 Jul 2013 17:12:40 +0200 nemo (1.8.3) olivia; urgency=low * 1.8.3 -- Clement Lefebvre Sat, 01 Jun 2013 12:55:17 +0100 nemo (1.8.2) olivia; urgency=low * 1.8.2 -- Clement Lefebvre Sun, 19 May 2013 21:08:35 +0100 nemo (1.8.1) olivia; urgency=low * 1.8.1 -- Clement Lefebvre Thu, 09 May 2013 13:29:40 +0100 nemo (1.8.0) olivia; urgency=low * 1.8.0 -- Clement Lefebvre Sun, 05 May 2013 13:21:54 +0100 nemo (1.7.6) olivia; urgency=low * 1.7.6 -- Clement Lefebvre Fri, 03 May 2013 17:07:54 +0100 nemo (1.7.5) olivia; urgency=low * 1.7.5 -- Clement Lefebvre Tue, 30 Apr 2013 16:45:52 +0100 nemo (1.7.4) olivia; urgency=low * 1.7.4 -- Clement Lefebvre Sat, 27 Apr 2013 20:03:25 +0100 nemo (1.7.3) olivia; urgency=low * 1.7.3 -- Clement Lefebvre Mon, 15 Apr 2013 14:56:37 +0100 nemo (1.7.2) olivia; urgency=low * 1.7.2 -- Clement Lefebvre Fri, 22 Mar 2013 14:07:10 +0000 nemo (1.7.1) olivia; urgency=low * 1.7.1 -- Clement Lefebvre Tue, 19 Feb 2013 16:29:56 +0000 nemo (1.1.2) nadia; urgency=low * 1.1.2 -- Clement Lefebvre Wed, 14 Nov 2012 12:02:03 +0000 nemo (1.1.1) nadia; urgency=low * 1.1.1 -- Clement Lefebvre Tue, 06 Nov 2012 16:37:43 +0000 nemo (1.1.0) nadia; urgency=low * 1.1.0 -- Clement Lefebvre Mon, 05 Nov 2012 18:47:31 +0000 nemo (1.0.9) nadia; urgency=low * 1.0.9 -- Clement Lefebvre Fri, 02 Nov 2012 20:50:56 +0000 nemo (1.0.8) nadia; urgency=low * 1.0.8 -- Clement Lefebvre Thu, 01 Nov 2012 12:55:13 +0000 nemo (1.0.7) nadia; urgency=low * 1.0.7 -- Clement Lefebvre Sun, 28 Oct 2012 16:25:12 +0000 nemo (1.0.6) nadia; urgency=low * 1.0.6 -- Clement Lefebvre Tue, 23 Oct 2012 15:33:14 +0100 nemo (1.0.5) nadia; urgency=low * nadia -- Clement Lefebvre Sat, 20 Oct 2012 12:23:47 +0100 nemo (1.0.4) nadia; urgency=low * 1.0.4 -- Clement Lefebvre Thu, 18 Oct 2012 13:43:14 +0100 nemo (1.0.3) maya; urgency=low * 1.0.3 -- Clement Lefebvre Mon, 01 Oct 2012 15:22:23 +0100 nemo (1.0.2) maya; urgency=low * 1.0.2 -- Clement Lefebvre Thu, 27 Sep 2012 14:27:20 +0100 nemo (1.0.1) maya; urgency=low * 1.0.1 -- Clement Lefebvre Wed, 19 Sep 2012 10:32:29 +0100 nemo (1.0.0) maya; urgency=low * Initial version, based on nautilus 3.4.2-0ubuntu3 -- Clement Lefebvre Wed, 18 Jul 2012 18:43:00 +0000 nemo-4.4.2/debian/clean000066400000000000000000000000151357442400300147040ustar00rootroot00000000000000debian/build/nemo-4.4.2/debian/compat000066400000000000000000000000031357442400300151020ustar00rootroot0000000000000010 nemo-4.4.2/debian/control000066400000000000000000000101231357442400300153030ustar00rootroot00000000000000Source: nemo Section: misc Priority: optional Maintainer: Linux Mint Build-Depends: cinnamon-l10n, debhelper (>= 10), dh-python, gobject-introspection, gtk-doc-tools (>= 1.4), intltool (>= 0.40.1), libatk1.0-dev (>= 1.32.0), libcinnamon-desktop-dev (>= 3.6), libexempi-dev (>= 2.2.0), libexif-dev (>= 0.6.20), libgail-3-dev, libgirepository1.0-dev (>= 0.9.12), libglib2.0-dev (>= 2.45.7), libglib2.0-doc, libgtk-3-dev (>= 3.9.10), libgtk-3-doc, libnotify-dev (>= 0.7.0), libx11-dev, libxapp-dev (>= 1.4.0), libxext-dev, libxml2-dev (>= 2.7.8), libxrender-dev, libxt-dev, meson, python, python3, python3-gi, shared-mime-info (>= 0.50), x11proto-core-dev, Homepage: http://www.github.com/linuxmint/nemo/ Standards-Version: 3.9.5 Package: gir1.2-nemo-3.0 Architecture: any Section: introspection Depends: ${gir:Depends}, ${misc:Depends} Conflicts: gir1.0-nemo-3.0 Replaces: gir1.0-nemo-3.0 Description: libraries for nemo components - gir bindings Nemo is the official file manager and graphical shell for the Cinnamon desktop. . This package can be used by other packages using the GIRepository format to generate dynamic bindings. Package: libnemo-extension-dev Architecture: any Section: libdevel Depends: gir1.2-nemo-3.0 (= ${binary:Version}), libglib2.0-dev (>= 2.45.7), libgtk-3-dev (>= 3.9.10), libnemo-extension1 (= ${binary:Version}), ${misc:Depends}, Description: libraries for nemo components - development version Nemo is the official file manager and graphical shell for the Cinnamon desktop. . This package provides the necessary development libraries and include files to develop and compile Nemo extensions. Package: libnemo-extension1 Architecture: any Section: libs Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: ${misc:Depends}, ${shlibs:Depends} Provides: libnemo-extension1a Replaces: libnemo-extension1a breaks: libnemo-extension1a Description: libraries for nemo components - runtime version Nemo is the official file manager and graphical shell for the Cinnamon desktop. . This package contains a few runtime libraries needed by nemo' extensions. Package: nemo Architecture: any Pre-Depends: ${misc:Pre-Depends} Depends: cinnamon-desktop-data, cinnamon-l10n, desktop-file-utils (>= 0.7), gsettings-desktop-schemas, gvfs (>= 1.3.2), libcinnamon-desktop4 (>= 2.6.1), libglib2.0-data, libnemo-extension1 (= ${binary:Version}), libxapp1 (>= 1.4.0), nemo-data (= ${source:Version}), shared-mime-info (>= 0.50), ${misc:Depends}, ${shlibs:Depends}, Recommends: gvfs-backends, gvfs-fuse, librsvg2-common, nemo-fileroller, Suggests: eog, evince | pdf-viewer, totem | mp3-decoder, xdg-user-dirs Description: file manager and graphical shell for Cinnamon Nemo is the official file manager for the Cinnamon desktop. It allows to browse directories, preview files and launch applications associated with them. It is also responsible for handling the icons on the Cinnamon desktop. It works on local and remote filesystems. . Several icon themes and components for viewing different kinds of files are available in separate packages. Package: nemo-data Architecture: all Depends: python, ${misc:Depends}, ${python:Depends} Suggests: nemo Description: data files for nemo Nemo is the official file manager and graphical shell for the Cinnamon desktop. . This package contains pictures, localization files and other data needed by nemo. Package: nemo-dbg Section: debug Architecture: any Priority: extra Depends: nemo (= ${binary:Version}), ${misc:Depends} Replaces: libnemo-extension1-dbg Description: file manager and graphical shell for Cinnamon - debugging version Nemo is the official file manager for the Cinnamon desktop. It allows to browse directories, preview files and launch applications associated with them. It is also responsible for handling the icons on the Cinnamon desktop. It works on local and remote filesystems. . Several icon themes and components for viewing different kinds of files are available in separate packages. . This development package contains unstripped binaries compiled with debugging symbols needed by gdb. nemo-4.4.2/debian/copyright000066400000000000000000000260331357442400300156420ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Nemo Upstream-Contact: Linux Mint Project Source: https://github.com/linuxmint/nemo Files: * Copyright: 2009, Alexander Larsson 2007-2011, Amos Brocco 2002, Anders Carlsson 2002, Bent Spoon Software 2003-2005, Christian Persch 2002, Christophe Fergeau 2008-2010, Cosimo Cecchi 2010, Cosimo Cecchi 2002, Darin Adler 2000-2001, Eazel, Inc 1999-2000, Free Software Foundation 2008, Free Software Foundation, Inc 1999-2000, Free Software Foundaton 2004, James Willcox 2001, Maciej Stachowiak 2003-2004, Marco Pesenti Gritti 2007, Martin Wehner 2005, Mr Jamie McCracken 2007, Novell, Inc 2006, Paolo Borelli 2004, Red Hat Inc 1999-2000, Red Hat, Inc 2002, Sun Microsystems, Inc 2005, Vincent Untz 1999-2000, Eazel, Inc 1999-2000, Red Hat Inc License: GPL-2+ Files: COPYING.LIB cut-n-paste-code/libegg/eggtreemultidnd.c cut-n-paste-code/libegg/eggtreemultidnd.h data/dbus-interfaces.xml data/freedesktop-dbus-interfaces.xml eel/check-program.c eel/eel-accessibility.c eel/eel-accessibility.h eel/eel-art-extensions.c eel/eel-art-extensions.h eel/eel-canvas.c eel/eel-canvas.h eel/eel-debug.c eel/eel-debug.h eel/eel-editable-label.c eel/eel-editable-label.h eel/eel-gdk-extensions.c eel/eel-gdk-extensions.h eel/eel-glib-extensions.c eel/eel-glib-extensions.h eel/eel-gnome-extensions.c eel/eel-gnome-extensions.h eel/eel-graphic-effects.c eel/eel-graphic-effects.h eel/eel-gtk-extensions.c eel/eel-gtk-extensions.h eel/eel-lib-self-check-functions.c eel/eel-lib-self-check-functions.h eel/eel-self-checks.c eel/eel-self-checks.h eel/eel-stock-dialogs.c eel/eel-stock-dialogs.h eel/eel-string.c eel/eel-string.h eel/eel-vfs-extensions.c eel/eel-vfs-extensions.h eel/eel.h libnemo-extension/nemo-column-provider.c libnemo-extension/nemo-column-provider.h libnemo-extension/nemo-column.c libnemo-extension/nemo-column.h libnemo-extension/nemo-extension-private.h libnemo-extension/nemo-extension-types.h libnemo-extension/nemo-file-info.c libnemo-extension/nemo-file-info.h libnemo-extension/nemo-info-provider.c libnemo-extension/nemo-info-provider.h libnemo-extension/nemo-location-widget-provider.c libnemo-extension/nemo-location-widget-provider.h libnemo-extension/nemo-menu-item.c libnemo-extension/nemo-menu-item.h libnemo-extension/nemo-menu-provider.c libnemo-extension/nemo-menu-provider.h libnemo-extension/nemo-menu.c libnemo-extension/nemo-menu.h libnemo-extension/nemo-property-page-provider.c libnemo-extension/nemo-property-page-provider.h libnemo-extension/nemo-property-page.c libnemo-extension/nemo-property-page.h libnemo-private/nemo-bookmark.c libnemo-private/nemo-bookmark.h libnemo-private/nemo-centered-placement-grid.c libnemo-private/nemo-clipboard.c libnemo-private/nemo-clipboard.h libnemo-private/nemo-column-chooser.c libnemo-private/nemo-column-chooser.h libnemo-private/nemo-column-utilities.c libnemo-private/nemo-column-utilities.h libnemo-private/nemo-context-menu-menu-item.c libnemo-private/nemo-context-menu-menu-item.h libnemo-private/nemo-dnd.c libnemo-private/nemo-dnd.h libnemo-private/nemo-entry.c libnemo-private/nemo-entry.h libnemo-private/nemo-file-dnd.c libnemo-private/nemo-file-dnd.h libnemo-private/nemo-file-utilities.c libnemo-private/nemo-file-utilities.h libnemo-private/nemo-global-preferences.c libnemo-private/nemo-global-preferences.h libnemo-private/nemo-icon-canvas-item.c libnemo-private/nemo-icon-canvas-item.h libnemo-private/nemo-icon-container.c libnemo-private/nemo-icon-container.h libnemo-private/nemo-icon-dnd.c libnemo-private/nemo-icon-dnd.h libnemo-private/nemo-icon-info.c libnemo-private/nemo-icon-private.h libnemo-private/nemo-icon.h libnemo-private/nemo-metadata.c libnemo-private/nemo-mime-application-chooser.c libnemo-private/nemo-mime-application-chooser.h libnemo-private/nemo-module.c libnemo-private/nemo-module.h libnemo-private/nemo-placement-grid.c libnemo-private/nemo-program-choosing.c libnemo-private/nemo-program-choosing.h libnemo-private/nemo-selection-canvas-item.c libnemo-private/nemo-selection-canvas-item.h libnemo-private/nemo-ui-utilities.c libnemo-private/nemo-ui-utilities.h libnemo-private/nemo-undo-manager.c libnemo-private/nemo-undo-manager.h libnemo-private/nemo-undo-private.h libnemo-private/nemo-undo-signal-handlers.c libnemo-private/nemo-undo-signal-handlers.h libnemo-private/nemo-undo-transaction.c libnemo-private/nemo-undo-transaction.h libnemo-private/nemo-undo.c libnemo-private/nemo-undo.h libnemo-private/nemo-widget-menu-item.c libnemo-private/nemo-widget-menu-item.h src/nemo-autorun-software.c src/nemo-desktop-icon-grid-view.c src/nemo-desktop-icon-grid-view.h src/nemo-desktop-icon-view.c src/nemo-desktop-icon-view.h src/nemo-empty-view.c src/nemo-empty-view.h src/nemo-error-reporting.c src/nemo-error-reporting.h src/nemo-file-management-properties.c src/nemo-file-management-properties.h src/nemo-floating-bar.c src/nemo-floating-bar.h src/nemo-icon-view-container.c src/nemo-icon-view-container.h src/nemo-icon-view-grid-container.c src/nemo-icon-view-grid-container.h src/nemo-icon-view.c src/nemo-icon-view.h src/nemo-list-model.c src/nemo-list-model.h src/nemo-list-view-private.h src/nemo-list-view.c src/nemo-list-view.h src/nemo-mime-actions.c src/nemo-mime-actions.h src/nemo-navigation-state.c src/nemo-navigation-state.h src/nemo-pathbar.c src/nemo-pathbar.h src/nemo-properties-window.c src/nemo-properties-window.h src/nemo-statusbar.c src/nemo-statusbar.h src/nemo-window-slot-dnd.c src/nemo-window-slot-dnd.h Copyright: 2001-2002, Anders Carlsson 2001-2002, Anders Carlsson 2002, Anders Carlsson, Sun Microsystems, Inc 1999-2001, Eazel, Inc 2000-2001, Eazel, Inc.mou 1997-2000, Free Software Foundation 2006, Free Software Foundation, Inc 1999-2000, Free Software Foundaton 2002, Jan Arne Petersen 2003-2004, Novell, Inc 1995-1997, Peter Mattis, Spencer Kimball and Josh MacDonald 2005, Raffaele Sandrini 2011, Red Hat Inc 2001-2011, Red Hat, Inc 2007, Red Hat, Inc., Alexander Larsson 2004, Red Hat, Inc., Jonathan Blandford 2009, Red Hatl, Inc 2003, Soeren Sandmann 2002, Sun Microsystems, Inc License: LGPL-2+ Files: po/Makefile.in.in Copyright: 2004-2008, Rodney Dawes 1995-1997, Ulrich Drepper License: Permissive 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. Files: files/usr/share/gtksourceview-2.0/language-specs/nemo_action.lang files/usr/share/gtksourceview-3.0/language-specs/nemo_action.lang libnemo-private/nemo-debug.c libnemo-private/nemo-debug.h Copyright: 2007, Collabora Ltd 2006, Luca Cavalli 2007, Nokia Corporation 2003, Paolo Maggi 2010, Red Hat, Inc License: LGPL-2.1+ Files: debian/* Copyright: 2012, Nicolas Bourdaud 2012, Josselin Mouette 2014-2015, Maximiliano Curia License: GPL-2+ License: GPL-2+ This package 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 package 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 package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. License: LGPL-2+ 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 package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/LGPL-2'. License: LGPL-2.1+ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. . This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the complete text of the GNU Lesser General Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. nemo-4.4.2/debian/gir1.2-nemo-3.0.install000066400000000000000000000000331357442400300175230ustar00rootroot00000000000000usr/lib/*/girepository-1.0 nemo-4.4.2/debian/libnemo-extension-dev.install000066400000000000000000000001611357442400300215040ustar00rootroot00000000000000usr/include usr/lib/*/libnemo-extension*.so usr/lib/*/pkgconfig usr/share/gir-1.0/Nemo-3.0.gir usr/share/gtk-doc nemo-4.4.2/debian/libnemo-extension1.install000066400000000000000000000000421357442400300210070ustar00rootroot00000000000000usr/lib/*/libnemo-extension*.so.* nemo-4.4.2/debian/menu000066400000000000000000000002161357442400300145710ustar00rootroot00000000000000?package(nemo):needs="X11" section="Applications/File Management" \ title="Nemo" command="/usr/bin/nemo" icon="/usr/share/pixmaps/nemo.xpm" nemo-4.4.2/debian/nemo-data.install000066400000000000000000000003131357442400300171350ustar00rootroot00000000000000usr/share/glib-2.0/schemas/org.nemo.gschema.xml usr/share/gtksourceview-2.0 usr/share/gtksourceview-3.0 usr/share/icons/hicolor usr/share/mime/packages/nemo.xml usr/share/nemo usr/share/polkit-1/actions nemo-4.4.2/debian/nemo.install000066400000000000000000000002071357442400300162300ustar00rootroot00000000000000usr/bin usr/lib/*/nemo/nemo-convert-metadata usr/lib/*/nemo/nemo-extensions-list usr/share/applications usr/share/dbus-1 usr/share/man nemo-4.4.2/debian/nemo.lintian-overrides000066400000000000000000000002271357442400300202220ustar00rootroot00000000000000# Used by gnome-session # https://wiki.gnome.org/Projects/SessionManagement/GnomeSession nemo: desktop-entry-contains-unknown-key * AutostartCondition nemo-4.4.2/debian/not-installed000066400000000000000000000002261357442400300164030ustar00rootroot00000000000000# No libtool files usr/lib/x86_64-linux-gnu/libnemo-extension.la # False positives usr/share/man/man1/nemo.1 usr/share/man/man1/nemo-connect-server.1 nemo-4.4.2/debian/rules000077500000000000000000000020021357442400300147550ustar00rootroot00000000000000#!/usr/bin/make -f # Force UTF8 to workaround build error export LC_ALL=C.UTF-8 CONFIGURE_EXTRA_FLAGS = \ --prefix=/usr \ --libdir=/usr/lib/$(DEB_HOST_MULTIARCH) \ --libexecdir=/usr/lib/$(DEB_HOST_MULTIARCH)/nemo \ -D deprecated_warnings=false \ -D gtk_doc=true \ -D selinux=false export LDFLAGS+=-Wl,-z,defs -Wl,-O1 -Wl,--as-needed %: dh $@ --with gir override_dh_auto_configure: mkdir -p debian/build meson debian/build $(CONFIGURE_EXTRA_FLAGS) override_dh_auto_build: ninja -C debian/build override_dh_auto_test: # ninja -C build test override_dh_strip: dh_strip --dbg-package=nemo-dbg override_dh_auto_install: DESTDIR=${CURDIR}/debian/tmp \ ninja -C debian/build install override_dh_makeshlibs: dh_makeshlibs -Xusr/lib/nemo/extensions-3.0/ override_dh_installmime: dh_installmime -pnemo-data # with dh11 replace with dh_missing # debian/not-installed wildcard support introduced in debhelper 11.1 # --list-missing will be default in compat 12 override_dh_install: dh_install --list-missing nemo-4.4.2/debian/source/000077500000000000000000000000001357442400300152035ustar00rootroot00000000000000nemo-4.4.2/debian/source/format000066400000000000000000000000151357442400300164120ustar00rootroot000000000000003.0 (native) nemo-4.4.2/docs/000077500000000000000000000000001357442400300134115ustar00rootroot00000000000000nemo-4.4.2/docs/dnd.txt000066400000000000000000000061201357442400300147160ustar00rootroot00000000000000 Nemo dnd code. ------------------ Nemo dnd code is pretty compilcated, it has a lot of entry points and exit points. Trying to clarify this now. You have to implement: If you are a source: drag_begin drag_end drag_get_data If you are a destination: drag_motion drag_data_received drag_drop drag_leave 1) Source --------- if you are a source, you have to start a drag trough gtk_drag_begin. This will call drag_begin signal in the source. Then, when the destination calls gtk_drag_finish, drag_end will be called in the source. drag_get_data will be called in the source when the destination calls gtk_drag_get_data So, the source is very easy to write: it just needs to implement those 3 signals and it should not have any memory management issue. 2) Destination -------------- Things get a little bit complicated. when the dragging cursor gets in your window, you will get drag_motion events. In nemo, we do many things in this function: - we start auto-scrolling if it is necessary. - we call nemo_*_ensure_data - we prelight what is under the cursor if it can accept the drag. - we try to expand what is under you if it can accept the drop (tree view) nemo_*_ensure_data is vital. It calls gtk_drag_get_data to get the data from the source. this allows the destination to store it in advance and use it to know if what is under the cursor can accept the drag. Then, when the drop occurs, drag_drop is called on the destination. drag_drop calls gtk_drag_get_data to get the data from the source to do its drop. Then, drag_data_received is called when the data is received. There, we can do the actual operation involved by the drop. Also, just before the drag_drop event, a drag_leave event is triggered. If no drop occurs, a drag_leave occurs. So, drag_data_received does 2 things: it is called to get the data when we are in motion and store it. It is also called to do the actual drop operation when a drop happened. So, drag_data_received usually does 2 tests: it tests if the data was received. If it was received, it stores it. Then it tests if the drop occured just before. If so, it does the operation. This schema involves careful memory management: 1) 2 exit points in destination. (drag_leave and drag_data_received) 2) a lot of things are done in the callbacks so you have to take into account all the possible code paths. To solve 1), we should use ONE destroy function which cleans up the drag data. To solve 2), we have to be very careful where we call this fution from. This function has to clean up: - the list of expanded nodes (tree view). - the autoscroll code. - the prelighting code. It also has to set drag_info->need_to_destroy to TRUE so that during the next drag in this widget, the rest of the drag data is destroyed before begening the actual new drag. When we receive a drag_motion, we first test for need_to_destroy and destroy the rest of the data left from the previous drag. This code has to destroy/reset: - the drag data. - the boolean vars used to store the state of the drag. nemo-4.4.2/docs/key_mouse_navigation.txt000066400000000000000000000075321357442400300204000ustar00rootroot00000000000000This document describes the keyboard and mouse navigation model used in the default Nemo views in detail. This is useful as a a guide for people implementing a Nemo view or something else that wants to have a feel that is compatible with Nemo. *********** Icon view ******************** Keyboard: ========= Navigation and selection: When the focus is on the icon view you can move the currently selected icon by using: Arrow Keys - moves one step in the direction Tab - moves to the "next" icon in order (i.e. at the end of one row, go to the first icon the next row) Shift Tab - moves to the "previous" icon in order Home - moves to the first icon End - moves to the last icon In order to allow multiple selection the above navigation keys can be combined with the Control key to move the keyboard focus without affecting the current selection. If you use normal movement (not using control) all the previously selected icons will be deselected. If several icons are selected and there is no keyboard focus you press up or left will start navigating from the topmost leftmost icon, while pressing down or right will start from the bottommost rightmost icon. This works the same way if you hold down Control. To select or deselect an icon position the keyboard focus on it and press ctlr-space. ctrl-space with no keyboard focus produces a keyboard focus at the first selected icon, or the first one if none are selected. In manual layout (and especially, on the desktop) the keyboard arrow keys work in a slightly different way. To allow all icons to be reached the closest icon in the quadrant of the direction selected will be used as the "next" icon when navigating. Other keyboard shortcuts: Return, Keypad Return - Activate the selected objects Space (without control) - Activate the selected objects Escape - Undo icon stretching if in progress Alt Left - go back Alt Right - go forward Alt Up - go up a directory Alt Down - enter directory / activate selection Shift-F10 bring up context menu for selection, or the directory context menu if nothing is selected Ctrl-F10 bring up context menu for directory Other key presses are used for typeahead search In rename mode: Escape - Cancel rename Return, Keypad Return - Finish rename Mouse: ====== In double click mode: Clicking on an icon selects it and deselects all others on BUTTON_PRESS. Dragging does the default dnd file operation. Clicking on blank space deselect all selected icons. Doesn't allow dragging. Double clicking (both clicks on the same icon) with no modifiers activates the clicked file. (And deselects the others due to the first click.) Clicking when Control (Shift can also be used, which is not written out below) is held down can be used to do multiple selections. Control-click on empty space does nothing. Control-click on unselected icon selects it on BUTTON_PRESS Control-click on selected icon de-selects it on BUTTON_RELEASE Control-double click does nothing Control can be held down while starting a drag While doing a drag modifers affect the operation the drag causes: Control - Copy the files Shift - Move the files Alt - Open a menu with the available alternatives All the basic clicks are typically done with the left button, but can be done with the other buttons to. [Do we want this?] However some of the buttons also have special operations: Right-click on a selected icon opens the context menu for the selected icons. Right-click on empty space opens the context menu for the directory. Middle-button drag always opens the menu with possible operations on drop. In single click mode: Single click mode work just like double click mode except single clicks on icons activate the icon on button release if you didn't drag, didn't hold down for 1.5 secs or clicked twice within the double-click time. *********** List view ******************** [TODO: Add stuff here] nemo-4.4.2/docs/load-states.dia000066400000000000000000000037521357442400300163170ustar00rootroot00000000000000‹í\ÛnÛF}×WÊ+½Ú+/Qì ) @ÑM/%®%¶)´÷¡ßÞÙ•|‘D*2—«¸) ؉èÕÎzgΙ١޼ý¼L[Y”Iž] Â÷Wƒ7q½†ïy-•êÕåpQU«×£Ñz½Fé]UyÒä•rôO”¦Ñ†WÇy:AU‘º¶½UU‘Lo*édÑR^§Ñì¯y‘ßdñp3j;n–§yáÜFéåðÕµþŽ¶ÓŒvæ92÷*ZÉbÚå*/RÝ­†4Ì£~>³U l~õêµ¹¥í…ǹên´¤ZFÅ<Éq ¥›… ( ÷«ð|€©m€Ô6@a )'«¼¨Š(©A¦yžÊ(ÛàTÅlS΢¶Ê1CÈ ³o.?léF÷Ø\ÚóG—Fw²ØÞÔûGOtn“2™¦rkç˧ÊYµuži¾ž-¢¢r.œ÷ùçác ÁC'‰/‡?á]ïÛ_˜ ¼Ü÷¿UždÕfòu/(E^kÒ´"M(Óé>HvDÙ<•÷@ÂÛù< Æ#&„ç^…¼-²Lår2Ë‹ì0Ætl£FZ'qµ8´ó~Kq˜Ÿyó/d2_TͰvíf/ùzRÃ_ö¼ç ¬¢8Þõº½ûÇH´›¹’Ÿ–eŸiöÆ4­„æq{tó1Kª$JeU²yŽÄ£Üë<«êPÕõíïò›"<2Á9ØBµ†À d7¤Ô¹œBàs !ˆœ–*u€O5 Ö_f@@ól)ëÿR2»YÖPÇ1jª£&}5zŒþí逘ÒG¾B¬$…vù¨F¢kBàˆù¶ 0¶LXy #„Hpb“À€žl3 Wkˆ4¿ýòÑI²ë¼g…v¬î ´ƒ='tÄ Ÿ ¦ÆQ%üd²†¨)'Üs¹Rêv9ÁGkÕ;d›$p¥IkB˜åY6‘Y¬íieeã66!ÈN夬îR¹K[Š·ä,žDE‘¯›g&†3OR™ÍñÞN,iñf=AmØeàå]ÜÿÆY€©l|¦ÊuZí<þÖ‹l‡š7“í›Éî›éþ}ÜÑsµßÏ…Œå5ì þ›ÏdYÖ¸=3u{*T¦:…L1bÑï 2s Å1@A cáb̪ìÆÊS´ @Ct³ZàØ'ä% Âë4YMy‘ü 'J¢\Gii.Q%3{ 'ˆ[ØRB°—¯p¿‡[ 6¬èÕm;uK¤dªkb¯W·çQ·Ü”æTÝêº1¨;œDs„!îo¡Žcê!¡y7´&Ÿ“%n³©Öx±×¢ÆZtONÏ‘¢l÷½¸)úÄ)ë«ÂØ'u/8<ô=›þˆˆÐ8!àŒI;Ýõ/0å6%§¹u§ÈMÉ´ÍÂ#X!^²Ò<%ÃþÒuS”÷Ì‹ò˜z AJD9·è Á– ª\€«ò ¥ÜU `Ù%º°ð§ðáV3°¾o;Uù!bç6‘ë>Mi{4K\‚xÈCÖ')çIR|Sx88Áv ðò5L¸­¾ƒþgª4×V¨œœš4X7Цê©OJºNJžW {oî:+iðÂÀ8-ÁˆøÜ%™bÑ CÈÓ¹J½=L{(PÈWZŸ^%h°òH€€S’¶uÎÞÍÝÑë®F ºöÆ_•ð;ôÆÐüXš¹X°Y% ê`Xíq2BÇøzœ*dõš„/_11&£ÙB«æ×ߤl&öEsífëe³ÕnFãîv†8åˬ36 øH—NTPÝî¶+']XxJå$@8ðißÛþß.ž|½¢ºàxÙ\:KY–ѼïroÍ Ü ¸Ëç}5ålÕBÌ¥#QUmËœà¨J›f„1¢·Ê9R¸Zû·¯wôÙ[×ÙÛ3» ±vÃ'^ø®˜Õ9¡q[±ÒH„‚GxâÕ AšøÜ†B‚W÷ãÙ¯¦4Xy¤îÜÖMq+'qR‚ý3yLlQŸ…ÂÞÉj_ úz¥YlP ÚE¸óæå†Tϸ]ÙCóWµ6§Y¥ulÀQU8 0¿ǘÚÌõº0ñ”\äñm>µÆès½s=µ6—­¤ÚC‰\ªÜIó(î3¾vŸ"éPx.¡ð/û”ïL)7?A÷usŸåœ/@!Ëྈ¹Ú+…­™á'èuÙÁF,Òë4c¶w î=+éc¶Ÿ1ki¢ƒ‡Iµ† tÑÁ곤A°R%ù1ltšKÅÓeZ&ö7óêg”±;Xƒ\ƒ ½0k-ÌhÀ€ÖB]Œï…YǬ¡‹ƒxäíBuòÐöÃ, Uç åÛ6ެ_¿ü8ñ£\;¿C·Ñßj¤°ÞÈѰÝú(a5}ó;h½ÄBרì÷BD]]ÑÃ:D¶¡"¬ço a:#}Ù'p­¸‡$LX>ykò&óFf†|¡jÖTït›¬Kf¹úõa9¾÷ÐË ·àÁ©š =ÚÌLúg ¾êë®›Ù;Ói¸q7³ªO0ÌÙX¦8 5_UB.ˆjZ ÇÌGç3—RDIÈl{d“Ç?®@жÏmž|$΄÷GâßbD…˜F”ÍkýIàWƒ ¿ü GQÀ@ `nemo-4.4.2/docs/meson.build000066400000000000000000000003561357442400300155570ustar00rootroot00000000000000 install_man( 'nemo.1', 'nemo-connect-server.1', ) if gtkdoc_enabled subdir('reference') endif # Just for Dist extraMans = [ 'dnd.txt', 'key_mouse_navigation.txt', 'load-states.dia', 'nemo-io.txt', 'style-guide.html', ] nemo-4.4.2/docs/nemo-connect-server.1000066400000000000000000000034011357442400300173620ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH nemo-connect-server 1 "05 Jan 2008" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME nemo-connect-server \- To Access a remote server .SH SYNOPSIS .B nemo-connect-server .RI [ options ] .RI [ URI ] .SH DESCRIPTION This manual page documents briefly the .B nemo-connect-server command. .PP Nemo Connect Server is the connection manager for the GNOME desktop. .PP You can use the file manager to access a remote server, be it an FTP site, a Windows share, a WebDav server or an SSH server. .SH OPTIONS Nemo follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP .B \-\-help Show a summary of options. .TP .B \-\-version Show version. .TP Other standard GNOME options not listed here are also supported. .SH SEE ALSO Nemo Connect Server documentation can be found from the "Help" menu, or by pressing the F1 key. Nemo also has a website at http://www.gnome.org/projects/nemo/ .SH AUTHOR This manual page was written by Julian Andres Klode for the Debian GNU/Linux system (but may be used by others), based on a manpage by Fernando Ribeiro . nemo-4.4.2/docs/nemo-io.txt000066400000000000000000000305151357442400300155210ustar00rootroot00000000000000Nemo I/O Primer draft ("Better Than Nothing") 2001-08-23 Darin Adler The Nemo shell, and the file manager inside it, does a lot of I/O. Because of this, there are some special disciplines required when writing Nemo code. No I/O on the main thread To be able to respond to the user quickly, Nemo needs to be designed so that the main user input thread does not block. The basic approach is to never do any disk I/O on the main thread. In practice, Nemo code does assume that some disk I/O is fast, in some cases intentionally and in other cases due to programmer sloppiness. The typical assumption is that reading files from the user's home directory and the installed files in the Nemo datadir are very fast, effectively instantaneous. So the general approach is to allow I/O for files that have file system paths, assuming that the access to these files is fast, and to prohibit I/O for files that have arbitrary URIs, assuming that access to these could be arbitrarily slow. Although this works pretty well, it is based on an incorrect assumption, because with NFS and other kinds of abstract file systems, there can be arbitrarily slow parts of the file system that have file system paths. For historical reasons, threading in Nemo is done through the gnome-vfs asynchronous I/O abstraction rather than using threads directly. This means that all the threads are created by gnome-vfs, and Nemo code runs on the main thread only. Thus, the rule of thumb is that synchronous gnome-vfs operations like the ones in are illegal in most Nemo code. Similarly, it's illegal to ask for a piece of information, say a file size, and then wait until it arrives. The program's main thread must be allowed to get back to the main loop and start asking for user input again. How NemoFile is used to do this The NemoFile class presents an API for scheduling this asynchronous I/O and dealing with the uncertainty of when the information will be available. (It also does a few other things, but that's the main service it provides.) When you want information about a particular file or directory, you get the NemoFile object for that item using nemo_file_get. This operation, like most NemoFile operations, is not allowed to do any disk I/O. Once you have a NemoFile object, you can ask it questions like "What is your file type?" by calling functions like nemo_file_get_file_type. However, for a newly created NemoFile object the answer is almost certainly "I don't know." Each function defines a default, which is the answer given for "I don't know." For example, nemo_file_get_type will return GNOME_VFS_FILE_TYPE_UNKNOWN if it doesn't yet know the type. It's worth taking a side trip to discuss the nature of the NemoFile API. Since these classes are a private part of the Nemo implementation, we make no effort to have the API be "complete" in an abstract sense. Instead we add operations as necessary and give them the semantics that are most handy for our purposes. For example, we could have a nemo_file_get_size that returns a special distinguishable value to mean "I don't know" or a separate boolean instead of returning 0 for files where the size is unknown. This is entirely motivated by pragmatic concerns. The intent is that we tweak these calls as needed if the semantics aren't good enough. Back to the newly created NemoFile object. If you actually need to get the type, you need to arrange for that information to be fetched from the file system. There are two ways to make this request. If you are planning to display the type on an ongoing basis then you want to tell the NemoFile that you'll be monitoring the file's type and want to know about changes to it. If you just need one-time information about the type then you'll want to be informed when the type is discovered. The calls used for this are nemo_file_monitor_add and nemo_file_call_when_ready respectively. Both of these calls take a list of information needed about a file. If all you need is the file type, for example, you would pass a list containing just NEMO_FILE_ATTRIBUTE_FILE_TYPE (the attributes are defined in nemo-file-attributes.h). Not every call has a corresponding file attribute type. We add new ones as needed. If you do a nemo_file_monitor_add, you also typically connect to the NemoFile object's changed signal. Each time any monitored attribute changes, a changed signal is emitted. The caller typically caches the value of the attribute that was last seen (for example, what's displayed on screen) and does a quick check to see if the attribute it cares about has changed. If you do a nemo_file_call_when_ready, you don't typically need to connect to the changed signal, because your callback function will be called when and if the requested information is ready. Both a monitor and a callback can be cancelled. For ease of use, neither requires that you store an ID for canceling. Instead, the monitor function uses an arbitrary client pointer, which can be any kind of pointer that's known to not conflict with other monitorers. Usually, this is a pointer to the monitoring object, but it can also be, for example, a pointer to a global variable. The call_when_ready function uses the callback function and callback data to identify the particular callback to cancel. One advantage of the monitor API is that it also lets the NemoFile framework know that the file should be monitored for changes made outside Nemo. This is how we know when to ask FAM to monitor a file or directory for us. Lets review a few of the concepts: 1) Nearly all NemoFile operations, like nemo_file_get_type, are not allowed to do any disk I/O. 2) To cause the actual I/O to be done, callers need to use set up either a monitor or a callback. 3) The actual I/O is done by asynchronous gnome-vfs calls, so the work is done on another thread. To work with an entire directory of files at once, you use a NemoDirectory object. With the NemoDirectory object you can monitor a whole set of NemoFile objects at once, and you can connect to a single "files_changed" signal that gets emitted whenever files within the directory are modified. That way you don't have to connect separately to each file you want to monitor. These calls are also the mechanism for finding out which files are in a directory. In most other respects, they are like the NemoFile calls. Caching, the good and the bad Another feature of the NemoFile class is the caching. If you keep around a NemoFile object, it keeps around information about the last known state of that file. Thus, if you call nemo_file_get_type, you might well get file type of the file found at this location the last time you looked, rather than the information about what the file type is now, or "unknown". There are some problems with this, though. The first problem is that if wrong information is cached, you need some way to "goose" the NemoFile object and get it to grab new information. This is trickier than it might sound, because we don't want to constantly distrust information we received just moments before. To handle this, we have the nemo_file_invalidate_attributes and nemo_file_invalidate_all_attributes calls, as well as the nemo_directory_force_reload call. If some code in Nemo makes a change to a file that's known to affect the cached information, it can call one of these to inform the NemoFile framework. Changes that are made through the framework itself are automatically understood, so usually these calls aren't necessary. The second problem is that it's hard to predict when information will and won't be cached. The current rule that's implemented is that no information is cached if no one retains a reference to the NemoFile object. This means that someone else holding a NemoFile object can subtly affect the semantics of whether you have new data or not. Calling nemo_file_call_when_ready or nemo_file_monitor_add will not invalidate the cache, but rather will return you the already cached information. These problems are less pronounced when FAM is in use. With FAM, any monitored file is highly likely to have accurate information, because changes to the file will be noticed by FAM, and that in turn will trigger new I/O to determine what the new status of the file is. Operations that change the file You'll note that up until this point, I've only discussed getting information about the file, not making changes to it. NemoFile also contains some APIs for making changes. There are two kinds of these. The calls that change metadata are examples of the first kind. These calls make changes to the internal state right away and schedule I/O to write the changes out to the file system. There's no way to detect if the I/O succeeds or fails, and as far as the client code is concerned the change takes place right away. The calls that make other kinds of file system change are examples of of the second kind. These calls take a NemoFileOperationCallback. They are all cancellable, and they give a callback when the operation completes, whether it succeeds or fails. Files that move When a file is moved, and the NemoFile framework knows it, then the NemoFile and NemoDirectory objects follow the file rather than staying stuck to the path. This has a direct influence on the user interface of Nemo -- if you move a directory, already-open windows and property windows will follow the directory around. This means that keeping around a NemoFile object and keeping around a URI for a file have different semantics, and there are cases where one is the better choice and cases where the other is. Icons The current implementation of the Nemo icon factory uses synchronous I/O to get the icons and ignores these guidelines. The only reason this doesn't ruin the Nemo user experience is that it also refuses to even try to fetch icons from URIs that don't correspond to file system paths, which for most cases means it limits itself to reading from the high-speed local disk. Don't ask me what the repercussions of this are for NFS; do the research and tell me instead! Slowness caused by asynchronous operations One danger in all this asynchronous I/O is that you might end up doing repeated drawing and updating. If you go to display a file right after asking for information about it, you might immediately show an "unknown file type" icon. Then, milliseconds later, you may complete the I/O and discover more information about the file, including the appropriate icon. So you end up drawing the icon twice. There are a number of strategies for preventing this problem. One of them is to allow a bit of hysteresis and wait some fixed amount of time after requesting the I/O before displaying the "unknown" state. One strategy that's used in Nemo is to wait until some basic information is available until displaying anything. This might make the program overall be faster, but it might make it seem slower, because you don't see things right away. [What other strategies are used in Nemo now for this?] How to make Nemo slow If you add I/O to the functions in NemoFile that are used simply to fetch cached file information, you can make Nemo incredibly I/O intensive. On the other hand, the NemoFile API does not provide a way to do arbitrary file reads, for example. So it can be tricky to add features to Nemo, since you first have to educate NemoFile about how to do the I/O asynchronously and cache it, then request the information and have some way to deal with the time when it's not yet known. Adding new kinds of I/O usually involves working on the Nemo I/O state machine in nemo-directory-async.c. If we changed Nemo to use threading instead of using gnome-vfs asychronous operations, I'm pretty sure that most of the changes would be here in this file. That's because the external API used for NemoFile wouldn't really have a reason to change. In either case, you'd want to schedule work to be done, and get called back when the work is complete. [We probably need more about nemo-directory-async.c here.] Future direction Some have suggested that by using threading directly in Nemo rather than using it indirectly through the gnome-vfs async. calls, we could simplify the I/O code in Nemo. It's possible this would make a big improvement, but it's also possible that this would primarily affect the internals and implementation details of NemoFile and still leave the rest of the Nemo code the same. That's all for now This is a very rough early draft of this document. Let me know about other topics that would be useful to be covered in here. -- Darin nemo-4.4.2/docs/nemo.1000066400000000000000000000036531357442400300144400ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH Nemo 1 "October 2012" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME nemo \- the Cinnamon File Manager .SH SYNOPSIS .B nemo .RI [ options ] " URIs" ... .br .SH DESCRIPTION This manual page documents briefly the .B nemo command. .PP Nemo is the file manager for the Cinnamon desktop. .br .SH OPTIONS Nemo follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP .B \-c .TP .B \-\-check Perform a quick set of self-check tests. .TP .B \-g .TP .B \-\-geometry=\fIGEOMETRY\fR Create the initial window with the given geometry. .TP \fB\-t .TP .B \-\-tabs\fR Open URIs in tabs. .TP .B \-n .TP .B \-\-no-default-window Only create windows for explicitly specified URIs. .TP .B \-\-no-desktop Ignored - left for compatibility only. .TP .B \-\-fix-cache Repair the user thumbnail cache - this can be useful if you're having trouble with file thumbnails. Must be run as root. .TP .B \-q .TP .B \-\-quit Quit Nemo. .TP .B \-\-help Show a summary of options. .TP .B \-\-version Show Nemo' version. .TP Other standard GNOME options not listed here are also supported. .SH AUTHOR This manual page was originally written for Nautilus by Takuo KITAME and Dafydd Harries for the Debian GNU/Linux system (but may be used by others). nemo-4.4.2/docs/reference/000077500000000000000000000000001357442400300153475ustar00rootroot00000000000000nemo-4.4.2/docs/reference/libnemo-extension/000077500000000000000000000000001357442400300210065ustar00rootroot00000000000000nemo-4.4.2/docs/reference/libnemo-extension/libnemo-extension-docs.xml000066400000000000000000000024751357442400300261250ustar00rootroot00000000000000 ]> Nemo Extension Reference Manual For Nemo-Extension &version; API Reference Extension Interfaces Classes Index nemo-4.4.2/docs/reference/libnemo-extension/libnemo-extension-overrides.txt000066400000000000000000000000001357442400300271740ustar00rootroot00000000000000nemo-4.4.2/docs/reference/libnemo-extension/libnemo-extension-sections.txt000066400000000000000000000074671357442400300270510ustar00rootroot00000000000000
nemo-location-widget-provider NemoLocationWidgetProvider NemoLocationWidgetProviderInterface nemo_location_widget_provider_get_widget
nemo-menu-provider NemoMenuProvider NemoMenuProviderInterface nemo_menu_provider_get_file_items nemo_menu_provider_get_background_items nemo_menu_provider_emit_items_updated_signal
nemo-menu NEMO_TYPE_MENU_ITEM NEMO_MENU_ITEM NEMO_MENU_ITEM_CLASS NEMO_MENU_IS_ITEM NEMO_MENU_IS_ITEM_CLASS NEMO_MENU_ITEM_GET_CLASS NemoMenuPrivate NemoMenuItemDetails NemoMenu NemoMenu NemoMenuItem NemoMenuItem nemo_menu_new nemo_menu_append_item nemo_menu_get_items nemo_menu_item_list_free nemo_menu_item_get_type nemo_menu_item_new nemo_menu_item_activate nemo_menu_item_set_submenu NEMO_MENU NEMO_IS_MENU NEMO_TYPE_MENU nemo_menu_get_type NEMO_MENU_CLASS NEMO_IS_MENU_CLASS NEMO_MENU_GET_CLASS
nemo-column-provider NemoColumnProvider NemoColumnProviderInterface nemo_column_provider_get_columns
nemo-name-and-desc-provider NemoNameAndDescProvider NemoNameAndDescProviderInterface nemo_name_and_desc_provider_get_name_and_desc
nemo-property-page-provider NemoPropertyPageProvider NemoPropertyPageProviderInterface nemo_property_page_provider_get_pages
nemo-file-info NEMO_FILE_DEFINED NemoFile NemoFileInfo NemoFileInfoIface nemo_file_info_create nemo_file_info_create_for_uri nemo_file_info_getter nemo_file_info_lookup nemo_file_info_lookup_for_uri nemo_file_info_list_copy nemo_file_info_list_free nemo_file_info_is_gone nemo_file_info_get_file_type nemo_file_info_get_location nemo_file_info_get_name nemo_file_info_get_uri nemo_file_info_get_activation_uri nemo_file_info_get_parent_location nemo_file_info_get_parent_uri nemo_file_info_get_mount nemo_file_info_get_uri_scheme nemo_file_info_get_parent_info nemo_file_info_get_mime_type nemo_file_info_is_mime_type nemo_file_info_is_directory nemo_file_info_can_write nemo_file_info_add_emblem nemo_file_info_get_string_attribute nemo_file_info_add_string_attribute nemo_file_info_invalidate_extension_info NEMO_FILE_INFO NEMO_IS_FILE_INFO NEMO_TYPE_FILE_INFO nemo_file_info_get_type NEMO_FILE_INFO_GET_IFACE
nemo-column NemoColumnDetails NemoColumn NemoColumn nemo_column_new NEMO_COLUMN NEMO_IS_COLUMN NEMO_TYPE_COLUMN nemo_column_get_type NEMO_COLUMN_CLASS NEMO_IS_COLUMN_CLASS NEMO_COLUMN_GET_CLASS
nemo-info-provider NemoInfoProvider NemoInfoProviderInterface NemoInfoProviderUpdateComplete nemo_info_provider_update_file_info nemo_info_provider_cancel_update nemo_info_provider_update_complete_invoke
nemo-property-page NemoPropertyPageDetails NemoPropertyPage NemoPropertyPage nemo_property_page_new NEMO_PROPERTY_PAGE NEMO_IS_PROPERTY_PAGE NEMO_TYPE_PROPERTY_PAGE nemo_property_page_get_type NEMO_PROPERTY_PAGE_CLASS NEMO_IS_PROPERTY_PAGE_CLASS NEMO_PROPERTY_PAGE_GET_CLASS
nemo-extension-types NemoOperationHandle NemoOperationResult nemo_module_initialize nemo_module_shutdown nemo_module_list_types
nemo-menu-item
nemo-simple-button NemoSimpleButton NemoSimpleButton nemo_simple_button_new nemo_simple_button_new_from_icon_name nemo_simple_button_new_from_stock nemo_simple_button_new_from_file NEMO_SIMPLE_BUTTON NEMO_IS_SIMPLE_BUTTON NEMO_TYPE_SIMPLE_BUTTON nemo_simple_button_get_type NEMO_SIMPLE_BUTTON_CLASS NEMO_IS_SIMPLE_BUTTON_CLASS NEMO_SIMPLE_BUTTON_GET_CLASS
nemo-4.4.2/docs/reference/libnemo-extension/meson.build000066400000000000000000000010501357442400300231440ustar00rootroot00000000000000 docConf = configuration_data() docConf.set('NEMO_EXTENSION_VERSION_INFO', NEMO_EXTENSION_VERSION_INFO) configure_file( input : 'version.xml.in', output: 'version.xml', configuration: docConf ) gnome.gtkdoc('libnemo-extension', main_xml: 'libnemo-extension-docs.xml', src_dir: join_paths(meson.source_root(), 'libnemo-extension'), dependencies: nemo_extension, install: true, gobject_typesfile: 'libnemo-extension.types', install_dir: 'libnemo-extension', scan_args: [ '--rebuild-types', '--ignore-headers="config.h"' ] ) nemo-4.4.2/docs/reference/libnemo-extension/version.xml.in000066400000000000000000000000361357442400300236210ustar00rootroot00000000000000@NEMO_EXTENSION_VERSION_INFO@ nemo-4.4.2/docs/reference/meson.build000066400000000000000000000000341357442400300175060ustar00rootroot00000000000000subdir('libnemo-extension') nemo-4.4.2/docs/style-guide.html000066400000000000000000000120601357442400300165310ustar00rootroot00000000000000 Nemo Coding Style Guide

To make code written for Nemo look and act in a predictable way, we follow a set of guidelines that specify some details of how we write code. To start, we follow all the guidelines outlined in the GNOME Programming Guidelines.

This document covers both things that are not mentioned in the GNOME Programming Guidelines and things that are mentioned there but need to be re-emphasized because people don't follow them often enough.

I'm just getting started on this document. Feedback is welcome. Eventually I'd like better organization and tons of examples.

- Darin


We use the most-recommended coding style from the GNOME Programming Guidelines. This means that we use the Linux kernel brace style with 8-character tabs (not the GNU brace style), we put spaces before the parentheses that introduce function argument lists, we put the braces that open the block for an if statement on the same line as the if statement (part of Linux kernel brace style).

We prefer to use words rather than acronyms or abbreviations. This means that we name classes with a prefix like Nemo, not Ntl, for example. And we use variables named result rather than retval or rv.

We strive to have a minimum number of local variables. This makes it easier to move pieces of code around. For more on this, read Refactoring.

We use type casts as little as possible. There are many places in GTK programming where you have to cast to make the program work, but we do whatever we can to avoid this. Also, we prefer to cast data pointers, rather than casting function pointers, since there's so much more to get wrong with function pointer casts.

We use typedefs from <glib.h> for things like guint, guchar and gpointer, but not gint, gchar, or gdouble. Using these gives a false sense of portability. In all three cases, using system calls like printf requires knowing that these are the "real" int, char, and double, so there's no reason to use a typedef that's non-standard unless it's a shorter name or clearer in some way.

We avoid in-band signaling. This means that we avoid using special values to indicate errors, for example. This can lead to subtle bugs when a valid result is misinterpreted as an error, and can make it hard to tell if the code handles errors or not.

We code for clarity first. Other concerns like efficiency are secondary. Sometimes they become more important than clarity, but only once they are proven to be a problem.

We use for loops when they make the code easier to read. The alternative is usually to use a while loop. It's true that "easy to read" is a subjective thing.

We declare local variables at the beginning of a block. C99 allows you to declare variables anywhere in a function, but a lot of compilers still do not support C99.

We do not initialize local variables in their declarations. C allows you to initialize a local variable when declaring it. But no other code can run before this, because the other statements in a function must be after all the declarations. If there are lines of code initializing the variables in the declarations, it can be harder to change the function around, since code must move down from the declaration if other code needs to run after it. To avoid this, we just don't use the ability to initialize the variable when it's declared.

We always use braces, even for one-statement "blocks". Our consensus is to do things like this:

if (list != NULL) {
        g_warning ("the list isn't empty");
}

Instead of this:

if (list != NULL)
        g_warning ("the list isn't empty");

This applies to all control structures: if, while, for, do.

We make each header "stand alone". Our concept with C header files is that each one must be written so it can be included without including another file first. To test that the header files we develop have this property, we always include the corresponding header file first in each C source file. The only exception is the include of <config.h>, which goes first. Here's an example:

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
 *
 * nemo-icon-factory.c: Class for obtaining icons for files and other objects.
 *
 * Copyright (C) 1999, 2000 Red Hat Inc.
 * Copyright (C) 1999, 2000 Eazel, Inc.
 *
 * License agreement goes here.
 *
 * Author: John Sullivan <sullivan@eazel.com>
 */

#include <config.h>
#include "nemo-icon-factory.h"

#include <string.h>
#include <stdio.h>
Include statements for other header files go here.

Other declarations and code go here.

nemo-4.4.2/eel/000077500000000000000000000000001357442400300132265ustar00rootroot00000000000000nemo-4.4.2/eel/README000066400000000000000000000000351357442400300141040ustar00rootroot00000000000000README for eel/eel Writeme nemo-4.4.2/eel/check-eel000077500000000000000000000000731357442400300147740ustar00rootroot00000000000000#!/bin/sh ./check-program --g-fatal-warnings --sm-disable nemo-4.4.2/eel/check-program.c000066400000000000000000000032321357442400300161140ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* check-program.c: A simple driver for eel self checks. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ramiro Estrugo */ #include #include #include #include #include #include #include #include #include int main (int argc, char *argv[]) { #if !defined (EEL_OMIT_SELF_CHECK) eel_make_warnings_and_criticals_stop_in_debugger (); LIBXML_TEST_VERSION gtk_init (&argc, &argv); /* Run the checks for eel twice. */ eel_run_lib_self_checks (); eel_exit_if_self_checks_failed (); eel_run_lib_self_checks (); eel_exit_if_self_checks_failed (); eel_debug_shut_down (); #endif /* !EEL_OMIT_SELF_CHECK */ return EXIT_SUCCESS; } nemo-4.4.2/eel/eel-accessibility.c000066400000000000000000000217451357442400300167750ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-accessibility.h - Utility functions for accessibility Copyright (C) 2002 Anders Carlsson, Sun Microsystems, Inc. The Eel 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. The Eel 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 the Eel Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Anders Carlsson Michael Meeks */ #include #include #include void eel_accessibility_set_up_label_widget_relation (GtkWidget *label, GtkWidget *widget) { AtkObject *atk_widget, *atk_label; atk_label = gtk_widget_get_accessible (label); atk_widget = gtk_widget_get_accessible (widget); /* Create the label -> widget relation */ atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, atk_widget); /* Create the widget -> label relation */ atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, atk_label); } /* * Hacks to make re-using gail somewhat easier. */ /** * eel_accessibility_create_derived_type: * @type_name: the name for the new accessible type eg. NemoIconCanvasItemAccessible * @existing_gobject_with_proxy: the GType of an object that has a registered factory that * manufactures the type we want to inherit from. ie. to inherit from a GailCanvasItem * we need to pass GNOME_TYPE_CANVAS_ITEM - since GailCanvasItem is registered against * that type. * @opt_gail_parent_class: the name of the Gail class to derive from eg. GailCanvasItem * @class_init: the init function to run for this class * * This should be run to register the type, it can subsequently be run with * the same name and will not re-register it, but simply return it. * * NB. to do instance init, you prolly want to override AtkObject::initialize * * Return value: the registered type, or 0 on failure. **/ GType eel_accessibility_create_derived_type (const char *type_name, GType existing_gobject_with_proxy, EelAccessibilityClassInitFn class_init) { GType type; GType parent_atk_type; GTypeInfo tinfo = { 0 }; GTypeQuery query; AtkObjectFactory *factory; if ((type = g_type_from_name (type_name))) { return type; } factory = atk_registry_get_factory (atk_get_default_registry (), existing_gobject_with_proxy); if (!factory) { return G_TYPE_INVALID; } parent_atk_type = atk_object_factory_get_accessible_type (factory); if (!parent_atk_type) { return G_TYPE_INVALID; } /* * Figure out the size of the class and instance * we are deriving from */ g_type_query (parent_atk_type, &query); if (class_init) { tinfo.class_init = (GClassInitFunc) class_init; } tinfo.class_size = query.class_size; tinfo.instance_size = query.instance_size; /* Register the type */ type = g_type_register_static ( parent_atk_type, type_name, &tinfo, 0); return type; } static GQuark get_quark_accessible (void) { static GQuark quark_accessible_object = 0; if (!quark_accessible_object) { quark_accessible_object = g_quark_from_static_string ("accessible-object"); } return quark_accessible_object; } static GQuark get_quark_gobject (void) { static GQuark quark_accessible_gobject = 0; if (!quark_accessible_gobject) { quark_accessible_gobject = g_quark_from_static_string ("object-for-accessible"); } return quark_accessible_gobject; } /** * eel_accessibility_get_atk_object: * @object: a GObject of some sort * * gets an AtkObject associated with a GObject * * Return value: the associated accessible if one exists or NULL **/ AtkObject * eel_accessibility_get_atk_object (gpointer object) { return g_object_get_qdata (object, get_quark_accessible ()); } /** * eel_accessibilty_for_object: * @object: a GObject of some sort * * gets an AtkObject associated with a GObject and if it doesn't * exist creates a suitable accessible object. * * Return value: an associated accessible. **/ AtkObject * eel_accessibility_for_object (gpointer object) { if (GTK_IS_WIDGET (object)) return gtk_widget_get_accessible (object); return atk_gobject_accessible_for_object (object); } /** * eel_accessibility_get_gobject: * @object: an AtkObject * * gets the GObject associated with the AtkObject, for which * @object provides accessibility support. * * Return value: the accessible's associated GObject **/ gpointer eel_accessibility_get_gobject (AtkObject *object) { return g_object_get_qdata (G_OBJECT (object), get_quark_gobject ()); } static void eel_accessibility_destroy (gpointer data) { g_object_set_qdata (G_OBJECT (data), get_quark_gobject (), NULL); atk_object_notify_state_change (ATK_OBJECT (data), ATK_STATE_DEFUNCT, TRUE); g_object_unref (data); } /** * eel_accessibility_set_atk_object_return: * @object: a GObject * @atk_object: it's AtkObject * * used to register and return a new accessible object for something * * Return value: @atk_object. **/ AtkObject * eel_accessibility_set_atk_object_return (gpointer object, AtkObject *atk_object) { atk_object_initialize (atk_object, object); if (!ATK_IS_GOBJECT_ACCESSIBLE (atk_object)) { g_object_set_qdata_full (object, get_quark_accessible (), atk_object, eel_accessibility_destroy); g_object_set_qdata (G_OBJECT (atk_object), get_quark_gobject (), object); } return atk_object; } static GailTextUtil * get_simple_text (gpointer object) { GObject *gobject; EelAccessibleTextIface *aif; if (GTK_IS_ACCESSIBLE (object)) { gobject = G_OBJECT (gtk_accessible_get_widget (GTK_ACCESSIBLE (object))); } else { gobject = eel_accessibility_get_gobject (object); } if (!gobject) { return NULL; } aif = EEL_ACCESSIBLE_TEXT_GET_IFACE (gobject); if (!aif) { g_warning ("No accessible text inferface on '%s'", g_type_name_from_instance ((gpointer) gobject)); } else if (aif->get_text) { return aif->get_text (gobject); } return NULL; } char * eel_accessibility_text_get_text (AtkText *text, gint start_pos, gint end_pos) { GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, NULL); return gail_text_util_get_substring (util, start_pos, end_pos); } gunichar eel_accessibility_text_get_character_at_offset (AtkText *text, gint offset) { char *txt, *index; gint sucks1 = 0, sucks2 = -1; gunichar c; GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, 0); txt = gail_text_util_get_substring (util, sucks1, sucks2); index = g_utf8_offset_to_pointer (txt, offset); c = g_utf8_get_char (index); g_free (txt); return c; } char * eel_accessibility_text_get_text_before_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, NULL); return gail_text_util_get_text ( util, NULL, GAIL_BEFORE_OFFSET, boundary_type, offset, start_offset, end_offset); } char * eel_accessibility_text_get_text_at_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, NULL); return gail_text_util_get_text ( util, NULL, GAIL_AT_OFFSET, boundary_type, offset, start_offset, end_offset); } gchar* eel_accessibility_text_get_text_after_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, NULL); return gail_text_util_get_text ( util, NULL, GAIL_AFTER_OFFSET, boundary_type, offset, start_offset, end_offset); } gint eel_accessibility_text_get_character_count (AtkText *text) { GailTextUtil *util = get_simple_text (text); g_return_val_if_fail (util != NULL, -1); return gtk_text_buffer_get_char_count (util->buffer); } GType eel_accessible_text_get_type (void) { static GType type = 0; if (!type) { const GTypeInfo tinfo = { sizeof (AtkTextIface), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) NULL, (GClassFinalizeFunc) NULL }; type = g_type_register_static ( G_TYPE_INTERFACE, "EelAccessibleText", &tinfo, 0); } return type; } nemo-4.4.2/eel/eel-accessibility.h000066400000000000000000000114211357442400300167700ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-accessibility.h - Utility functions for accessibility Copyright (C) 2002 Anders Carlsson The Eel 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. The Eel 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 the Eel Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Anders Carlsson */ #ifndef EEL_ACCESSIBILITY_H #define EEL_ACCESSIBILITY_H #include #include #include #include void eel_accessibility_set_up_label_widget_relation (GtkWidget *label, GtkWidget *widget); typedef void (*EelAccessibilityClassInitFn) (AtkObjectClass *klass); AtkObject *eel_accessibility_get_atk_object (gpointer object); AtkObject *eel_accessibility_for_object (gpointer object); gpointer eel_accessibility_get_gobject (AtkObject *object); AtkObject *eel_accessibility_set_atk_object_return (gpointer object, AtkObject *atk_object); GType eel_accessibility_create_derived_type (const char *type_name, GType existing_gobject_with_proxy, EelAccessibilityClassInitFn class_init); char* eel_accessibility_text_get_text (AtkText *text, gint start_pos, gint end_pos); gunichar eel_accessibility_text_get_character_at_offset (AtkText *text, gint offset); char* eel_accessibility_text_get_text_before_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); char* eel_accessibility_text_get_text_at_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); char* eel_accessibility_text_get_text_after_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); gint eel_accessibility_text_get_character_count (AtkText *text); #define EEL_TYPE_ACCESSIBLE_TEXT (eel_accessible_text_get_type ()) #define EEL_IS_ACCESSIBLE_TEXT(obj) G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_ACCESSIBLE_TEXT) #define EEL_ACCESSIBLE_TEXT(obj) G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_ACCESSIBLE_TEXT, EelAccessibleText) #define EEL_ACCESSIBLE_TEXT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EEL_TYPE_ACCESSIBLE_TEXT, EelAccessibleTextIface)) /* Instead of implementing the AtkText interface, implement this */ typedef struct _EelAccessibleText EelAccessibleText; typedef struct { GTypeInterface parent; GailTextUtil *(*get_text) (GObject *text); PangoLayout *(*get_layout) (GObject *text); } EelAccessibleTextIface; GType eel_accessible_text_get_type (void); #endif /* EEL_ACCESSIBILITY_H */ nemo-4.4.2/eel/eel-art-extensions.c000066400000000000000000000106201357442400300171170ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-art-extensions.c - implementation of libart extension functions. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler Ramiro Estrugo */ #include #include "eel-art-extensions.h" #include "eel-lib-self-check-functions.h" #include const EelDRect eel_drect_empty = { 0.0, 0.0, 0.0, 0.0 }; const EelIRect eel_irect_empty = { 0, 0, 0, 0 }; void eel_irect_copy (EelIRect *dest, const EelIRect *src) { dest->x0 = src->x0; dest->y0 = src->y0; dest->x1 = src->x1; dest->y1 = src->y1; } void eel_irect_union (EelIRect *dest, const EelIRect *src1, const EelIRect *src2) { if (eel_irect_is_empty (src1)) { eel_irect_copy (dest, src2); } else if (eel_irect_is_empty (src2)) { eel_irect_copy (dest, src1); } else { dest->x0 = MIN (src1->x0, src2->x0); dest->y0 = MIN (src1->y0, src2->y0); dest->x1 = MAX (src1->x1, src2->x1); dest->y1 = MAX (src1->y1, src2->y1); } } void eel_irect_intersect (EelIRect *dest, const EelIRect *src1, const EelIRect *src2) { dest->x0 = MAX (src1->x0, src2->x0); dest->y0 = MAX (src1->y0, src2->y0); dest->x1 = MIN (src1->x1, src2->x1); dest->y1 = MIN (src1->y1, src2->y1); } gboolean eel_irect_is_empty (const EelIRect *src) { return (src->x1 <= src->x0 || src->y1 <= src->y0); } /** * eel_irect_get_width: * * @rectangle: An EelIRect. * * Returns: The width of the rectangle. * */ int eel_irect_get_width (EelIRect rectangle) { return rectangle.x1 - rectangle.x0; } /** * eel_irect_get_height: * * @rectangle: An EelIRect. * * Returns: The height of the rectangle. * */ int eel_irect_get_height (EelIRect rectangle) { return rectangle.y1 - rectangle.y0; } static void eel_drect_copy (EelDRect *dest, const EelDRect *src) { dest->x0 = src->x0; dest->y0 = src->y0; dest->x1 = src->x1; dest->y1 = src->y1; } static gboolean eel_drect_is_empty (const EelDRect *src) { return (src->x1 <= src->x0 || src->y1 <= src->y0); } void eel_drect_union (EelDRect *dest, const EelDRect *src1, const EelDRect *src2) { if (eel_drect_is_empty (src1)) { eel_drect_copy (dest, src2); } else if (eel_drect_is_empty (src2)) { eel_drect_copy (dest, src1); } else { dest->x0 = MIN (src1->x0, src2->x0); dest->y0 = MIN (src1->y0, src2->y0); dest->x1 = MAX (src1->x1, src2->x1); dest->y1 = MAX (src1->y1, src2->y1); } } /** * eel_irect_contains_point: * * @rectangle: An EelIRect. * @x: X coordinate to test. * @y: Y coordinate to test. * * Returns: A boolean value indicating whether the rectangle * contains the x,y coordinate. * */ gboolean eel_irect_contains_point (EelIRect rectangle, int x, int y) { return x >= rectangle.x0 && x <= rectangle.x1 && y >= rectangle.y0 && y <= rectangle.y1; } gboolean eel_irect_hits_irect (EelIRect rectangle_a, EelIRect rectangle_b) { EelIRect intersection; eel_irect_intersect (&intersection, &rectangle_a, &rectangle_b); return !eel_irect_is_empty (&intersection); } gboolean eel_irect_equal (EelIRect rectangle_a, EelIRect rectangle_b) { return rectangle_a.x0 == rectangle_b.x0 && rectangle_a.y0 == rectangle_b.y0 && rectangle_a.x1 == rectangle_b.x1 && rectangle_a.y1 == rectangle_b.y1; } EelIRect eel_irect_offset_by (EelIRect rectangle, int x, int y) { rectangle.x0 += x; rectangle.x1 += x; rectangle.y0 += y; rectangle.y1 += y; return rectangle; } EelIRect eel_irect_scale_by (EelIRect rectangle, double scale) { rectangle.x0 *= scale; rectangle.x1 *= scale; rectangle.y0 *= scale; rectangle.y1 *= scale; return rectangle; } nemo-4.4.2/eel/eel-art-extensions.h000066400000000000000000000050661357442400300171340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-art-extensions.h - interface of libart extension functions. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler Ramiro Estrugo */ #ifndef EEL_ART_EXTENSIONS_H #define EEL_ART_EXTENSIONS_H #include G_BEGIN_DECLS typedef struct { double x0, y0, x1, y1; } EelDRect; typedef struct { /*< public >*/ int x0, y0, x1, y1; } EelIRect; extern const EelDRect eel_drect_empty; extern const EelIRect eel_irect_empty; void eel_irect_copy (EelIRect *dest, const EelIRect *src); void eel_irect_union (EelIRect *dest, const EelIRect *src1, const EelIRect *src2); void eel_irect_intersect (EelIRect *dest, const EelIRect *src1, const EelIRect *src2); gboolean eel_irect_equal (EelIRect rectangle_a, EelIRect rectangle_b); gboolean eel_irect_hits_irect (EelIRect rectangle_a, EelIRect rectangle_b); EelIRect eel_irect_offset_by (EelIRect rectangle, int x, int y); EelIRect eel_irect_scale_by (EelIRect rectangle, double scale); gboolean eel_irect_is_empty (const EelIRect *rectangle); gboolean eel_irect_contains_point (EelIRect outer_rectangle, int x, int y); int eel_irect_get_width (EelIRect rectangle); int eel_irect_get_height (EelIRect rectangle); void eel_drect_union (EelDRect *dest, const EelDRect *src1, const EelDRect *src2); G_END_DECLS #endif /* EEL_ART_EXTENSIONS_H */ nemo-4.4.2/eel/eel-canvas.c000066400000000000000000003415711357442400300154230ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ /* * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation * All rights reserved. * * This file is part of the Gnome Library. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ /* @NOTATION@ */ /* * EelCanvas widget - Tk-like canvas widget for Gnome * * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. * * * Authors: Federico Mena * Raph Levien */ /* * TO-DO list for the canvas: * * - Allow to specify whether EelCanvasImage sizes are in units or pixels (scale or don't scale). * * - Implement a flag for eel_canvas_item_reparent() that tells the function to keep the item * visually in the same place, that is, to keep it in the same place with respect to the canvas * origin. * * - GC put functions for items. * * - Widget item (finish it). * * - GList *eel_canvas_gimme_all_items_contained_in_this_area (EelCanvas *canvas, Rectangle area); * * - Retrofit all the primitive items with microtile support. * * - Curve support for line item. * * - Arc item (Havoc has it; to be integrated in EelCanvasEllipse). * * - Sane font handling API. * * - Get_arg methods for items: * - How to fetch the outline width and know whether it is in pixels or units? */ #include #include #include #include #include #include #include #include #include "eel-canvas.h" static void eel_canvas_request_update (EelCanvas *canvas); static void group_add (EelCanvasGroup *group, EelCanvasItem *item); static void group_remove (EelCanvasGroup *group, EelCanvasItem *item); static void redraw_and_repick_if_mapped (EelCanvasItem *item); /*** EelCanvasItem ***/ /* Some convenience stuff */ #define GCI_UPDATE_MASK (EEL_CANVAS_UPDATE_REQUESTED | EEL_CANVAS_UPDATE_DEEP) #define GCI_EPSILON 1e-18 enum { ITEM_PROP_0, ITEM_PROP_PARENT, ITEM_PROP_VISIBLE }; enum { ITEM_DESTROY, ITEM_EVENT, ITEM_LAST_SIGNAL }; static void eel_canvas_item_class_init (EelCanvasItemClass *klass); static void eel_canvas_item_init (EelCanvasItem *item); static int emit_event (EelCanvas *canvas, GdkEvent *event); static guint item_signals[ITEM_LAST_SIGNAL] = { 0 }; static GObjectClass *item_parent_class; static gpointer accessible_item_parent_class; static gpointer accessible_parent_class; /** * eel_canvas_item_get_type: * * Registers the &EelCanvasItem class if necessary, and returns the type ID * associated to it. * * Return value: The type ID of the &EelCanvasItem class. **/ GType eel_canvas_item_get_type (void) { static GType canvas_item_type = 0; if (!canvas_item_type) { static const GTypeInfo canvas_item_info = { sizeof (EelCanvasItemClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eel_canvas_item_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EelCanvasItem), 0, /* n_preallocs */ (GInstanceInitFunc) eel_canvas_item_init }; canvas_item_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, "EelCanvasItem", &canvas_item_info, 0); } return canvas_item_type; } /* Object initialization function for EelCanvasItem */ static void eel_canvas_item_init (EelCanvasItem *item) { item->flags |= EEL_CANVAS_ITEM_VISIBLE; } /** * eel_canvas_item_new: * @parent: The parent group for the new item. * @type: The object type of the item. * @first_arg_name: A list of object argument name/value pairs, NULL-terminated, * used to configure the item. For example, "fill_color", "black", * "width_units", 5.0, NULL. * @Varargs: * * Creates a new canvas item with @parent as its parent group. The item is * created at the top of its parent's stack, and starts up as visible. The item * is of the specified @type, for example, it can be * eel_canvas_rect_get_type(). The list of object arguments/value pairs is * used to configure the item. * * Return value: The newly-created item. **/ EelCanvasItem * eel_canvas_item_new (EelCanvasGroup *parent, GType type, const gchar *first_arg_name, ...) { EelCanvasItem *item; va_list args; g_return_val_if_fail (EEL_IS_CANVAS_GROUP (parent), NULL); g_return_val_if_fail (g_type_is_a (type, eel_canvas_item_get_type ()), NULL); item = EEL_CANVAS_ITEM (g_object_new (type, NULL)); va_start (args, first_arg_name); eel_canvas_item_construct (item, parent, first_arg_name, args); va_end (args); return item; } /* Performs post-creation operations on a canvas item (adding it to its parent * group, etc.) */ static void item_post_create_setup (EelCanvasItem *item) { group_add (EEL_CANVAS_GROUP (item->parent), item); redraw_and_repick_if_mapped (item); } /* Set_property handler for canvas items */ static void eel_canvas_item_set_property (GObject *gobject, guint param_id, const GValue *value, GParamSpec *pspec) { EelCanvasItem *item; g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject)); item = EEL_CANVAS_ITEM (gobject); switch (param_id) { case ITEM_PROP_PARENT: if (item->parent != NULL) { g_warning ("Cannot set `parent' argument after item has " "already been constructed."); } else if (g_value_get_object (value)) { item->parent = EEL_CANVAS_ITEM (g_value_get_object (value)); item->canvas = item->parent->canvas; item_post_create_setup (item); } break; case ITEM_PROP_VISIBLE: if (g_value_get_boolean (value)) { eel_canvas_item_show (item); } else { eel_canvas_item_hide (item); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); break; } } /* Get_property handler for canvas items */ static void eel_canvas_item_get_property (GObject *gobject, guint param_id, GValue *value, GParamSpec *pspec) { EelCanvasItem *item; g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject)); item = EEL_CANVAS_ITEM (gobject); switch (param_id) { case ITEM_PROP_VISIBLE: g_value_set_boolean (value, item->flags & EEL_CANVAS_ITEM_VISIBLE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); break; } } /** * eel_canvas_item_construct: * @item: An unconstructed canvas item. * @parent: The parent group for the item. * @first_arg_name: The name of the first argument for configuring the item. * @args: The list of arguments used to configure the item. * * Constructs a canvas item; meant for use only by item implementations. **/ void eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent, const gchar *first_arg_name, va_list args) { g_return_if_fail (EEL_IS_CANVAS_GROUP (parent)); g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); item->parent = EEL_CANVAS_ITEM (parent); item->canvas = item->parent->canvas; g_object_set_valist (G_OBJECT (item), first_arg_name, args); item_post_create_setup (item); } static void redraw_and_repick_if_mapped (EelCanvasItem *item) { if (item->flags & EEL_CANVAS_ITEM_MAPPED) { eel_canvas_item_request_redraw (item); item->canvas->need_repick = TRUE; } } /* Dispose handler for canvas items */ static void eel_canvas_item_dispose (GObject *object) { EelCanvasItem *item; g_return_if_fail (EEL_IS_CANVAS_ITEM (object)); item = EEL_CANVAS_ITEM (object); if (item->canvas) { eel_canvas_item_request_redraw (item); /* Make the canvas forget about us */ if (item == item->canvas->current_item) { item->canvas->current_item = NULL; item->canvas->need_repick = TRUE; } if (item == item->canvas->new_current_item) { item->canvas->new_current_item = NULL; item->canvas->need_repick = TRUE; } eel_canvas_item_ungrab (item, GDK_CURRENT_TIME); if (item == item->canvas->focused_item) item->canvas->focused_item = NULL; /* Normal destroy stuff */ if (item->flags & EEL_CANVAS_ITEM_MAPPED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); if (item->flags & EEL_CANVAS_ITEM_REALIZED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item); if (item->parent) group_remove (EEL_CANVAS_GROUP (item->parent), item); item->canvas = NULL; } g_object_set_data (object, "in-destruction", GINT_TO_POINTER (1)); g_signal_emit (object, item_signals[ITEM_DESTROY], 0); g_object_set_data (object, "in-destruction", NULL); G_OBJECT_CLASS (item_parent_class)->dispose (object); } void eel_canvas_item_destroy (EelCanvasItem *item) { if (g_object_get_data (G_OBJECT (item), "in-destruction") == NULL) { g_object_run_dispose (G_OBJECT (item)); } } /* Realize handler for canvas items */ static void eel_canvas_item_realize (EelCanvasItem *item) { if (item->parent && !(item->parent->flags & EEL_CANVAS_ITEM_REALIZED)) (* EEL_CANVAS_ITEM_GET_CLASS (item->parent)->realize) (item->parent); if (item->parent == NULL && !gtk_widget_get_realized (GTK_WIDGET (item->canvas))) gtk_widget_realize (GTK_WIDGET (item->canvas)); item->flags |= EEL_CANVAS_ITEM_REALIZED; eel_canvas_item_request_update (item); } /* Unrealize handler for canvas items */ static void eel_canvas_item_unrealize (EelCanvasItem *item) { if (item->flags & EEL_CANVAS_ITEM_MAPPED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); item->flags &= ~(EEL_CANVAS_ITEM_REALIZED); } /* Map handler for canvas items */ static void eel_canvas_item_map (EelCanvasItem *item) { item->flags |= EEL_CANVAS_ITEM_MAPPED; } /* Unmap handler for canvas items */ static void eel_canvas_item_unmap (EelCanvasItem *item) { item->flags &= ~(EEL_CANVAS_ITEM_MAPPED); } /* Update handler for canvas items */ static void eel_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) { item->flags &= ~(EEL_CANVAS_ITEM_NEED_UPDATE); item->flags &= ~(EEL_CANVAS_ITEM_NEED_DEEP_UPDATE); } /* * This routine invokes the update method of the item * Please notice, that we take parent to canvas pixel matrix as argument * unlike virtual method ::update, whose argument is item 2 canvas pixel * matrix * * I will try to force somewhat meaningful naming for affines (Lauris) * General naming rule is FROM2TO, where FROM and TO are abbreviations * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel * I hope that this helps to keep track of what really happens * */ static void eel_canvas_item_invoke_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) { int child_flags; child_flags = flags; /* apply object flags to child flags */ child_flags &= ~EEL_CANVAS_UPDATE_REQUESTED; if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE) child_flags |= EEL_CANVAS_UPDATE_REQUESTED; if (item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE) child_flags |= EEL_CANVAS_UPDATE_DEEP; if (child_flags & GCI_UPDATE_MASK) { if (EEL_CANVAS_ITEM_GET_CLASS (item)->update) EEL_CANVAS_ITEM_GET_CLASS (item)->update (item, i2w_dx, i2w_dy, child_flags); } /* If this fail you probably forgot to chain up to * EelCanvasItem::update from a derived class */ g_return_if_fail (!(item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)); } /* * This routine invokes the point method of the item. * The arguments x, y should be in the parent item local coordinates. */ static double eel_canvas_item_invoke_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) { /* Calculate x & y in item local coordinates */ if (EEL_CANVAS_ITEM_GET_CLASS (item)->point) return EEL_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item); return 1e18; } /** * eel_canvas_item_set: * @item: A canvas item. * @first_arg_name: The list of object argument name/value pairs used to configure the item. * @Varargs: * * Configures a canvas item. The arguments in the item are set to the specified * values, and the item is repainted as appropriate. **/ void eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...) { va_list args; va_start (args, first_arg_name); eel_canvas_item_set_valist (item, first_arg_name, args); va_end (args); } /** * eel_canvas_item_set_valist: * @item: A canvas item. * @first_arg_name: The name of the first argument used to configure the item. * @args: The list of object argument name/value pairs used to configure the item. * * Configures a canvas item. The arguments in the item are set to the specified * values, and the item is repainted as appropriate. **/ void eel_canvas_item_set_valist (EelCanvasItem *item, const gchar *first_arg_name, va_list args) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_object_set_valist (G_OBJECT (item), first_arg_name, args); item->canvas->need_repick = TRUE; } /** * eel_canvas_item_move: * @item: A canvas item. * @dx: Horizontal offset. * @dy: Vertical offset. * * Moves a canvas item by creating an affine transformation matrix for * translation by using the specified values. This happens in item * local coordinate system, so if you have nontrivial transform, it * most probably does not do, what you want. **/ void eel_canvas_item_move (EelCanvasItem *item, double dx, double dy) { g_return_if_fail (item != NULL); g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (!EEL_CANVAS_ITEM_GET_CLASS (item)->translate) { g_warning ("Item type %s does not implement translate method.\n", g_type_name (G_OBJECT_TYPE (item))); return; } (* EEL_CANVAS_ITEM_GET_CLASS (item)->translate) (item, dx, dy); if (item->flags & EEL_CANVAS_ITEM_MAPPED) item->canvas->need_repick = TRUE; if (!(item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) { item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; if (item->parent != NULL) eel_canvas_item_request_update (item->parent); else eel_canvas_request_update (item->canvas); } } static void eel_canvas_queue_resize (EelCanvas *canvas) { if (gtk_widget_is_drawable (GTK_WIDGET (canvas))) gtk_widget_queue_resize (GTK_WIDGET (canvas)); } /* Convenience function to reorder items in a group's child list. This puts the * specified link after the "before" link. Returns TRUE if the list was changed. */ static gboolean put_item_after (GList *link, GList *before) { EelCanvasGroup *parent; if (link == before) return FALSE; parent = EEL_CANVAS_GROUP (EEL_CANVAS_ITEM (link->data)->parent); if (before == NULL) { if (link == parent->item_list) return FALSE; link->prev->next = link->next; if (link->next) link->next->prev = link->prev; else parent->item_list_end = link->prev; link->prev = before; link->next = parent->item_list; link->next->prev = link; parent->item_list = link; } else { if ((link == parent->item_list_end) && (before == parent->item_list_end->prev)) return FALSE; if (link->next) link->next->prev = link->prev; if (link->prev) link->prev->next = link->next; else { parent->item_list = link->next; parent->item_list->prev = NULL; } link->prev = before; link->next = before->next; link->prev->next = link; if (link->next) link->next->prev = link; else parent->item_list_end = link; } return TRUE; } /** * eel_canvas_item_raise: * @item: A canvas item. * @positions: Number of steps to raise the item. * * Raises the item in its parent's stack by the specified number of positions. * If the number of positions is greater than the distance to the top of the * stack, then the item is put at the top. **/ void eel_canvas_item_raise (EelCanvasItem *item, int positions) { GList *link, *before; EelCanvasGroup *parent; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (positions >= 0); if (!item->parent || positions == 0) return; parent = EEL_CANVAS_GROUP (item->parent); link = g_list_find (parent->item_list, item); g_assert (link != NULL); for (before = link; positions && before; positions--) before = before->next; if (!before) before = parent->item_list_end; if (put_item_after (link, before)) { redraw_and_repick_if_mapped (item); } } /** * eel_canvas_item_lower: * @item: A canvas item. * @positions: Number of steps to lower the item. * * Lowers the item in its parent's stack by the specified number of positions. * If the number of positions is greater than the distance to the bottom of the * stack, then the item is put at the bottom. **/ void eel_canvas_item_lower (EelCanvasItem *item, int positions) { GList *link, *before; EelCanvasGroup *parent; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (positions >= 1); if (!item->parent || positions == 0) return; parent = EEL_CANVAS_GROUP (item->parent); link = g_list_find (parent->item_list, item); g_assert (link != NULL); if (link->prev) for (before = link->prev; positions && before; positions--) before = before->prev; else before = NULL; if (put_item_after (link, before)) { redraw_and_repick_if_mapped (item); } } /** * eel_canvas_item_raise_to_top: * @item: A canvas item. * * Raises an item to the top of its parent's stack. **/ void eel_canvas_item_raise_to_top (EelCanvasItem *item) { GList *link; EelCanvasGroup *parent; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (!item->parent) return; parent = EEL_CANVAS_GROUP (item->parent); link = g_list_find (parent->item_list, item); g_assert (link != NULL); if (put_item_after (link, parent->item_list_end)) { redraw_and_repick_if_mapped (item); } } /** * eel_canvas_item_lower_to_bottom: * @item: A canvas item. * * Lowers an item to the bottom of its parent's stack. **/ void eel_canvas_item_lower_to_bottom (EelCanvasItem *item) { GList *link; EelCanvasGroup *parent; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (!item->parent) return; parent = EEL_CANVAS_GROUP (item->parent); link = g_list_find (parent->item_list, item); g_assert (link != NULL); if (put_item_after (link, NULL)) { redraw_and_repick_if_mapped (item); } } /** * eel_canvas_item_send_behind: * @item: A canvas item. * @behind_item: The canvas item to put item behind, or NULL * * Moves item to a in the position in the stacking order so that * it is placed immediately below behind_item, or at the top if * behind_item is NULL. **/ void eel_canvas_item_send_behind (EelCanvasItem *item, EelCanvasItem *behind_item) { GList *item_list; int item_position, behind_position; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (behind_item == NULL) { eel_canvas_item_raise_to_top (item); return; } g_return_if_fail (EEL_IS_CANVAS_ITEM (behind_item)); g_return_if_fail (item->parent == behind_item->parent); item_list = EEL_CANVAS_GROUP (item->parent)->item_list; item_position = g_list_index (item_list, item); g_assert (item_position != -1); behind_position = g_list_index (item_list, behind_item); g_assert (behind_position != -1); g_assert (item_position != behind_position); if (item_position == behind_position - 1) { return; } if (item_position < behind_position) { eel_canvas_item_raise (item, (behind_position - 1) - item_position); } else { eel_canvas_item_lower (item, item_position - behind_position); } } /** * eel_canvas_item_show: * @item: A canvas item. * * Shows a canvas item. If the item was already shown, then no action is taken. **/ void eel_canvas_item_show (EelCanvasItem *item) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (!(item->flags & EEL_CANVAS_ITEM_VISIBLE)) { item->flags |= EEL_CANVAS_ITEM_VISIBLE; if (!(item->flags & EEL_CANVAS_ITEM_REALIZED)) (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item); if (item->parent != NULL) { if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) && (item->parent->flags & EEL_CANVAS_ITEM_MAPPED)) (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); } else { if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) && gtk_widget_get_mapped (GTK_WIDGET (item->canvas))) (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); } redraw_and_repick_if_mapped (item); eel_canvas_queue_resize (item->canvas); } } /** * eel_canvas_item_hide: * @item: A canvas item. * * Hides a canvas item. If the item was already hidden, then no action is * taken. **/ void eel_canvas_item_hide (EelCanvasItem *item) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (item->flags & EEL_CANVAS_ITEM_VISIBLE) { item->flags &= ~EEL_CANVAS_ITEM_VISIBLE; redraw_and_repick_if_mapped (item); if (item->flags & EEL_CANVAS_ITEM_MAPPED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); eel_canvas_queue_resize (item->canvas); /* No need to unrealize when we just want to hide */ } } /** * eel_canvas_item_grab: * @item: A canvas item. * @event_mask: Mask of events that will be sent to this item. * @cursor: If non-NULL, the cursor that will be used while the grab is active. * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME. * * Specifies that all events that match the specified event mask should be sent * to the specified item, and also grabs the mouse by calling * gdk_pointer_grab(). The event mask is also used when grabbing the pointer. * If @cursor is not NULL, then that cursor is used while the grab is active. * The @etime parameter is the timestamp required for grabbing the mouse. * * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If * the specified item was hidden by calling eel_canvas_item_hide(), then it * returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling * gdk_pointer_grab(). **/ GdkGrabStatus eel_canvas_item_grab (EelCanvasItem *item, GdkEventMask event_mask, GdkCursor *cursor, guint32 timestamp) { GdkGrabStatus retval; GdkDisplay *display; GdkDeviceManager *manager; GdkDevice *device; g_return_val_if_fail (EEL_IS_CANVAS_ITEM (item), GDK_GRAB_NOT_VIEWABLE); g_return_val_if_fail (gtk_widget_get_mapped (GTK_WIDGET (item->canvas)), GDK_GRAB_NOT_VIEWABLE); if (item->canvas->grabbed_item) return GDK_GRAB_ALREADY_GRABBED; if (!(item->flags & EEL_CANVAS_ITEM_MAPPED)) return GDK_GRAB_NOT_VIEWABLE; display = gtk_widget_get_display (GTK_WIDGET (item->canvas)); manager = gdk_display_get_device_manager (display); device = gdk_device_manager_get_client_pointer (manager); retval = gdk_device_grab (device, gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)), GDK_OWNERSHIP_NONE, FALSE, event_mask, cursor, timestamp); if (retval != GDK_GRAB_SUCCESS) return retval; item->canvas->grabbed_item = item; item->canvas->grabbed_event_mask = event_mask; item->canvas->current_item = item; /* So that events go to the grabbed item */ return retval; } /** * eel_canvas_item_ungrab: * @item: A canvas item that holds a grab. * @etime: The timestamp for ungrabbing the mouse. * * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the * mouse. **/ void eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime) { GdkDisplay *display; GdkDeviceManager *manager; GdkDevice *device; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); if (item->canvas->grabbed_item != item) return; display = gtk_widget_get_display (GTK_WIDGET (item->canvas)); manager = gdk_display_get_device_manager (display); device = gdk_device_manager_get_client_pointer (manager); item->canvas->grabbed_item = NULL; gdk_device_ungrab (device, etime); } /** * eel_canvas_item_w2i: * @item: A canvas item. * @x: X coordinate to convert (input/output value). * @y: Y coordinate to convert (input/output value). * * Converts a coordinate pair from world coordinates to item-relative * coordinates. **/ void eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (x != NULL); g_return_if_fail (y != NULL); item = item->parent; while (item) { if (EEL_IS_CANVAS_GROUP (item)) { *x -= EEL_CANVAS_GROUP (item)->xpos; *y -= EEL_CANVAS_GROUP (item)->ypos; } item = item->parent; } } /** * eel_canvas_item_i2w: * @item: A canvas item. * @x: X coordinate to convert (input/output value). * @y: Y coordinate to convert (input/output value). * * Converts a coordinate pair from item-relative coordinates to world * coordinates. **/ void eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (x != NULL); g_return_if_fail (y != NULL); item = item->parent; while (item) { if (EEL_IS_CANVAS_GROUP (item)) { *x += EEL_CANVAS_GROUP (item)->xpos; *y += EEL_CANVAS_GROUP (item)->ypos; } item = item->parent; } } /* Returns whether the item is an inferior of or is equal to the parent. */ static int is_descendant (EelCanvasItem *item, EelCanvasItem *parent) { for (; item; item = item->parent) if (item == parent) return TRUE; return FALSE; } /** * eel_canvas_item_reparent: * @item: A canvas item. * @new_group: A canvas group. * * Changes the parent of the specified item to be the new group. The item keeps * its group-relative coordinates as for its old parent, so the item may change * its absolute position within the canvas. **/ void eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group) { g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (EEL_IS_CANVAS_GROUP (new_group)); /* Both items need to be in the same canvas */ g_return_if_fail (item->canvas == EEL_CANVAS_ITEM (new_group)->canvas); /* The group cannot be an inferior of the item or be the item itself -- * this also takes care of the case where the item is the root item of * the canvas. */ g_return_if_fail (!is_descendant (EEL_CANVAS_ITEM (new_group), item)); /* Everything is ok, now actually reparent the item */ g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */ eel_canvas_item_request_redraw (item); group_remove (EEL_CANVAS_GROUP (item->parent), item); item->parent = EEL_CANVAS_ITEM (new_group); /* item->canvas is unchanged. */ group_add (new_group, item); /* Redraw and repick */ redraw_and_repick_if_mapped (item); g_object_unref (G_OBJECT (item)); } /** * eel_canvas_item_grab_focus: * @item: A canvas item. * * Makes the specified item take the keyboard focus, so all keyboard events will * be sent to it. If the canvas widget itself did not have the focus, it grabs * it as well. **/ void eel_canvas_item_grab_focus (EelCanvasItem *item) { EelCanvasItem *focused_item; GdkEvent ev; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))); focused_item = item->canvas->focused_item; if (focused_item) { ev.focus_change.type = GDK_FOCUS_CHANGE; ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)); ev.focus_change.send_event = FALSE; ev.focus_change.in = FALSE; emit_event (item->canvas, &ev); } item->canvas->focused_item = item; gtk_widget_grab_focus (GTK_WIDGET (item->canvas)); if (focused_item) { ev.focus_change.type = GDK_FOCUS_CHANGE; ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)); ev.focus_change.send_event = FALSE; ev.focus_change.in = TRUE; emit_event (item->canvas, &ev); } } /** * eel_canvas_item_get_bounds: * @item: A canvas item. * @x1: Leftmost edge of the bounding box (return value). * @y1: Upper edge of the bounding box (return value). * @x2: Rightmost edge of the bounding box (return value). * @y2: Lower edge of the bounding box (return value). * * Queries the bounding box of a canvas item. The bounds are returned in the * coordinate system of the item's parent. **/ void eel_canvas_item_get_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { double tx1, ty1, tx2, ty2; g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); tx1 = ty1 = tx2 = ty2 = 0.0; /* Get the item's bounds in its coordinate system */ if (EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) (* EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2); /* Return the values */ if (x1) *x1 = tx1; if (y1) *y1 = ty1; if (x2) *x2 = tx2; if (y2) *y2 = ty2; } /** * eel_canvas_item_request_update * @item: A canvas item. * * To be used only by item implementations. Requests that the canvas queue an * update for the specified item. **/ void eel_canvas_item_request_update (EelCanvasItem *item) { if (NULL == item->canvas) return; g_return_if_fail (!item->canvas->doing_update); if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE) return; item->flags |= EEL_CANVAS_ITEM_NEED_UPDATE; if (item->parent != NULL) { /* Recurse up the tree */ eel_canvas_item_request_update (item->parent); } else { /* Have reached the top of the tree, make sure the update call gets scheduled. */ eel_canvas_request_update (item->canvas); } } /** * eel_canvas_item_request_update * @item: A canvas item. * * Convenience function that informs a canvas that the specified item needs * to be repainted. To be used by item implementations **/ void eel_canvas_item_request_redraw (EelCanvasItem *item) { if (item->flags & EEL_CANVAS_ITEM_MAPPED) eel_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 3); } /*** EelCanvasGroup ***/ enum { GROUP_PROP_0, GROUP_PROP_X, GROUP_PROP_Y }; static void eel_canvas_group_class_init (EelCanvasGroupClass *klass); static void eel_canvas_group_init (EelCanvasGroup *group); static void eel_canvas_group_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void eel_canvas_group_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void eel_canvas_group_destroy (EelCanvasItem *object); static void eel_canvas_group_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); static void eel_canvas_group_unrealize (EelCanvasItem *item); static void eel_canvas_group_map (EelCanvasItem *item); static void eel_canvas_group_unmap (EelCanvasItem *item); static void eel_canvas_group_draw (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region); static double eel_canvas_group_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item); static void eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy); static void eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); static EelCanvasItemClass *group_parent_class; /** * eel_canvas_group_get_type: * * Registers the &EelCanvasGroup class if necessary, and returns the type ID * associated to it. * * Return value: The type ID of the &EelCanvasGroup class. **/ GType eel_canvas_group_get_type (void) { static GType group_type = 0; if (!group_type) { static const GTypeInfo group_info = { sizeof (EelCanvasGroupClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eel_canvas_group_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EelCanvasGroup), 0, /* n_preallocs */ (GInstanceInitFunc) eel_canvas_group_init }; group_type = g_type_register_static (eel_canvas_item_get_type (), "EelCanvasGroup", &group_info, 0); } return group_type; } /* Class initialization function for EelCanvasGroupClass */ static void eel_canvas_group_class_init (EelCanvasGroupClass *klass) { GObjectClass *gobject_class; EelCanvasItemClass *item_class; gobject_class = (GObjectClass *) klass; item_class = (EelCanvasItemClass *) klass; group_parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = eel_canvas_group_set_property; gobject_class->get_property = eel_canvas_group_get_property; g_object_class_install_property (gobject_class, GROUP_PROP_X, g_param_spec_double ("x", _("X"), _("X"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, GROUP_PROP_Y, g_param_spec_double ("y", _("Y"), _("Y"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); item_class->destroy = eel_canvas_group_destroy; item_class->update = eel_canvas_group_update; item_class->unrealize = eel_canvas_group_unrealize; item_class->map = eel_canvas_group_map; item_class->unmap = eel_canvas_group_unmap; item_class->draw = eel_canvas_group_draw; item_class->point = eel_canvas_group_point; item_class->translate = eel_canvas_group_translate; item_class->bounds = eel_canvas_group_bounds; } /* Object initialization function for EelCanvasGroup */ static void eel_canvas_group_init (EelCanvasGroup *group) { group->xpos = 0.0; group->ypos = 0.0; } /* Set_property handler for canvas groups */ static void eel_canvas_group_set_property (GObject *gobject, guint param_id, const GValue *value, GParamSpec *pspec) { EelCanvasItem *item; EelCanvasGroup *group; double old; gboolean moved; g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject)); item = EEL_CANVAS_ITEM (gobject); group = EEL_CANVAS_GROUP (gobject); moved = FALSE; switch (param_id) { case GROUP_PROP_X: old = group->xpos; group->xpos = g_value_get_double (value); if (old != group->xpos) moved = TRUE; break; case GROUP_PROP_Y: old = group->ypos; group->ypos = g_value_get_double (value); if (old != group->ypos) moved = TRUE; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); break; } if (moved) { item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; if (item->parent != NULL) eel_canvas_item_request_update (item->parent); else eel_canvas_request_update (item->canvas); } } /* Get_property handler for canvas groups */ static void eel_canvas_group_get_property (GObject *gobject, guint param_id, GValue *value, GParamSpec *pspec) { EelCanvasGroup *group; g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject)); group = EEL_CANVAS_GROUP (gobject); switch (param_id) { case GROUP_PROP_X: g_value_set_double (value, group->xpos); break; case GROUP_PROP_Y: g_value_set_double (value, group->ypos); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); break; } } /* Destroy handler for canvas groups */ static void eel_canvas_group_destroy (EelCanvasItem *object) { EelCanvasGroup *group; EelCanvasItem *child; GList *list; g_return_if_fail (EEL_IS_CANVAS_GROUP (object)); group = EEL_CANVAS_GROUP (object); list = group->item_list; while (list) { child = list->data; list = list->next; eel_canvas_item_destroy (child); } if (EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy) (* EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy) (object); } /* Update handler for canvas groups */ static void eel_canvas_group_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) { EelCanvasGroup *group; GList *list; EelCanvasItem *i; double bbox_x0, bbox_y0, bbox_x1, bbox_y1; gboolean first = TRUE; group = EEL_CANVAS_GROUP (item); (* group_parent_class->update) (item, i2w_dx, i2w_dy, flags); bbox_x0 = 0; bbox_y0 = 0; bbox_x1 = 0; bbox_y1 = 0; for (list = group->item_list; list; list = list->next) { i = list->data; eel_canvas_item_invoke_update (i, i2w_dx + group->xpos, i2w_dy + group->ypos, flags); if (first) { first = FALSE; bbox_x0 = i->x1; bbox_y0 = i->y1; bbox_x1 = i->x2; bbox_y1 = i->y2; } else { bbox_x0 = MIN (bbox_x0, i->x1); bbox_y0 = MIN (bbox_y0, i->y1); bbox_x1 = MAX (bbox_x1, i->x2); bbox_y1 = MAX (bbox_y1, i->y2); } } item->x1 = bbox_x0; item->y1 = bbox_y0; item->x2 = bbox_x1; item->y2 = bbox_y1; } /* Unrealize handler for canvas groups */ static void eel_canvas_group_unrealize (EelCanvasItem *item) { EelCanvasGroup *group; GList *list; EelCanvasItem *i; group = EEL_CANVAS_GROUP (item); /* Unmap group before children to avoid flash */ if (item->flags & EEL_CANVAS_ITEM_MAPPED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); for (list = group->item_list; list; list = list->next) { i = list->data; if (i->flags & EEL_CANVAS_ITEM_REALIZED) (* EEL_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i); } (* group_parent_class->unrealize) (item); } /* Map handler for canvas groups */ static void eel_canvas_group_map (EelCanvasItem *item) { EelCanvasGroup *group; GList *list; EelCanvasItem *i; group = EEL_CANVAS_GROUP (item); for (list = group->item_list; list; list = list->next) { i = list->data; if ((i->flags & EEL_CANVAS_ITEM_VISIBLE) && !(i->flags & EEL_CANVAS_ITEM_MAPPED)) { if (!(i->flags & EEL_CANVAS_ITEM_REALIZED)) (* EEL_CANVAS_ITEM_GET_CLASS (i)->realize) (i); (* EEL_CANVAS_ITEM_GET_CLASS (i)->map) (i); } } (* group_parent_class->map) (item); } /* Unmap handler for canvas groups */ static void eel_canvas_group_unmap (EelCanvasItem *item) { EelCanvasGroup *group; GList *list; EelCanvasItem *i; group = EEL_CANVAS_GROUP (item); for (list = group->item_list; list; list = list->next) { i = list->data; if (i->flags & EEL_CANVAS_ITEM_MAPPED) (* EEL_CANVAS_ITEM_GET_CLASS (i)->unmap) (i); } (* group_parent_class->unmap) (item); } /* Draw handler for canvas groups */ static void eel_canvas_group_draw (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region) { EelCanvasGroup *group; GList *list; EelCanvasItem *child = NULL; group = EEL_CANVAS_GROUP (item); for (list = group->item_list; list; list = list->next) { child = list->data; if ((child->flags & EEL_CANVAS_ITEM_MAPPED) && (EEL_CANVAS_ITEM_GET_CLASS (child)->draw)) { GdkRectangle child_rect; child_rect.x = child->x1; child_rect.y = child->y1; child_rect.width = child->x2 - child->x1 + 1; child_rect.height = child->y2 - child->y1 + 1; if (cairo_region_contains_rectangle (region, &child_rect) != CAIRO_REGION_OVERLAP_OUT) EEL_CANVAS_ITEM_GET_CLASS (child)->draw (child, cr, region); } } } /* Point handler for canvas groups */ static double eel_canvas_group_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) { EelCanvasGroup *group; GList *list; EelCanvasItem *child, *point_item; int x1, y1, x2, y2; double gx, gy; double dist, best; int has_point; group = EEL_CANVAS_GROUP (item); x1 = cx - item->canvas->close_enough; y1 = cy - item->canvas->close_enough; x2 = cx + item->canvas->close_enough; y2 = cy + item->canvas->close_enough; best = 0.0; *actual_item = NULL; gx = x - group->xpos; gy = y - group->ypos; dist = 0.0; /* keep gcc happy */ for (list = group->item_list; list; list = list->next) { child = list->data; if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1)) continue; point_item = NULL; /* cater for incomplete item implementations */ if ((child->flags & EEL_CANVAS_ITEM_MAPPED) && EEL_CANVAS_ITEM_GET_CLASS (child)->point) { dist = eel_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item); has_point = TRUE; } else has_point = FALSE; if (has_point && point_item && ((int) (dist * item->canvas->pixels_per_unit + 0.5) <= item->canvas->close_enough)) { best = dist; *actual_item = point_item; } } return best; } void eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy) { EelCanvasGroup *group; group = EEL_CANVAS_GROUP (item); group->xpos += dx; group->ypos += dy; } /* Bounds handler for canvas groups */ static void eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { EelCanvasGroup *group; EelCanvasItem *child; GList *list; double tx1, ty1, tx2, ty2; double minx, miny, maxx, maxy; int set; group = EEL_CANVAS_GROUP (item); /* Get the bounds of the first visible item */ child = NULL; /* Unnecessary but eliminates a warning. */ set = FALSE; for (list = group->item_list; list; list = list->next) { child = list->data; if (child->flags & EEL_CANVAS_ITEM_MAPPED) { set = TRUE; eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy); break; } } /* If there were no visible items, return an empty bounding box */ if (!set) { *x1 = *y1 = *x2 = *y2 = 0.0; return; } /* Now we can grow the bounds using the rest of the items */ list = list->next; for (; list; list = list->next) { child = list->data; if (!(child->flags & EEL_CANVAS_ITEM_MAPPED)) continue; eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2); if (tx1 < minx) minx = tx1; if (ty1 < miny) miny = ty1; if (tx2 > maxx) maxx = tx2; if (ty2 > maxy) maxy = ty2; } /* Make the bounds be relative to our parent's coordinate system */ if (item->parent) { minx += group->xpos; miny += group->ypos; maxx += group->xpos; maxy += group->ypos; } *x1 = minx; *y1 = miny; *x2 = maxx; *y2 = maxy; } /* Adds an item to a group */ static void group_add (EelCanvasGroup *group, EelCanvasItem *item) { g_object_ref_sink (item); /* FIXME: relatively inefficient way to add to the list, appending to the list causes it to be read from the top each time. prepend, followed by a reverse if necessary is the recommended approach. However as this list append is a number of levels of call down, correcting it is not as easy as it could be */ if (!group->item_list) { group->item_list = g_list_append (group->item_list, item); group->item_list_end = group->item_list; } else group->item_list_end = g_list_append (group->item_list_end, item)->next; if ((item->flags & EEL_CANVAS_ITEM_VISIBLE) && (group->item.flags & EEL_CANVAS_ITEM_MAPPED)) { if (!(item->flags & EEL_CANVAS_ITEM_REALIZED)) (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item); if (!(item->flags & EEL_CANVAS_ITEM_MAPPED)) (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); } if (item->flags & EEL_CANVAS_ITEM_VISIBLE) eel_canvas_queue_resize (EEL_CANVAS_ITEM (group)->canvas); } /* Removes an item from a group */ static void group_remove (EelCanvasGroup *group, EelCanvasItem *item) { GList *children; g_return_if_fail (EEL_IS_CANVAS_GROUP (group)); g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); for (children = group->item_list; children; children = children->next) if (children->data == item) { if (item->flags & EEL_CANVAS_ITEM_MAPPED) { (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); } if (item->flags & EEL_CANVAS_ITEM_REALIZED) (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item); if (item->flags & EEL_CANVAS_ITEM_VISIBLE) eel_canvas_queue_resize (item->canvas); /* Unparent the child */ item->parent = NULL; /* item->canvas = NULL; */ g_object_unref (G_OBJECT (item)); /* Remove it from the list */ if (children == group->item_list_end) group->item_list_end = children->prev; group->item_list = g_list_remove_link (group->item_list, children); g_list_free (children); break; } } /*** EelCanvas ***/ enum { DRAW_BACKGROUND, LAST_SIGNAL }; static void eel_canvas_class_init (EelCanvasClass *klass); static void eel_canvas_init (EelCanvas *canvas); static void eel_canvas_destroy (GtkWidget *object); static void eel_canvas_map (GtkWidget *widget); static void eel_canvas_unmap (GtkWidget *widget); static void eel_canvas_realize (GtkWidget *widget); static void eel_canvas_unrealize (GtkWidget *widget); static void eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint eel_canvas_button (GtkWidget *widget, GdkEventButton *event); static gint eel_canvas_motion (GtkWidget *widget, GdkEventMotion *event); static gint eel_canvas_draw (GtkWidget *widget, cairo_t *cr); static gint eel_canvas_key (GtkWidget *widget, GdkEventKey *event); static gint eel_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event); static gint eel_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint eel_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event); static void eel_canvas_request_update_real (EelCanvas *canvas); static void eel_canvas_draw_background (EelCanvas *canvas, cairo_t *cr); static AtkObject *eel_canvas_get_accessible (GtkWidget *widget); static GtkLayoutClass *canvas_parent_class; static guint canvas_signals[LAST_SIGNAL] = { 0 }; /** * eel_canvas_get_type: * * Registers the &EelCanvas class if necessary, and returns the type ID * associated to it. * * Return value: The type ID of the &EelCanvas class. **/ GType eel_canvas_get_type (void) { static GType canvas_type = 0; if (!canvas_type) { static const GTypeInfo canvas_info = { sizeof (EelCanvasClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eel_canvas_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EelCanvas), 0, /* n_preallocs */ (GInstanceInitFunc) eel_canvas_init }; canvas_type = g_type_register_static (gtk_layout_get_type (), "EelCanvas", &canvas_info, 0); } return canvas_type; } static void eel_canvas_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void eel_canvas_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void eel_canvas_accessible_adjustment_changed (GtkAdjustment *adjustment, AtkObject *obj) { /* The scrollbars have changed */ g_signal_emit_by_name (obj, "visible_data_changed"); } static void accessible_destroy_cb (GtkWidget *widget, AtkObject *obj) { gtk_accessible_set_widget (GTK_ACCESSIBLE(obj), NULL); atk_object_notify_state_change (obj, ATK_STATE_DEFUNCT, TRUE); } static gboolean accessible_focus_cb (GtkWidget *widget, GdkEventFocus *event) { atk_object_notify_state_change ((AtkObject *)gtk_widget_get_accessible (widget), ATK_STATE_FOCUSED, event->in); return FALSE; } static void accessible_notify_cb (GObject *obj, GParamSpec *pspec) { GtkWidget* widget = GTK_WIDGET (obj); AtkObject* atk_obj = gtk_widget_get_accessible (widget); AtkState state; gboolean value; if (strcmp (pspec->name, "visible") == 0) { state = ATK_STATE_VISIBLE; value = gtk_widget_get_visible (widget); } else if (strcmp (pspec->name, "sensitive") == 0) { state = ATK_STATE_SENSITIVE; value = gtk_widget_get_sensitive (widget); atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED, value); } else { g_assert_not_reached (); } atk_object_notify_state_change (atk_obj, state, value); } /* Translate GtkWidget::size-allocate to AtkComponent::bounds-changed */ static void accessible_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation) { AtkObject* accessible = gtk_widget_get_accessible (widget); AtkRectangle rect; rect.x = allocation->x; rect.y = allocation->y; rect.width = allocation->width; rect.height = allocation->height; g_signal_emit_by_name (accessible, "bounds_changed", &rect); } /* Translate GtkWidget mapped state into AtkObject showing */ static void accessible_map_cb (GtkWidget *widget) { AtkObject *accessible = gtk_widget_get_accessible (widget); atk_object_notify_state_change (accessible, ATK_STATE_SHOWING, gtk_widget_get_mapped (widget)); } static void eel_canvas_accessible_initialize (AtkObject *obj, gpointer data) { EelCanvas *canvas = data; if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize != NULL) { ATK_OBJECT_CLASS (accessible_parent_class)->initialize (obj, data); } gtk_accessible_set_widget (GTK_ACCESSIBLE (obj), GTK_WIDGET (data)); g_signal_connect (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)), "value_changed", G_CALLBACK (eel_canvas_accessible_adjustment_changed), obj); g_signal_connect (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)), "value_changed", G_CALLBACK (eel_canvas_accessible_adjustment_changed), obj); obj->role = ATK_ROLE_LAYERED_PANE; /* below adapted from gtkwidgetaccessible.c */ g_signal_connect_after (canvas, "destroy", G_CALLBACK (accessible_destroy_cb), obj); g_signal_connect_after (canvas, "focus-in-event", G_CALLBACK (accessible_focus_cb), NULL); g_signal_connect_after (canvas, "focus-out-event", G_CALLBACK (accessible_focus_cb), NULL); g_signal_connect (canvas, "notify::visible", G_CALLBACK (accessible_notify_cb), NULL); g_signal_connect (canvas, "notify::sensitive", G_CALLBACK (accessible_notify_cb), NULL); g_signal_connect (canvas, "size-allocate", G_CALLBACK (accessible_size_allocate_cb), NULL); g_signal_connect (canvas, "map", G_CALLBACK (accessible_map_cb), NULL); g_signal_connect (canvas, "unmap", G_CALLBACK (accessible_map_cb), NULL); } static gint eel_canvas_accessible_get_n_children (AtkObject* obj) { GtkWidget *widget; EelCanvas *canvas; EelCanvasGroup *root_group; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)); if (widget == NULL) { return 0; } g_return_val_if_fail (EEL_IS_CANVAS (widget), 0); canvas = EEL_CANVAS (widget); root_group = eel_canvas_root (canvas); g_return_val_if_fail (root_group, 0); return 1; } static AtkObject* eel_canvas_accessible_ref_child (AtkObject *obj, gint i) { GtkWidget *widget; EelCanvas *canvas; EelCanvasGroup *root_group; AtkObject *atk_object; /* Canvas only has one child, so return NULL if index is non zero */ if (i != 0) { return NULL; } widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)); if (widget == NULL) { return NULL; } canvas = EEL_CANVAS (widget); root_group = eel_canvas_root (canvas); g_return_val_if_fail (root_group, NULL); atk_object = atk_gobject_accessible_for_object (G_OBJECT (root_group)); return g_object_ref (atk_object); } static gboolean eel_canvas_accessible_all_parents_visible (GtkWidget *widget) { GtkWidget *iter_parent = NULL; gboolean result = TRUE; for (iter_parent = gtk_widget_get_parent (widget); iter_parent != NULL; iter_parent = gtk_widget_get_parent (iter_parent)) { if (!gtk_widget_get_visible (iter_parent)) { result = FALSE; break; } } return result; } static gboolean eel_canvas_accessible_on_screen (GtkWidget *widget) { GtkAllocation allocation; GtkWidget *viewport; gboolean return_value = TRUE; gtk_widget_get_allocation (widget, &allocation); viewport = gtk_widget_get_ancestor (widget, GTK_TYPE_VIEWPORT); if (viewport) { GtkAllocation viewport_allocation; GtkAdjustment *adjustment; GdkRectangle visible_rect; gtk_widget_get_allocation (viewport, &viewport_allocation); adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (viewport)); visible_rect.y = gtk_adjustment_get_value (adjustment); adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (viewport)); visible_rect.x = gtk_adjustment_get_value (adjustment); visible_rect.width = viewport_allocation.width; visible_rect.height = viewport_allocation.height; if (((allocation.x + allocation.width) < visible_rect.x) || ((allocation.y + allocation.height) < visible_rect.y) || (allocation.x > (visible_rect.x + visible_rect.width)) || (allocation.y > (visible_rect.y + visible_rect.height))) { return_value = FALSE; } } else { /* Check whether the widget has been placed off the screen. * The widget may be MAPPED as when toolbar items do not * fit on the toolbar. */ if (allocation.x + allocation.width <= 0 && allocation.y + allocation.height <= 0) { return_value = FALSE; } } return return_value; } static AtkStateSet * eel_canvas_accessible_ref_state_set (AtkObject *accessible) { GtkWidget *widget; AtkStateSet *state_set; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); state_set = ATK_OBJECT_CLASS (accessible_parent_class)->ref_state_set (accessible); if (widget == NULL) { atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); } else { if (gtk_widget_is_sensitive (widget)) { atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); atk_state_set_add_state (state_set, ATK_STATE_ENABLED); } if (gtk_widget_get_can_focus (widget)) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); } /* * We do not currently generate notifications when an ATK object * corresponding to a GtkWidget changes visibility by being scrolled * on or off the screen. The testcase for this is the main window * of the testgtk application in which a set of buttons in a GtkVBox * is in a scrolled window with a viewport. * * To generate the notifications we would need to do the following: * 1) Find the GtkViewport among the ancestors of the objects * 2) Create an accessible for the viewport * 3) Connect to the value-changed signal on the viewport * 4) When the signal is received we need to traverse the children * of the viewport and check whether the children are visible or not * visible; we may want to restrict this to the widgets for which * accessible objects have been created. * 5) We probably need to store a variable on_screen in the * GtkWidgetAccessible data structure so we can determine whether * the value has changed. */ if (gtk_widget_get_visible (widget)) { atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); if (eel_canvas_accessible_on_screen (widget) && gtk_widget_get_mapped (widget) && eel_canvas_accessible_all_parents_visible (widget)) { atk_state_set_add_state (state_set, ATK_STATE_SHOWING); } } if (gtk_widget_has_focus (widget)) { if (g_object_get_data (G_OBJECT (accessible), "gail-focus-object") == NULL) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } } if (gtk_widget_has_default (widget)) { atk_state_set_add_state (state_set, ATK_STATE_DEFAULT); } } return state_set; } static void eel_canvas_accessible_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { GdkWindow *window; gint x_window, y_window; gint x_toplevel, y_toplevel; GtkWidget *widget; GtkAllocation allocation; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component)); if (widget == NULL) { return; } gtk_widget_get_allocation (widget, &allocation); *width = allocation.width; *height = allocation.height; if (!eel_canvas_accessible_on_screen (widget) || !gtk_widget_is_drawable (widget)) { *x = G_MININT; *y = G_MININT; return; } if (gtk_widget_get_parent (widget)) { *x = allocation.x; *y = allocation.y; window = gtk_widget_get_parent_window (widget); } else { *x = 0; *y = 0; window = gtk_widget_get_window (widget); } gdk_window_get_origin (window, &x_window, &y_window); *x += x_window; *y += y_window; if (coord_type == ATK_XY_WINDOW) { window = gdk_window_get_toplevel (gtk_widget_get_window (widget)); gdk_window_get_origin (window, &x_toplevel, &y_toplevel); *x -= x_toplevel; *y -= y_toplevel; } } static void eel_canvas_accessible_get_size (AtkComponent *component, gint *width, gint *height) { GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component)); if (widget == NULL) { return; } *width = gtk_widget_get_allocated_width (widget); *height = gtk_widget_get_allocated_height (widget); } static void eel_canvas_accessible_component_init (gpointer iface, gpointer data) { AtkComponentIface *component; g_assert (G_TYPE_FROM_INTERFACE(iface) == ATK_TYPE_COMPONENT); component = iface; component->get_extents = eel_canvas_accessible_get_extents; component->get_size = eel_canvas_accessible_get_size; } G_DEFINE_TYPE_WITH_CODE (EelCanvasAccessible, eel_canvas_accessible, GTK_TYPE_ACCESSIBLE, G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, eel_canvas_accessible_component_init)) static void eel_canvas_accessible_class_init (EelCanvasAccessibleClass *klass) { AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); accessible_parent_class = g_type_class_peek_parent (klass); atk_class->initialize = eel_canvas_accessible_initialize; atk_class->get_n_children = eel_canvas_accessible_get_n_children; atk_class->ref_child = eel_canvas_accessible_ref_child; /* below adapted from gtkwidgetaccessible.c */ atk_class->ref_state_set = eel_canvas_accessible_ref_state_set; } static void eel_canvas_accessible_init (EelCanvasAccessible *accessible) { } static AtkObject * eel_canvas_accessible_create (GObject *for_object) { GType type; AtkObject *accessible; EelCanvas *canvas; canvas = EEL_CANVAS (for_object); g_return_val_if_fail (canvas != NULL, NULL); type = eel_canvas_accessible_get_type (); if (type == G_TYPE_INVALID) { return atk_no_op_object_new (for_object); } accessible = g_object_new (type, NULL); atk_object_initialize (accessible, for_object); return accessible; } static GType eel_canvas_accessible_factory_get_accessible_type (void) { return eel_canvas_accessible_get_type (); } static AtkObject* eel_canvas_accessible_factory_create_accessible (GObject *obj) { g_return_val_if_fail (G_IS_OBJECT (obj), NULL); return eel_canvas_accessible_create (obj); } static void eel_canvas_accessible_factory_class_init (AtkObjectFactoryClass *klass) { klass->create_accessible = eel_canvas_accessible_factory_create_accessible; klass->get_accessible_type = eel_canvas_accessible_factory_get_accessible_type; } static GType eel_canvas_accessible_factory_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo tinfo = { sizeof (AtkObjectFactoryClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eel_canvas_accessible_factory_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (AtkObjectFactory), 0, /* n_preallocs */ NULL }; type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, "EelCanvasAccessibilityFactory", &tinfo, 0); } return type; } /* Class initialization function for EelCanvasClass */ static void eel_canvas_class_init (EelCanvasClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; gobject_class = (GObjectClass *)klass; widget_class = (GtkWidgetClass *) klass; canvas_parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = eel_canvas_set_property; gobject_class->get_property = eel_canvas_get_property; widget_class->destroy = eel_canvas_destroy; widget_class->map = eel_canvas_map; widget_class->unmap = eel_canvas_unmap; widget_class->realize = eel_canvas_realize; widget_class->unrealize = eel_canvas_unrealize; widget_class->size_allocate = eel_canvas_size_allocate; widget_class->button_press_event = eel_canvas_button; widget_class->button_release_event = eel_canvas_button; widget_class->motion_notify_event = eel_canvas_motion; widget_class->draw = eel_canvas_draw; widget_class->key_press_event = eel_canvas_key; widget_class->key_release_event = eel_canvas_key; widget_class->enter_notify_event = eel_canvas_crossing; widget_class->leave_notify_event = eel_canvas_crossing; widget_class->focus_in_event = eel_canvas_focus_in; widget_class->focus_out_event = eel_canvas_focus_out; widget_class->get_accessible = eel_canvas_get_accessible; klass->draw_background = eel_canvas_draw_background; klass->request_update = eel_canvas_request_update_real; canvas_signals[DRAW_BACKGROUND] = g_signal_new ("draw_background", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EelCanvasClass, draw_background), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, CAIRO_GOBJECT_TYPE_CONTEXT); atk_registry_set_factory_type (atk_get_default_registry (), EEL_TYPE_CANVAS, eel_canvas_accessible_factory_get_type ()); } /* Callback used when the root item of a canvas is destroyed. The user should * never ever do this, so we panic if this happens. */ static void panic_root_destroyed (GtkWidget *object, gpointer data) { g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data); } /* Object initialization function for EelCanvas */ static void eel_canvas_init (EelCanvas *canvas) { guint width, height; gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE); gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE); canvas->scroll_x1 = 0.0; canvas->scroll_y1 = 0.0; gtk_layout_get_size (GTK_LAYOUT (canvas), &width, &height); canvas->scroll_x2 = width; canvas->scroll_y2 = height; canvas->pixels_per_unit = 1.0; canvas->pick_event.type = GDK_LEAVE_NOTIFY; canvas->pick_event.crossing.x = 0; canvas->pick_event.crossing.y = 0; gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (canvas), NULL); gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (canvas), NULL); /* Create the root item as a special case */ canvas->root = EEL_CANVAS_ITEM (g_object_new (eel_canvas_group_get_type (), NULL)); canvas->root->canvas = canvas; g_object_ref_sink (canvas->root); canvas->root_destroy_id = g_signal_connect (G_OBJECT (canvas->root), "destroy", G_CALLBACK (panic_root_destroyed), canvas); canvas->need_repick = TRUE; canvas->doing_update = FALSE; } /* Convenience function to remove the idle handler of a canvas */ static void remove_idle (EelCanvas *canvas) { if (canvas->idle_id == 0) return; g_source_remove (canvas->idle_id); canvas->idle_id = 0; } /* Removes the transient state of the canvas (idle handler, grabs). */ static void shutdown_transients (EelCanvas *canvas) { /* We turn off the need_redraw flag, since if the canvas is mapped again * it will request a redraw anyways. We do not turn off the need_update * flag, though, because updates are not queued when the canvas remaps * itself. */ if (canvas->need_redraw) { canvas->need_redraw = FALSE; } if (canvas->grabbed_item) { eel_canvas_item_ungrab (canvas->grabbed_item, GDK_CURRENT_TIME); } remove_idle (canvas); } /* Destroy handler for EelCanvas */ static void eel_canvas_destroy (GtkWidget *object) { EelCanvas *canvas; g_return_if_fail (EEL_IS_CANVAS (object)); /* remember, destroy can be run multiple times! */ canvas = EEL_CANVAS (object); if (canvas->root_destroy_id) { g_signal_handler_disconnect (G_OBJECT (canvas->root), canvas->root_destroy_id); canvas->root_destroy_id = 0; } if (canvas->root) { EelCanvasItem *root = canvas->root; canvas->root = NULL; eel_canvas_item_destroy (root); g_object_unref (root); } shutdown_transients (canvas); if (GTK_WIDGET_CLASS (canvas_parent_class)->destroy) (* GTK_WIDGET_CLASS (canvas_parent_class)->destroy) (object); } /** * eel_canvas_new: * @void: * * Creates a new empty canvas. If you wish to use the * &EelCanvasImage item inside this canvas, then you must push the gdk_imlib * visual and colormap before calling this function, and they can be popped * afterwards. * * Return value: A newly-created canvas. **/ GtkWidget * eel_canvas_new (void) { return GTK_WIDGET (g_object_new (eel_canvas_get_type (), NULL)); } /* Map handler for the canvas */ static void eel_canvas_map (GtkWidget *widget) { EelCanvas *canvas; g_return_if_fail (EEL_IS_CANVAS (widget)); /* Normal widget mapping stuff */ if (GTK_WIDGET_CLASS (canvas_parent_class)->map) (* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget); canvas = EEL_CANVAS (widget); /* Map items */ if ((canvas->root->flags & EEL_CANVAS_ITEM_VISIBLE) && !(canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) && EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (canvas->root); } /* Unmap handler for the canvas */ static void eel_canvas_unmap (GtkWidget *widget) { EelCanvas *canvas; g_return_if_fail (EEL_IS_CANVAS (widget)); canvas = EEL_CANVAS (widget); shutdown_transients (canvas); /* Unmap items */ if (EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root); /* Normal widget unmapping stuff */ if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget); } /* Realize handler for the canvas */ static void eel_canvas_realize (GtkWidget *widget) { EelCanvas *canvas; g_return_if_fail (EEL_IS_CANVAS (widget)); /* Normal widget realization stuff */ if (GTK_WIDGET_CLASS (canvas_parent_class)->realize) (* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget); canvas = EEL_CANVAS (widget); gdk_window_set_events (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)), (gdk_window_get_events (gtk_layout_get_bin_window (GTK_LAYOUT (canvas))) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK)); /* Create our own temporary pixmap gc and realize all the items */ (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root); } /* Unrealize handler for the canvas */ static void eel_canvas_unrealize (GtkWidget *widget) { EelCanvas *canvas; g_return_if_fail (EEL_IS_CANVAS (widget)); canvas = EEL_CANVAS (widget); shutdown_transients (canvas); /* Unrealize items and parent widget */ (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root); if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget); } /* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to * keep as much as possible of the canvas scrolling region in view. */ static void scroll_to (EelCanvas *canvas, int cx, int cy) { int scroll_width, scroll_height; int right_limit, bottom_limit; int old_zoom_xofs, old_zoom_yofs; int changed_x = FALSE, changed_y = FALSE; int canvas_width, canvas_height; GtkAllocation allocation; GtkAdjustment *vadjustment, *hadjustment; guint width, height; gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation); canvas_width = allocation.width; canvas_height = allocation.height; scroll_width = floor ((canvas->scroll_x2 - canvas->scroll_x1) * canvas->pixels_per_unit + 0.5); scroll_height = floor ((canvas->scroll_y2 - canvas->scroll_y1) * canvas->pixels_per_unit + 0.5); right_limit = scroll_width - canvas_width; bottom_limit = scroll_height - canvas_height; old_zoom_xofs = canvas->zoom_xofs; old_zoom_yofs = canvas->zoom_yofs; if (right_limit < 0) { cx = 0; if (canvas->center_scroll_region) { canvas->zoom_xofs = (canvas_width - scroll_width) / 2; scroll_width = canvas_width; } else { canvas->zoom_xofs = 0; } } else if (cx < 0) { cx = 0; canvas->zoom_xofs = 0; } else if (cx > right_limit) { cx = right_limit; canvas->zoom_xofs = 0; } else canvas->zoom_xofs = 0; if (bottom_limit < 0) { cy = 0; if (canvas->center_scroll_region) { canvas->zoom_yofs = (canvas_height - scroll_height) / 2; scroll_height = canvas_height; } else { canvas->zoom_yofs = 0; } } else if (cy < 0) { cy = 0; canvas->zoom_yofs = 0; } else if (cy > bottom_limit) { cy = bottom_limit; canvas->zoom_yofs = 0; } else canvas->zoom_yofs = 0; if ((canvas->zoom_xofs != old_zoom_xofs) || (canvas->zoom_yofs != old_zoom_yofs)) { /* This can only occur, if either canvas size or widget size changes */ /* So I think we can request full redraw here */ /* More stuff - we have to mark root as needing fresh affine (Lauris) */ if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) { canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; eel_canvas_request_update (canvas); } gtk_widget_queue_draw (GTK_WIDGET (canvas)); } hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)); vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)); if (((int) gtk_adjustment_get_value (hadjustment)) != cx) { gtk_adjustment_set_value (hadjustment, cx); changed_x = TRUE; } if (((int) gtk_adjustment_get_value (vadjustment)) != cy) { gtk_adjustment_set_value (vadjustment, cy); changed_y = TRUE; } gtk_layout_get_size (&canvas->layout, &width, &height); if ((scroll_width != (int) width )|| (scroll_height != (int) height)) { gtk_layout_set_size (GTK_LAYOUT (canvas), scroll_width, scroll_height); } /* Signal GtkLayout that it should do a redraw. */ if (changed_x) g_signal_emit_by_name (hadjustment, "value_changed"); if (changed_y) g_signal_emit_by_name (vadjustment, "value_changed"); } /* Size allocation handler for the canvas */ static void eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EelCanvas *canvas; GtkAdjustment *vadjustment, *hadjustment; g_return_if_fail (EEL_IS_CANVAS (widget)); g_return_if_fail (allocation != NULL); if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation); canvas = EEL_CANVAS (widget); /* Recenter the view, if appropriate */ hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)); vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)); gtk_adjustment_set_page_size (hadjustment, allocation->width); gtk_adjustment_set_page_increment (hadjustment, allocation->width / 2); gtk_adjustment_set_page_size (vadjustment, allocation->height); gtk_adjustment_set_page_increment (vadjustment, allocation->height / 2); scroll_to (canvas, gtk_adjustment_get_value (hadjustment), gtk_adjustment_get_value (vadjustment)); g_signal_emit_by_name (hadjustment, "changed"); g_signal_emit_by_name (vadjustment, "changed"); } /* Emits an event for an item in the canvas, be it the current item, grabbed * item, or focused item, as appropriate. */ static int emit_event (EelCanvas *canvas, GdkEvent *event) { GdkEvent ev; gint finished; EelCanvasItem *item; EelCanvasItem *parent; guint mask; /* Could be an old pick event */ if (!gtk_widget_get_realized (GTK_WIDGET (canvas))) { return FALSE; } /* Perform checks for grabbed items */ if (canvas->grabbed_item && !is_descendant (canvas->current_item, canvas->grabbed_item)) { return FALSE; } if (canvas->grabbed_item) { switch ((int) event->type) { case GDK_ENTER_NOTIFY: mask = GDK_ENTER_NOTIFY_MASK; break; case GDK_LEAVE_NOTIFY: mask = GDK_LEAVE_NOTIFY_MASK; break; case GDK_MOTION_NOTIFY: mask = GDK_POINTER_MOTION_MASK; break; case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: mask = GDK_BUTTON_PRESS_MASK; break; case GDK_BUTTON_RELEASE: mask = GDK_BUTTON_RELEASE_MASK; break; case GDK_KEY_PRESS: mask = GDK_KEY_PRESS_MASK; break; case GDK_KEY_RELEASE: mask = GDK_KEY_RELEASE_MASK; break; default: mask = 0; break; } if (!(mask & canvas->grabbed_event_mask)) return FALSE; } /* Convert to world coordinates -- we have two cases because of diferent * offsets of the fields in the event structures. */ ev = *event; switch ((int) ev.type) { case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: eel_canvas_window_to_world (canvas, ev.crossing.x, ev.crossing.y, &ev.crossing.x, &ev.crossing.y); break; case GDK_MOTION_NOTIFY: eel_canvas_window_to_world (canvas, ev.motion.x, ev.motion.y, &ev.motion.x, &ev.motion.y); break; case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: eel_canvas_window_to_world (canvas, ev.motion.x, ev.motion.y, &ev.motion.x, &ev.motion.y); break; case GDK_BUTTON_RELEASE: eel_canvas_window_to_world (canvas, ev.motion.x, ev.motion.y, &ev.motion.x, &ev.motion.y); break; default: break; } /* Choose where we send the event */ item = canvas->current_item; if (canvas->focused_item && ((event->type == GDK_KEY_PRESS) || (event->type == GDK_KEY_RELEASE) || (event->type == GDK_FOCUS_CHANGE))) item = canvas->focused_item; /* The event is propagated up the hierarchy (for if someone connected to * a group instead of a leaf event), and emission is stopped if a * handler returns TRUE, just like for GtkWidget events. */ finished = FALSE; while (item && !finished) { g_object_ref (item); g_signal_emit ( G_OBJECT (item), item_signals[ITEM_EVENT], 0, &ev, &finished); parent = item->parent; g_object_unref (item); item = parent; } return finished; } /* Re-picks the current item in the canvas, based on the event's coordinates. * Also emits enter/leave events for items as appropriate. */ static int pick_current_item (EelCanvas *canvas, GdkEvent *event) { int button_down; double x, y; int cx, cy; int retval; retval = FALSE; /* If a button is down, we'll perform enter and leave events on the * current item, but not enter on any other item. This is more or less * like X pointer grabbing for canvas items. */ button_down = canvas->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK); if (!button_down) canvas->left_grabbed_item = FALSE; /* Save the event in the canvas. This is used to synthesize enter and * leave events in case the current item changes. It is also used to * re-pick the current item if the current one gets deleted. Also, * synthesize an enter event. */ if (event != &canvas->pick_event) { if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) { /* these fields have the same offsets in both types of events */ canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY; canvas->pick_event.crossing.window = event->motion.window; canvas->pick_event.crossing.send_event = event->motion.send_event; canvas->pick_event.crossing.subwindow = NULL; canvas->pick_event.crossing.x = event->motion.x; canvas->pick_event.crossing.y = event->motion.y; canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL; canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR; canvas->pick_event.crossing.focus = FALSE; canvas->pick_event.crossing.state = event->motion.state; /* these fields don't have the same offsets in both types of events */ if (event->type == GDK_MOTION_NOTIFY) { canvas->pick_event.crossing.x_root = event->motion.x_root; canvas->pick_event.crossing.y_root = event->motion.y_root; } else { canvas->pick_event.crossing.x_root = event->button.x_root; canvas->pick_event.crossing.y_root = event->button.y_root; } } else canvas->pick_event = *event; } /* Don't do anything else if this is a recursive call */ if (canvas->in_repick) return retval; /* LeaveNotify means that there is no current item, so we don't look for one */ if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) { /* these fields don't have the same offsets in both types of events */ if (canvas->pick_event.type == GDK_ENTER_NOTIFY) { x = canvas->pick_event.crossing.x; y = canvas->pick_event.crossing.y; } else { x = canvas->pick_event.motion.x; y = canvas->pick_event.motion.y; } /* canvas pixel coords */ cx = (int) (x + 0.5); cy = (int) (y + 0.5); /* world coords */ eel_canvas_c2w (canvas, cx, cy, &x, &y); /* find the closest item */ if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &canvas->new_current_item); else canvas->new_current_item = NULL; } else canvas->new_current_item = NULL; if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item) return retval; /* current item did not change */ /* Synthesize events for old and new current items */ if ((canvas->new_current_item != canvas->current_item) && (canvas->current_item != NULL) && !canvas->left_grabbed_item) { GdkEvent new_event; new_event = canvas->pick_event; new_event.type = GDK_LEAVE_NOTIFY; new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; new_event.crossing.subwindow = NULL; canvas->in_repick = TRUE; retval = emit_event (canvas, &new_event); canvas->in_repick = FALSE; } /* new_current_item may have been set to NULL during the call to emit_event() above */ if ((canvas->new_current_item != canvas->current_item) && button_down) { canvas->left_grabbed_item = TRUE; return retval; } /* Handle the rest of cases */ canvas->left_grabbed_item = FALSE; canvas->current_item = canvas->new_current_item; if (canvas->current_item != NULL) { GdkEvent new_event; new_event = canvas->pick_event; new_event.type = GDK_ENTER_NOTIFY; new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; new_event.crossing.subwindow = NULL; retval = emit_event (canvas, &new_event); } return retval; } /* Button event handler for the canvas */ static gint eel_canvas_button (GtkWidget *widget, GdkEventButton *event) { EelCanvas *canvas; int mask; int retval; g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); /* Don't handle extra mouse button events */ if (event->button > 5) return FALSE; retval = FALSE; canvas = EEL_CANVAS (widget); /* * dispatch normally regardless of the event's window if an item has * has a pointer grab in effect */ if (!canvas->grabbed_item && event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas))) return retval; switch (event->button) { case 1: mask = GDK_BUTTON1_MASK; break; case 2: mask = GDK_BUTTON2_MASK; break; case 3: mask = GDK_BUTTON3_MASK; break; case 4: mask = GDK_BUTTON4_MASK; break; case 5: mask = GDK_BUTTON5_MASK; break; default: mask = 0; } switch ((int) event->type) { case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: /* Pick the current item as if the button were not pressed, and * then process the event. */ event->state ^= mask; canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); event->state ^= mask; canvas->state = event->state; retval = emit_event (canvas, (GdkEvent *) event); break; case GDK_BUTTON_RELEASE: /* Process the event as if the button were pressed, then repick * after the button has been released */ canvas->state = event->state; retval = emit_event (canvas, (GdkEvent *) event); event->state ^= mask; canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); event->state ^= mask; break; default: g_assert_not_reached (); } return retval; } /* Motion event handler for the canvas */ static gint eel_canvas_motion (GtkWidget *widget, GdkEventMotion *event) { EelCanvas *canvas; g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); canvas = EEL_CANVAS (widget); if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas))) return FALSE; canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); return emit_event (canvas, (GdkEvent *) event); } /* Key event handler for the canvas */ static gint eel_canvas_key (GtkWidget *widget, GdkEventKey *event) { EelCanvas *canvas; g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); canvas = EEL_CANVAS (widget); if (emit_event (canvas, (GdkEvent *) event)) return TRUE; if (event->type == GDK_KEY_RELEASE) return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, event); else return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, event); } /* Crossing event handler for the canvas */ static gint eel_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event) { EelCanvas *canvas; g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); canvas = EEL_CANVAS (widget); if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas))) return FALSE; canvas->state = event->state; return pick_current_item (canvas, (GdkEvent *) event); } /* Focus in handler for the canvas */ static gint eel_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event) { EelCanvas *canvas; canvas = EEL_CANVAS (widget); if (canvas->focused_item) return emit_event (canvas, (GdkEvent *) event); else return FALSE; } static AtkObject * eel_canvas_get_accessible (GtkWidget *widget) { return atk_gobject_accessible_for_object (G_OBJECT (widget)); } /* Focus out handler for the canvas */ static gint eel_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event) { EelCanvas *canvas; canvas = EEL_CANVAS (widget); if (canvas->focused_item) return emit_event (canvas, (GdkEvent *) event); else return FALSE; } static cairo_region_t * eel_cairo_get_clip_region (cairo_t *cr) { cairo_rectangle_list_t *list; cairo_region_t *region; int i; list = cairo_copy_clip_rectangle_list (cr); if (list->status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) { cairo_rectangle_int_t clip_rect; cairo_rectangle_list_destroy (list); if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) return NULL; return cairo_region_create_rectangle (&clip_rect); } region = cairo_region_create (); for (i = list->num_rectangles - 1; i >= 0; --i) { cairo_rectangle_t *rect = &list->rectangles[i]; cairo_rectangle_int_t clip_rect; clip_rect.x = floor (rect->x); clip_rect.y = floor (rect->y); clip_rect.width = ceil (rect->x + rect->width) - clip_rect.x; clip_rect.height = ceil (rect->y + rect->height) - clip_rect.y; if (cairo_region_union_rectangle (region, &clip_rect) != CAIRO_STATUS_SUCCESS) { cairo_region_destroy (region); region = NULL; break; } } cairo_rectangle_list_destroy (list); return region; } /* Expose handler for the canvas */ static gboolean eel_canvas_draw (GtkWidget *widget, cairo_t *cr) { EelCanvas *canvas; GdkWindow *bin_window; cairo_region_t *region; if (!gdk_cairo_get_clip_rectangle (cr, NULL)) return FALSE; bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); if (!gtk_cairo_should_draw_window (cr, bin_window)) return FALSE; cairo_save (cr); gtk_cairo_transform_to_window (cr, widget, bin_window); region = eel_cairo_get_clip_region (cr); if (region == NULL) { cairo_restore (cr); return FALSE; } #ifdef VERBOSE g_print ("Draw\n"); #endif /* If there are any outstanding items that need updating, do them now */ canvas = EEL_CANVAS (widget); if (canvas->idle_id) { g_source_remove (canvas->idle_id); canvas->idle_id = 0; } if (canvas->need_update) { g_return_val_if_fail (!canvas->doing_update, FALSE); canvas->doing_update = TRUE; eel_canvas_item_invoke_update (canvas->root, 0, 0, 0); g_return_val_if_fail (canvas->doing_update, FALSE); canvas->doing_update = FALSE; canvas->need_update = FALSE; } /* Hmmm. Would like to queue antiexposes if the update marked anything that is gonna get redrawn as invalid */ g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0, cr); if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->draw (canvas->root, cr, region); cairo_restore (cr); /* Chain up to get exposes on child widgets */ if (GTK_WIDGET_CLASS (canvas_parent_class)->draw) GTK_WIDGET_CLASS (canvas_parent_class)->draw (widget, cr); cairo_region_destroy (region); return FALSE; } static void eel_canvas_draw_background (EelCanvas *canvas, cairo_t *cr) { cairo_rectangle_int_t rect; GtkStyleContext *style_context; GdkRGBA color; if (!gdk_cairo_get_clip_rectangle (cr, &rect)) return; cairo_save (cr); /* By default, we use the style background. */ style_context = gtk_widget_get_style_context (GTK_WIDGET (canvas)); gtk_style_context_get_background_color (style_context, GTK_STATE_FLAG_NORMAL, &color); gdk_cairo_set_source_rgba (cr, &color); gdk_cairo_rectangle (cr, &rect); cairo_fill (cr); cairo_restore (cr); } static void do_update (EelCanvas *canvas) { /* Cause the update if necessary */ update_again: if (canvas->need_update) { g_return_if_fail (!canvas->doing_update); canvas->doing_update = TRUE; eel_canvas_item_invoke_update (canvas->root, 0, 0, 0); g_return_if_fail (canvas->doing_update); canvas->doing_update = FALSE; canvas->need_update = FALSE; } /* Pick new current item */ while (canvas->need_repick) { canvas->need_repick = FALSE; pick_current_item (canvas, &canvas->pick_event); } /* it is possible that during picking we emitted an event in which the user then called some function which then requested update of something. Without this we'd be left in a state where need_update would have been left TRUE and the canvas would have been left unpainted. */ if (canvas->need_update) { goto update_again; } } /* Idle handler for the canvas. It deals with pending updates and redraws. */ static gint idle_handler (gpointer data) { EelCanvas *canvas; canvas = EEL_CANVAS (data); do_update (canvas); /* Reset idle id */ canvas->idle_id = 0; return FALSE; } /* Convenience function to add an idle handler to a canvas */ static void add_idle (EelCanvas *canvas) { if (!canvas->idle_id) { /* We let the update idle handler have higher priority * than the redraw idle handler so the canvas state * will be updated during the expose event. canvas in * expose_event. */ canvas->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW - 20, idle_handler, canvas, NULL); } } /** * eel_canvas_root: * @canvas: A canvas. * * Queries the root group of a canvas. * * Return value: The root group of the specified canvas. **/ EelCanvasGroup * eel_canvas_root (EelCanvas *canvas) { g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL); return EEL_CANVAS_GROUP (canvas->root); } /** * eel_canvas_set_scroll_region: * @canvas: A canvas. * @x1: Leftmost limit of the scrolling region. * @y1: Upper limit of the scrolling region. * @x2: Rightmost limit of the scrolling region. * @y2: Lower limit of the scrolling region. * * Sets the scrolling region of a canvas to the specified rectangle. The canvas * will then be able to scroll only within this region. The view of the canvas * is adjusted as appropriate to display as much of the new region as possible. **/ void eel_canvas_set_scroll_region (EelCanvas *canvas, double x1, double y1, double x2, double y2) { double wxofs, wyofs; int xofs, yofs; g_return_if_fail (EEL_IS_CANVAS (canvas)); if ((canvas->scroll_x1 == x1) && (canvas->scroll_y1 == y1) && (canvas->scroll_x2 == x2) && (canvas->scroll_y2 == y2)) { return; } /* * Set the new scrolling region. If possible, do not move the visible contents of the * canvas. */ eel_canvas_c2w (canvas, gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas))) + canvas->zoom_xofs, gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas))) + canvas->zoom_yofs, /*canvas->zoom_xofs, canvas->zoom_yofs,*/ &wxofs, &wyofs); canvas->scroll_x1 = x1; canvas->scroll_y1 = y1; canvas->scroll_x2 = x2; canvas->scroll_y2 = y2; eel_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs); scroll_to (canvas, xofs, yofs); canvas->need_repick = TRUE; if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) { canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; eel_canvas_request_update (canvas); } } /** * eel_canvas_get_scroll_region: * @canvas: A canvas. * @x1: Leftmost limit of the scrolling region (return value). * @y1: Upper limit of the scrolling region (return value). * @x2: Rightmost limit of the scrolling region (return value). * @y2: Lower limit of the scrolling region (return value). * * Queries the scrolling region of a canvas. **/ void eel_canvas_get_scroll_region (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2) { g_return_if_fail (EEL_IS_CANVAS (canvas)); if (x1) *x1 = canvas->scroll_x1; if (y1) *y1 = canvas->scroll_y1; if (x2) *x2 = canvas->scroll_x2; if (y2) *y2 = canvas->scroll_y2; } void eel_canvas_set_center_scroll_region (EelCanvas *canvas, gboolean center_scroll_region) { g_return_if_fail (EEL_IS_CANVAS (canvas)); canvas->center_scroll_region = center_scroll_region != 0; scroll_to (canvas, gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (&canvas->layout))), gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (&canvas->layout)))); } /** * eel_canvas_set_pixels_per_unit: * @canvas: A canvas. * @n: The number of pixels that correspond to one canvas unit. * * Sets the zooming factor of a canvas by specifying the number of pixels that * correspond to one canvas unit. **/ void eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n) { GtkWidget *widget; double cx, cy; int x1, y1; int center_x, center_y; GdkWindow *window; GdkWindowAttr attributes; gint attributes_mask; GtkAllocation allocation; GtkAdjustment *vadjustment, *hadjustment; g_return_if_fail (EEL_IS_CANVAS (canvas)); g_return_if_fail (n > EEL_CANVAS_EPSILON); widget = GTK_WIDGET (canvas); gtk_widget_get_allocation (widget, &allocation); center_x = allocation.width / 2; center_y = allocation.height / 2; /* Find the coordinates of the screen center in units. */ hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)); vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)); cx = (gtk_adjustment_get_value (hadjustment) + center_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs; cy = (gtk_adjustment_get_value (vadjustment) + center_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs; /* Now calculate the new offset of the upper left corner. (round not truncate) */ x1 = ((cx - canvas->scroll_x1) * n) - center_x + .5; y1 = ((cy - canvas->scroll_y1) * n) - center_y + .5; canvas->pixels_per_unit = n; if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) { canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; eel_canvas_request_update (canvas); } /* Map a background None window over the bin_window to avoid * scrolling the window scroll causing exposes. */ window = NULL; if (gtk_widget_get_mapped (widget)) { attributes.window_type = GDK_WINDOW_CHILD; gtk_widget_get_allocation (widget, &allocation); attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (window, widget); gdk_window_show (window); } scroll_to (canvas, x1, y1); /* If we created a an overlapping background None window, remove it how. * * TODO: We would like to temporarily set the bin_window background to * None to avoid clearing the bin_window to the background, but gdk doesn't * expose enought to let us do this, so we get a flash-effect here. At least * it looks better than scroll + expose. */ if (window != NULL) { gdk_window_hide (window); gdk_window_set_user_data (window, NULL); gdk_window_destroy (window); } canvas->need_repick = TRUE; } /** * eel_canvas_scroll_to: * @canvas: A canvas. * @cx: Horizontal scrolling offset in canvas pixel units. * @cy: Vertical scrolling offset in canvas pixel units. * * Makes a canvas scroll to the specified offsets, given in canvas pixel units. * The canvas will adjust the view so that it is not outside the scrolling * region. This function is typically not used, as it is better to hook * scrollbars to the canvas layout's scrolling adjusments. **/ void eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy) { g_return_if_fail (EEL_IS_CANVAS (canvas)); scroll_to (canvas, cx, cy); } /** * eel_canvas_get_scroll_offsets: * @canvas: A canvas. * @cx: Horizontal scrolling offset (return value). * @cy: Vertical scrolling offset (return value). * * Queries the scrolling offsets of a canvas. The values are returned in canvas * pixel units. **/ void eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy) { g_return_if_fail (EEL_IS_CANVAS (canvas)); if (cx) *cx = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas))); if (cy) *cy = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas))); } /** * eel_canvas_update_now: * @canvas: A canvas. * * Forces an immediate update and redraw of a canvas. If the canvas does not * have any pending update or redraw requests, then no action is taken. This is * typically only used by applications that need explicit control of when the * display is updated, like games. It is not needed by normal applications. */ void eel_canvas_update_now (EelCanvas *canvas) { g_return_if_fail (EEL_IS_CANVAS (canvas)); if (!(canvas->need_update || canvas->need_redraw)) return; remove_idle (canvas); do_update (canvas); } /** * eel_canvas_get_item_at: * @canvas: A canvas. * @x: X position in world coordinates. * @y: Y position in world coordinates. * * Looks for the item that is under the specified position, which must be * specified in world coordinates. * * Return value: The sought item, or NULL if no item is at the specified * coordinates. **/ EelCanvasItem * eel_canvas_get_item_at (EelCanvas *canvas, double x, double y) { EelCanvasItem *item; double dist; int cx, cy; g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL); eel_canvas_w2c (canvas, x, y, &cx, &cy); dist = eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item); if ((int) (dist * canvas->pixels_per_unit + 0.5) <= canvas->close_enough) return item; else return NULL; } /* Queues an update of the canvas */ static void eel_canvas_request_update (EelCanvas *canvas) { EEL_CANVAS_GET_CLASS (canvas)->request_update (canvas); } static void eel_canvas_request_update_real (EelCanvas *canvas) { canvas->need_update = TRUE; add_idle (canvas); } /** * eel_canvas_request_redraw: * @canvas: A canvas. * @x1: Leftmost coordinate of the rectangle to be redrawn. * @y1: Upper coordinate of the rectangle to be redrawn. * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1. * @y2: Lower coordinate of the rectangle to be redrawn, plus 1. * * Convenience function that informs a canvas that the specified rectangle needs * to be repainted. The rectangle includes @x1 and @y1, but not @x2 and @y2. * To be used only by item implementations. **/ void eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2) { GdkRectangle bbox; g_return_if_fail (EEL_IS_CANVAS (canvas)); if (!gtk_widget_is_drawable (GTK_WIDGET (canvas)) || (x1 >= x2) || (y1 >= y2)) return; bbox.x = x1; bbox.y = y1; bbox.width = x2 - x1; bbox.height = y2 - y1; gdk_window_invalidate_rect (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)), &bbox, FALSE); } /** * eel_canvas_w2c: * @canvas: A canvas. * @wx: World X coordinate. * @wy: World Y coordinate. * @cx: X pixel coordinate (return value). * @cy: Y pixel coordinate (return value). * * Converts world coordinates into canvas pixel coordinates. **/ void eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy) { double zoom; g_return_if_fail (EEL_IS_CANVAS (canvas)); zoom = canvas->pixels_per_unit; if (cx) *cx = floor ((wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs + 0.5); if (cy) *cy = floor ((wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs + 0.5); } /** * eel_canvas_w2c: * @canvas: A canvas. * @world: rectangle in world coordinates. * @canvas: rectangle in canvase coordinates. * * Converts rectangles in world coordinates into canvas pixel coordinates. **/ void eel_canvas_w2c_rect_d (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2) { eel_canvas_w2c_d (canvas, *x1, *y1, x1, y1); eel_canvas_w2c_d (canvas, *x2, *y2, x2, y2); } /** * eel_canvas_w2c_d: * @canvas: A canvas. * @wx: World X coordinate. * @wy: World Y coordinate. * @cx: X pixel coordinate (return value). * @cy: Y pixel coordinate (return value). * * Converts world coordinates into canvas pixel coordinates. This version * produces coordinates in floating point coordinates, for greater precision. **/ void eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy) { double zoom; g_return_if_fail (EEL_IS_CANVAS (canvas)); zoom = canvas->pixels_per_unit; if (cx) *cx = (wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs; if (cy) *cy = (wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs; } /** * eel_canvas_c2w: * @canvas: A canvas. * @cx: Canvas pixel X coordinate. * @cy: Canvas pixel Y coordinate. * @wx: X world coordinate (return value). * @wy: Y world coordinate (return value). * * Converts canvas pixel coordinates to world coordinates. **/ void eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy) { double zoom; g_return_if_fail (EEL_IS_CANVAS (canvas)); zoom = canvas->pixels_per_unit; if (wx) *wx = (cx - canvas->zoom_xofs)/zoom + canvas->scroll_x1; if (wy) *wy = (cy - canvas->zoom_yofs)/zoom + canvas->scroll_y1; } /** * eel_canvas_window_to_world: * @canvas: A canvas. * @winx: Window-relative X coordinate. * @winy: Window-relative Y coordinate. * @worldx: X world coordinate (return value). * @worldy: Y world coordinate (return value). * * Converts window-relative coordinates into world coordinates. You can use * this when you need to convert mouse coordinates into world coordinates, for * example. * Window coordinates are really the same as canvas coordinates now, but this * function is here for backwards compatibility reasons. **/ void eel_canvas_window_to_world (EelCanvas *canvas, double winx, double winy, double *worldx, double *worldy) { g_return_if_fail (EEL_IS_CANVAS (canvas)); if (worldx) *worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs) / canvas->pixels_per_unit); if (worldy) *worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs) / canvas->pixels_per_unit); } /** * eel_canvas_world_to_window: * @canvas: A canvas. * @worldx: World X coordinate. * @worldy: World Y coordinate. * @winx: X window-relative coordinate. * @winy: Y window-relative coordinate. * * Converts world coordinates into window-relative coordinates. * Window coordinates are really the same as canvas coordinates now, but this * function is here for backwards compatibility reasons. **/ void eel_canvas_world_to_window (EelCanvas *canvas, double worldx, double worldy, double *winx, double *winy) { g_return_if_fail (EEL_IS_CANVAS (canvas)); if (winx) *winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs; if (winy) *winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs; } static gboolean boolean_handled_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer data) { gboolean signal_handled; signal_handled = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, signal_handled); return !signal_handled; } static guint eel_canvas_item_accessible_add_focus_handler (AtkComponent *component, AtkFocusHandler handler) { GSignalMatchType match_type; guint signal_id; match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC; signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT); if (!g_signal_handler_find (component, match_type, signal_id, 0, NULL, (gpointer) handler, NULL)) { return g_signal_connect_closure_by_id (component, signal_id, 0, g_cclosure_new ( G_CALLBACK (handler), NULL, (GClosureNotify) NULL), FALSE); } return 0; } static void eel_canvas_item_accessible_get_item_extents (EelCanvasItem *item, GdkRectangle *rect) { double bx1, bx2, by1, by2; gint scroll_x, scroll_y; gint x1, x2, y1, y2; eel_canvas_item_get_bounds (item, &bx1, &by1, &bx2, &by2); eel_canvas_w2c_rect_d (item->canvas, &bx1, &by1, &bx2, &by2); eel_canvas_get_scroll_offsets (item->canvas, &scroll_x, &scroll_y); x1 = floor (bx1 + .5); y1 = floor (by1 + .5); x2 = floor (bx2 + .5); y2 = floor (by2 + .5); rect->x = x1 - scroll_x; rect->y = y1 - scroll_y; rect->width = x2 - x1; rect->height = y2 - y1; } static gboolean eel_canvas_item_accessible_is_item_in_window (EelCanvasItem *item, GdkRectangle *rect) { GtkWidget *widget; gboolean retval; widget = GTK_WIDGET (item->canvas); if (gtk_widget_get_window (widget)) { int window_width, window_height; gdk_window_get_geometry (gtk_widget_get_window (widget), NULL, NULL, &window_width, &window_height); /* * Check whether rectangles intersect */ if (rect->x + rect->width < 0 || rect->y + rect->height < 0 || rect->x > window_width || rect->y > window_height) { retval = FALSE; } else { retval = TRUE; } } else { retval = FALSE; } return retval; } static void eel_canvas_item_accessible_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { GObject *obj; EelCanvasItem *item; gint window_x, window_y; gint toplevel_x, toplevel_y; GdkRectangle rect; GdkWindow *window; GtkWidget *canvas; obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)); if (obj == NULL) { /* item is defunct */ return; } /* Get the CanvasItem */ item = EEL_CANVAS_ITEM (obj); /* If this item has no parent canvas, something's broken */ g_return_if_fail (GTK_IS_WIDGET (item->canvas)); eel_canvas_item_accessible_get_item_extents (item, &rect); *width = rect.width; *height = rect.height; if (!eel_canvas_item_accessible_is_item_in_window (item, &rect)) { *x = G_MININT; *y = G_MININT; return; } canvas = GTK_WIDGET (item->canvas); window = gtk_widget_get_parent_window (canvas); gdk_window_get_origin (window, &window_x, &window_y); *x = rect.x + window_x; *y = rect.y + window_y; if (coord_type == ATK_XY_WINDOW) { window = gdk_window_get_toplevel (gtk_widget_get_window (canvas)); gdk_window_get_origin (window, &toplevel_x, &toplevel_y); *x -= toplevel_x; *y -= toplevel_y; } return; } static gint eel_canvas_item_accessible_get_mdi_zorder (AtkComponent *component) { GObject *g_obj; EelCanvasItem *item; g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)); if (g_obj == NULL) { /* Object is defunct */ return -1; } item = EEL_CANVAS_ITEM (g_obj); if (item->parent) { return g_list_index (EEL_CANVAS_GROUP (item->parent)->item_list, item); } else { g_return_val_if_fail (item->canvas->root == item, -1); return 0; } } static gboolean eel_canvas_item_accessible_grab_focus (AtkComponent *component) { GObject *obj; EelCanvasItem *item; GtkWidget *toplevel; obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)); item = EEL_CANVAS_ITEM (obj); if (item == NULL) { /* item is defunct */ return FALSE; } eel_canvas_item_grab_focus (item); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->canvas)); if (gtk_widget_is_toplevel (toplevel)) { gtk_window_present (GTK_WINDOW (toplevel)); } return TRUE; } static void eel_canvas_item_accessible_remove_focus_handler (AtkComponent *component, guint handler_id) { g_signal_handler_disconnect (component, handler_id); } static void eel_canvas_item_accessible_component_interface_init (AtkComponentIface *iface) { g_return_if_fail (iface != NULL); iface->add_focus_handler = eel_canvas_item_accessible_add_focus_handler; iface->get_extents = eel_canvas_item_accessible_get_extents; iface->get_mdi_zorder = eel_canvas_item_accessible_get_mdi_zorder; iface->grab_focus = eel_canvas_item_accessible_grab_focus; iface->remove_focus_handler = eel_canvas_item_accessible_remove_focus_handler; } static gboolean eel_canvas_item_accessible_is_item_on_screen (EelCanvasItem *item) { GdkRectangle rect; eel_canvas_item_accessible_get_item_extents (item, &rect); return eel_canvas_item_accessible_is_item_in_window (item, &rect); } static void eel_canvas_item_accessible_initialize (AtkObject *obj, gpointer data) { if (ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize != NULL) ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize (obj, data); g_object_set_data (G_OBJECT (obj), "atk-component-layer", GINT_TO_POINTER (ATK_LAYER_MDI)); } static AtkStateSet* eel_canvas_item_accessible_ref_state_set (AtkObject *accessible) { GObject *obj; EelCanvasItem *item; AtkStateSet *state_set; state_set = ATK_OBJECT_CLASS (accessible_item_parent_class)->ref_state_set (accessible); obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); item = EEL_CANVAS_ITEM (obj); if (item == NULL) { atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); } else { if (item->flags & EEL_CANVAS_ITEM_VISIBLE) { atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); if (eel_canvas_item_accessible_is_item_on_screen (item)) { atk_state_set_add_state (state_set, ATK_STATE_SHOWING); } } if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); if (item->canvas->focused_item == item) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } } } return state_set; } static void eel_canvas_item_accessible_class_init (AtkObjectClass *klass) { accessible_item_parent_class = g_type_class_peek_parent (klass); klass->initialize = eel_canvas_item_accessible_initialize; klass->ref_state_set = eel_canvas_item_accessible_ref_state_set; } static GType eel_canvas_item_accessible_get_type (void) { static GType type = 0; if (!type) { static const GInterfaceInfo atk_component_info = { (GInterfaceInitFunc) eel_canvas_item_accessible_component_interface_init, (GInterfaceFinalizeFunc) NULL, NULL }; AtkObjectFactory *factory; GType parent_atk_type; GTypeQuery query; GTypeInfo tinfo = { 0 }; factory = atk_registry_get_factory (atk_get_default_registry(), G_TYPE_INITIALLY_UNOWNED); if (!factory) { return G_TYPE_INVALID; } parent_atk_type = atk_object_factory_get_accessible_type (factory); if (!parent_atk_type) { return G_TYPE_INVALID; } g_type_query (parent_atk_type, &query); tinfo.class_init = (GClassInitFunc) eel_canvas_item_accessible_class_init; tinfo.class_size = query.class_size; tinfo.instance_size = query.instance_size; type = g_type_register_static (parent_atk_type, "EelCanvasItemAccessibility", &tinfo, 0); g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); } return type; } static AtkObject * eel_canvas_item_accessible_create (GObject *for_object) { GType type; AtkObject *accessible; EelCanvasItem *item; item = EEL_CANVAS_ITEM (for_object); g_return_val_if_fail (item != NULL, NULL); type = eel_canvas_item_accessible_get_type (); if (type == G_TYPE_INVALID) { return atk_no_op_object_new (for_object); } accessible = g_object_new (type, NULL); atk_object_initialize (accessible, for_object); return accessible; } static GType eel_canvas_item_accessible_factory_get_accessible_type (void) { return eel_canvas_item_accessible_get_type (); } static AtkObject* eel_canvas_item_accessible_factory_create_accessible (GObject *obj) { g_return_val_if_fail (G_IS_OBJECT (obj), NULL); return eel_canvas_item_accessible_create (obj); } static void eel_canvas_item_accessible_factory_class_init (AtkObjectFactoryClass *klass) { klass->create_accessible = eel_canvas_item_accessible_factory_create_accessible; klass->get_accessible_type = eel_canvas_item_accessible_factory_get_accessible_type; } static GType eel_canvas_item_accessible_factory_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo tinfo = { sizeof (AtkObjectFactoryClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eel_canvas_item_accessible_factory_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (AtkObjectFactory), 0, /* n_preallocs */ NULL }; type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, "EelCanvasItemAccessibilityFactory", &tinfo, 0); } return type; } /* Class initialization function for EelCanvasItemClass */ static void eel_canvas_item_class_init (EelCanvasItemClass *klass) { GObjectClass *gobject_class = (GObjectClass *) klass; item_parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = eel_canvas_item_set_property; gobject_class->get_property = eel_canvas_item_get_property; gobject_class->dispose = eel_canvas_item_dispose; g_object_class_install_property (gobject_class, ITEM_PROP_PARENT, g_param_spec_object ("parent", NULL, NULL, EEL_TYPE_CANVAS_ITEM, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, ITEM_PROP_VISIBLE, g_param_spec_boolean ("visible", NULL, NULL, TRUE, G_PARAM_READWRITE)); item_signals[ITEM_EVENT] = g_signal_new ("event", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EelCanvasItemClass, event), boolean_handled_accumulator, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); item_signals[ITEM_DESTROY] = g_signal_new ("destroy", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (EelCanvasItemClass, destroy), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); klass->realize = eel_canvas_item_realize; klass->unrealize = eel_canvas_item_unrealize; klass->map = eel_canvas_item_map; klass->unmap = eel_canvas_item_unmap; klass->update = eel_canvas_item_update; atk_registry_set_factory_type (atk_get_default_registry (), EEL_TYPE_CANVAS_ITEM, eel_canvas_item_accessible_factory_get_type ()); } nemo-4.4.2/eel/eel-canvas.h000066400000000000000000000453351357442400300154270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ /* * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation * All rights reserved. * * This file is part of the Gnome Library. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ /* @NOTATION@ */ /* EelCanvas widget - Tk-like canvas widget for Gnome * * EelCanvas is basically a port of the Tk toolkit's most excellent canvas * widget. Tk is copyrighted by the Regents of the University of California, * Sun Microsystems, and other parties. * * * Authors: Federico Mena * Raph Levien */ #ifndef EEL_CANVAS_H #define EEL_CANVAS_H #include #include #include G_BEGIN_DECLS /* "Small" value used by canvas stuff */ #define EEL_CANVAS_EPSILON 1e-10 /* Macros for building colors that fit in a 32-bit integer. The values are in * [0, 255]. */ #define EEL_CANVAS_COLOR(r, g, b) ((((int) (r) & 0xff) << 24) \ | (((int) (g) & 0xff) << 16) \ | (((int) (b) & 0xff) << 8) \ | 0xff) #define EEL_CANVAS_COLOR_A(r, g, b, a) ((((int) (r) & 0xff) << 24) \ | (((int) (g) & 0xff) << 16) \ | (((int) (b) & 0xff) << 8) \ | ((int) (a) & 0xff)) typedef struct _EelCanvas EelCanvas; typedef struct _EelCanvasClass EelCanvasClass; typedef struct _EelCanvasItem EelCanvasItem; typedef struct _EelCanvasItemClass EelCanvasItemClass; typedef struct _EelCanvasGroup EelCanvasGroup; typedef struct _EelCanvasGroupClass EelCanvasGroupClass; /* EelCanvasItem - base item class for canvas items * * All canvas items are derived from EelCanvasItem. The only information a * EelCanvasItem contains is its parent canvas, its parent canvas item group, * and its bounding box in world coordinates. * * Items inside a canvas are organized in a tree of EelCanvasItemGroup nodes * and EelCanvasItem leaves. Each canvas has a single root group, which can * be obtained with the eel_canvas_get_root() function. * * The abstract EelCanvasItem class does not have any configurable or * queryable attributes. */ /* Object flags for items */ enum { EEL_CANVAS_ITEM_REALIZED = 1 << 4, EEL_CANVAS_ITEM_MAPPED = 1 << 5, EEL_CANVAS_ITEM_ALWAYS_REDRAW = 1 << 6, EEL_CANVAS_ITEM_VISIBLE = 1 << 7, EEL_CANVAS_ITEM_NEED_UPDATE = 1 << 8, EEL_CANVAS_ITEM_NEED_DEEP_UPDATE = 1 << 9 }; /* Update flags for items */ enum { EEL_CANVAS_UPDATE_REQUESTED = 1 << 0, EEL_CANVAS_UPDATE_DEEP = 1 << 1 }; #define EEL_TYPE_CANVAS_ITEM (eel_canvas_item_get_type ()) #define EEL_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItem)) #define EEL_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) #define EEL_IS_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_ITEM)) #define EEL_IS_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ITEM)) #define EEL_CANVAS_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) struct _EelCanvasItem { GInitiallyUnowned object; /* Parent canvas for this item */ EelCanvas *canvas; /* Parent canvas group for this item (a EelCanvasGroup) */ EelCanvasItem *parent; /* Bounding box for this item (in canvas coordinates) */ double x1, y1, x2, y2; /* Object flags */ guint flags; }; struct _EelCanvasItemClass { GInitiallyUnownedClass parent_class; void (* destroy) (EelCanvasItem *item); /* Tell the item to update itself. The flags are from the update flags * defined above. The item should update its internal state from its * queued state, and recompute and request its repaint area. The * update method also recomputes the bounding box of the item. */ void (* update) (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); /* Realize an item -- create GCs, etc. */ void (* realize) (EelCanvasItem *item); /* Unrealize an item */ void (* unrealize) (EelCanvasItem *item); /* Map an item - normally only need by items with their own GdkWindows */ void (* map) (EelCanvasItem *item); /* Unmap an item */ void (* unmap) (EelCanvasItem *item); /* Draw an item of this type. (x, y) are the upper-left canvas pixel * coordinates of the drawable, a temporary pixmap, where things get * drawn. (width, height) are the dimensions of the drawable. */ void (* draw) (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region); /* Calculate the distance from an item to the specified point. It also * returns a canvas item which is the item itself in the case of the * object being an actual leaf item, or a child in case of the object * being a canvas group. (cx, cy) are the canvas pixel coordinates that * correspond to the item-relative coordinates (x, y). */ double (* point) (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item); void (* translate) (EelCanvasItem *item, double dx, double dy); /* Fetch the item's bounding box (need not be exactly tight). This * should be in item-relative coordinates. */ void (* bounds) (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); /* Signal: an event ocurred for an item of this type. The (x, y) * coordinates are in the canvas world coordinate system. */ gboolean (* event) (EelCanvasItem *item, GdkEvent *event); /* Reserved for future expansion */ gpointer spare_vmethods [4]; }; /* Standard Gtk function */ GType eel_canvas_item_get_type (void) G_GNUC_CONST; /* Create a canvas item using the standard Gtk argument mechanism. The item is * automatically inserted at the top of the specified canvas group. The last * argument must be a NULL pointer. */ EelCanvasItem *eel_canvas_item_new (EelCanvasGroup *parent, GType type, const gchar *first_arg_name, ...); void eel_canvas_item_destroy (EelCanvasItem *item); /* Constructors for use in derived classes and language wrappers */ void eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent, const gchar *first_arg_name, va_list args); /* Configure an item using the standard Gtk argument mechanism. The last * argument must be a NULL pointer. */ void eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...); /* Used only for language wrappers and the like */ void eel_canvas_item_set_valist (EelCanvasItem *item, const gchar *first_arg_name, va_list args); /* Move an item by the specified amount */ void eel_canvas_item_move (EelCanvasItem *item, double dx, double dy); /* Raise an item in the z-order of its parent group by the specified number of * positions. */ void eel_canvas_item_raise (EelCanvasItem *item, int positions); /* Lower an item in the z-order of its parent group by the specified number of * positions. */ void eel_canvas_item_lower (EelCanvasItem *item, int positions); /* Raise an item to the top of its parent group's z-order. */ void eel_canvas_item_raise_to_top (EelCanvasItem *item); /* Lower an item to the bottom of its parent group's z-order */ void eel_canvas_item_lower_to_bottom (EelCanvasItem *item); /* Send an item behind another item */ void eel_canvas_item_send_behind (EelCanvasItem *item, EelCanvasItem *behind_item); /* Show an item (make it visible). If the item is already shown, it has no * effect. */ void eel_canvas_item_show (EelCanvasItem *item); /* Hide an item (make it invisible). If the item is already invisible, it has * no effect. */ void eel_canvas_item_hide (EelCanvasItem *item); /* Grab the mouse for the specified item. Only the events in event_mask will be * reported. If cursor is non-NULL, it will be used during the duration of the * grab. Time is a proper X event time parameter. Returns the same values as * XGrabPointer(). */ GdkGrabStatus eel_canvas_item_grab (EelCanvasItem *item, GdkEventMask event_mask, GdkCursor *cursor, guint32 etime); /* Ungrabs the mouse -- the specified item must be the same that was passed to * eel_canvas_item_grab(). Time is a proper X event time parameter. */ void eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime); /* These functions convert from a coordinate system to another. "w" is world * coordinates and "i" is item coordinates. */ void eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y); void eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y); /* Remove the item from its parent group and make the new group its parent. The * item will be put on top of all the items in the new group. The item's * coordinates relative to its new parent to *not* change -- this means that the * item could potentially move on the screen. * * The item and the group must be in the same canvas. An item cannot be * reparented to a group that is the item itself or that is an inferior of the * item. */ void eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group); /* Used to send all of the keystroke events to a specific item as well as * GDK_FOCUS_CHANGE events. */ void eel_canvas_item_grab_focus (EelCanvasItem *item); /* Fetch the bounding box of the item. The bounding box may not be exactly * tight, but the canvas items will do the best they can. The returned bounding * box is in the coordinate system of the item's parent. */ void eel_canvas_item_get_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); /* Request that the update method eventually get called. This should be used * only by item implementations. */ void eel_canvas_item_request_update (EelCanvasItem *item); /* Request a redraw of the bounding box of the canvas item */ void eel_canvas_item_request_redraw (EelCanvasItem *item); /* EelCanvasGroup - a group of canvas items * * A group is a node in the hierarchical tree of groups/items inside a canvas. * Groups serve to give a logical structure to the items. * * Consider a circuit editor application that uses the canvas for its schematic * display. Hierarchically, there would be canvas groups that contain all the * components needed for an "adder", for example -- this includes some logic * gates as well as wires. You can move stuff around in a convenient way by * doing a eel_canvas_item_move() of the hierarchical groups -- to move an * adder, simply move the group that represents the adder. * * The following arguments are available: * * name type read/write description * -------------------------------------------------------------------------------- * x double RW X coordinate of group's origin * y double RW Y coordinate of group's origin */ #define EEL_TYPE_CANVAS_GROUP (eel_canvas_group_get_type ()) #define EEL_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroup)) #define EEL_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) #define EEL_IS_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_GROUP)) #define EEL_IS_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_GROUP)) #define EEL_CANVAS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) struct _EelCanvasGroup { EelCanvasItem item; double xpos, ypos; /* Children of the group */ GList *item_list; GList *item_list_end; }; struct _EelCanvasGroupClass { EelCanvasItemClass parent_class; }; /* Standard Gtk function */ GType eel_canvas_group_get_type (void) G_GNUC_CONST; /*** EelCanvas ***/ #define EEL_TYPE_CANVAS (eel_canvas_get_type ()) #define EEL_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS, EelCanvas)) #define EEL_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS, EelCanvasClass)) #define EEL_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS)) #define EEL_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS)) #define EEL_CANVAS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS, EelCanvasClass)) struct _EelCanvas { GtkLayout layout; /* Root canvas group */ EelCanvasItem *root; /* The item containing the mouse pointer, or NULL if none */ EelCanvasItem *current_item; /* Item that is about to become current (used to track deletions and such) */ EelCanvasItem *new_current_item; /* Item that holds a pointer grab, or NULL if none */ EelCanvasItem *grabbed_item; /* If non-NULL, the currently focused item */ EelCanvasItem *focused_item; /* Event on which selection of current item is based */ GdkEvent pick_event; /* Scrolling region */ double scroll_x1, scroll_y1; double scroll_x2, scroll_y2; /* Scaling factor to be used for display */ double pixels_per_unit; /* Idle handler ID */ guint idle_id; /* Signal handler ID for destruction of the root item */ guint root_destroy_id; /* Internal pixel offsets when zoomed out */ int zoom_xofs, zoom_yofs; /* Last known modifier state, for deferred repick when a button is down */ int state; /* Event mask specified when grabbing an item */ guint grabbed_event_mask; /* Tolerance distance for picking items */ int close_enough; /* Whether the canvas should center the canvas in the middle of * the window if the scroll region is smaller than the window */ unsigned int center_scroll_region : 1; /* Whether items need update at next idle loop iteration */ unsigned int need_update : 1; /* Are we in the midst of an update */ unsigned int doing_update : 1; /* Whether the canvas needs redrawing at the next idle loop iteration */ unsigned int need_redraw : 1; /* Whether current item will be repicked at next idle loop iteration */ unsigned int need_repick : 1; /* For use by internal pick_current_item() function */ unsigned int left_grabbed_item : 1; /* For use by internal pick_current_item() function */ unsigned int in_repick : 1; }; struct _EelCanvasClass { GtkLayoutClass parent_class; /* Draw the background for the area given. */ void (* draw_background) (EelCanvas *canvas, cairo_t *cr); /* Private Virtual methods for groping the canvas inside bonobo */ void (* request_update) (EelCanvas *canvas); /* Reserved for future expansion */ gpointer spare_vmethods [4]; }; /* Standard Gtk function */ GType eel_canvas_get_type (void) G_GNUC_CONST; /* Creates a new canvas. You should check that the canvas is created with the * proper visual and colormap. Any visual will do unless you intend to insert * gdk_imlib images into it, in which case you should use the gdk_imlib visual. * * You should call eel_canvas_set_scroll_region() soon after calling this * function to set the desired scrolling limits for the canvas. */ GtkWidget *eel_canvas_new (void); /* Returns the root canvas item group of the canvas */ EelCanvasGroup *eel_canvas_root (EelCanvas *canvas); /* Sets the limits of the scrolling region, in world coordinates */ void eel_canvas_set_scroll_region (EelCanvas *canvas, double x1, double y1, double x2, double y2); /* Gets the limits of the scrolling region, in world coordinates */ void eel_canvas_get_scroll_region (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2); /* Sets the number of pixels that correspond to one unit in world coordinates */ void eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n); /* Wether the canvas centers the scroll region if it is smaller than the window */ void eel_canvas_set_center_scroll_region (EelCanvas *canvas, gboolean center_scroll_region); /* Scrolls the canvas to the specified offsets, given in canvas pixel coordinates */ void eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy); /* Returns the scroll offsets of the canvas in canvas pixel coordinates. You * can specify NULL for any of the values, in which case that value will not be * queried. */ void eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy); /* Requests that the canvas be repainted immediately instead of in the idle * loop. */ void eel_canvas_update_now (EelCanvas *canvas); /* Returns the item that is at the specified position in world coordinates, or * NULL if no item is there. */ EelCanvasItem *eel_canvas_get_item_at (EelCanvas *canvas, double x, double y); /* For use only by item type implementations. Request that the canvas * eventually redraw the specified region, specified in canvas pixel * coordinates. The region contains (x1, y1) but not (x2, y2). */ void eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2); /* These functions convert from a coordinate system to another. "w" is world * coordinates, "c" is canvas pixel coordinates (pixel coordinates that are * (0,0) for the upper-left scrolling limit and something else for the * lower-left scrolling limit). */ void eel_canvas_w2c_rect_d (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2); void eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy); void eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy); void eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy); /* This function takes in coordinates relative to the GTK_LAYOUT * (canvas)->bin_window and converts them to world coordinates. * These days canvas coordinates and window coordinates are the same, but * these are left for backwards compat reasons. */ void eel_canvas_window_to_world (EelCanvas *canvas, double winx, double winy, double *worldx, double *worldy); /* This is the inverse of eel_canvas_window_to_world() */ void eel_canvas_world_to_window (EelCanvas *canvas, double worldx, double worldy, double *winx, double *winy); /* Accessible implementation */ GType eel_canvas_accessible_get_type(void); typedef struct _EelCanvasAccessible EelCanvasAccessible; struct _EelCanvasAccessible { GtkAccessible parent; }; typedef struct _EelCanvasAccessibleClass EelCanvasAccessibleClass; struct _EelCanvasAccessibleClass { GtkAccessibleClass parent_class; }; G_END_DECLS #endif nemo-4.4.2/eel/eel-debug.c000066400000000000000000000052161357442400300152270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-debug.c: Eel debugging aids. Copyright (C) 2000, 2001 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "eel-debug.h" #include #include #include typedef struct { gpointer data; GFreeFunc function; } ShutdownFunction; static GList *shutdown_functions; /* Raise a SIGINT signal to get the attention of the debugger. * When not running under the debugger, we don't want to stop, * so we ignore the signal for just the moment that we raise it. */ static void eel_stop_in_debugger (void) { void (* saved_handler) (int); saved_handler = signal (SIGINT, SIG_IGN); raise (SIGINT); signal (SIGINT, saved_handler); } /* Stop in the debugger after running the default log handler. * This makes certain kinds of messages stop in the debugger * without making them fatal (you can continue). */ static void log_handler (const char *domain, GLogLevelFlags level, const char *message, gpointer data) { g_log_default_handler (domain, level, message, data); if ((level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) != 0) { eel_stop_in_debugger (); } } void eel_make_warnings_and_criticals_stop_in_debugger (void) { g_log_set_default_handler (log_handler, NULL); } void eel_debug_shut_down (void) { ShutdownFunction *f; while (shutdown_functions != NULL) { f = shutdown_functions->data; shutdown_functions = g_list_remove (shutdown_functions, f); f->function (f->data); g_free (f); } } void eel_debug_call_at_shutdown (EelFunction function) { eel_debug_call_at_shutdown_with_data ((GFreeFunc) function, NULL); } void eel_debug_call_at_shutdown_with_data (GFreeFunc function, gpointer data) { ShutdownFunction *f; f = g_new (ShutdownFunction, 1); f->data = data; f->function = function; shutdown_functions = g_list_prepend (shutdown_functions, f); } nemo-4.4.2/eel/eel-debug.h000066400000000000000000000027501357442400300152340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-debug.h: Eel debugging aids. Copyright (C) 2000, 2001 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef EEL_DEBUG_H #define EEL_DEBUG_H #include G_BEGIN_DECLS typedef void (* EelFunction) (void); void eel_make_warnings_and_criticals_stop_in_debugger (void); /* A way to do cleanup at exit for compatibility with shutdown tools * like the ones in Bonobo. */ void eel_debug_shut_down (void); void eel_debug_call_at_shutdown (EelFunction function); void eel_debug_call_at_shutdown_with_data (GFreeFunc function, gpointer data); G_END_DECLS #endif /* EEL_DEBUG_H */ nemo-4.4.2/eel/eel-editable-label.c000066400000000000000000003674721357442400300170060ustar00rootroot00000000000000/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include #include #include #include "eel-editable-label.h" #include "eel-accessibility.h" #include #include #include #include #include enum { MOVE_CURSOR, POPULATE_POPUP, DELETE_FROM_CURSOR, CUT_CLIPBOARD, COPY_CLIPBOARD, PASTE_CLIPBOARD, TOGGLE_OVERWRITE, LAST_SIGNAL }; enum { PROP_0, PROP_TEXT, PROP_JUSTIFY, PROP_WRAP, PROP_CURSOR_POSITION, PROP_SELECTION_BOUND }; static guint signals[LAST_SIGNAL] = { 0 }; static void eel_editable_label_editable_init (GtkEditableInterface *iface); static void eel_editable_label_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void eel_editable_label_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void eel_editable_label_finalize (GObject *object); static void eel_editable_label_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void eel_editable_label_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); static void eel_editable_label_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void eel_editable_label_state_changed (GtkWidget *widget, GtkStateType state); static void eel_editable_label_style_updated (GtkWidget *widget); static void eel_editable_label_direction_changed (GtkWidget *widget, GtkTextDirection previous_dir); static gint eel_editable_label_draw (GtkWidget *widget, cairo_t *cr); static void eel_editable_label_realize (GtkWidget *widget); static void eel_editable_label_unrealize (GtkWidget *widget); static void eel_editable_label_map (GtkWidget *widget); static void eel_editable_label_unmap (GtkWidget *widget); static gint eel_editable_label_button_press (GtkWidget *widget, GdkEventButton *event); static gint eel_editable_label_button_release (GtkWidget *widget, GdkEventButton *event); static gint eel_editable_label_motion (GtkWidget *widget, GdkEventMotion *event); static gint eel_editable_label_key_press (GtkWidget *widget, GdkEventKey *event); static gint eel_editable_label_key_release (GtkWidget *widget, GdkEventKey *event); static gint eel_editable_label_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint eel_editable_label_focus_out (GtkWidget *widget, GdkEventFocus *event); static AtkObject *eel_editable_label_get_accessible (GtkWidget *widget); static void eel_editable_label_commit_cb (GtkIMContext *context, const gchar *str, EelEditableLabel *label); static void eel_editable_label_preedit_changed_cb (GtkIMContext *context, EelEditableLabel *label); static gboolean eel_editable_label_retrieve_surrounding_cb (GtkIMContext *context, EelEditableLabel *label); static gboolean eel_editable_label_delete_surrounding_cb (GtkIMContext *slave, gint offset, gint n_chars, EelEditableLabel *label); static void eel_editable_label_clear_layout (EelEditableLabel *label); static void eel_editable_label_recompute (EelEditableLabel *label); static void eel_editable_label_ensure_layout (EelEditableLabel *label, gboolean include_preedit); static void eel_editable_label_select_region_index (EelEditableLabel *label, gint anchor_index, gint end_index); static gboolean eel_editable_label_focus (GtkWidget *widget, GtkDirectionType direction); static void eel_editable_label_move_cursor (EelEditableLabel *label, GtkMovementStep step, gint count, gboolean extend_selection); static void eel_editable_label_delete_from_cursor (EelEditableLabel *label, GtkDeleteType type, gint count); static void eel_editable_label_copy_clipboard (EelEditableLabel *label); static void eel_editable_label_cut_clipboard (EelEditableLabel *label); static void eel_editable_label_paste (EelEditableLabel *label, GdkAtom selection); static void eel_editable_label_paste_clipboard (EelEditableLabel *label); static void eel_editable_label_select_all (EelEditableLabel *label); static void eel_editable_label_do_popup (EelEditableLabel *label, GdkEventButton *event); static void eel_editable_label_toggle_overwrite (EelEditableLabel *label); static gint eel_editable_label_move_forward_word (EelEditableLabel *label, gint start); static gint eel_editable_label_move_backward_word (EelEditableLabel *label, gint start); static void eel_editable_label_reset_im_context (EelEditableLabel *label); static void eel_editable_label_check_cursor_blink (EelEditableLabel *label); static void eel_editable_label_pend_cursor_blink (EelEditableLabel *label); /* Editable implementation: */ static void editable_insert_text_emit (GtkEditable *editable, const gchar *new_text, gint new_text_length, gint *position); static void editable_delete_text_emit (GtkEditable *editable, gint start_pos, gint end_pos); static void editable_insert_text (GtkEditable *editable, const gchar *new_text, gint new_text_length, gint *position); static void editable_delete_text (GtkEditable *editable, gint start_pos, gint end_pos); static gchar * editable_get_chars (GtkEditable *editable, gint start_pos, gint end_pos); static void editable_set_selection_bounds (GtkEditable *editable, gint start, gint end); static gboolean editable_get_selection_bounds (GtkEditable *editable, gint *start, gint *end); static void editable_real_set_position (GtkEditable *editable, gint position); static gint editable_get_position (GtkEditable *editable); G_DEFINE_TYPE_WITH_CODE (EelEditableLabel, eel_editable_label, GTK_TYPE_MISC, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, eel_editable_label_editable_init)); static void eel_editable_label_queue_resize (GtkWidget *label) { if (gtk_widget_get_realized (label)) { gtk_widget_queue_resize (label); } } static void add_move_binding (GtkBindingSet *binding_set, guint keyval, guint modmask, GtkMovementStep step, gint count) { g_assert ((modmask & GDK_SHIFT_MASK) == 0); gtk_binding_entry_add_signal (binding_set, keyval, modmask, "move_cursor", 3, G_TYPE_ENUM, step, G_TYPE_INT, count, G_TYPE_BOOLEAN, FALSE); /* Selection-extending version */ gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK, "move_cursor", 3, G_TYPE_ENUM, step, G_TYPE_INT, count, G_TYPE_BOOLEAN, TRUE); } static void eel_editable_label_class_init (EelEditableLabelClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); GtkBindingSet *binding_set; gobject_class->set_property = eel_editable_label_set_property; gobject_class->get_property = eel_editable_label_get_property; gobject_class->finalize = eel_editable_label_finalize; widget_class->get_preferred_width = eel_editable_label_get_preferred_width; widget_class->get_preferred_height = eel_editable_label_get_preferred_height; widget_class->size_allocate = eel_editable_label_size_allocate; widget_class->state_changed = eel_editable_label_state_changed; widget_class->style_updated = eel_editable_label_style_updated; widget_class->direction_changed = eel_editable_label_direction_changed; widget_class->draw = eel_editable_label_draw; widget_class->realize = eel_editable_label_realize; widget_class->unrealize = eel_editable_label_unrealize; widget_class->map = eel_editable_label_map; widget_class->unmap = eel_editable_label_unmap; widget_class->button_press_event = eel_editable_label_button_press; widget_class->button_release_event = eel_editable_label_button_release; widget_class->motion_notify_event = eel_editable_label_motion; widget_class->focus = eel_editable_label_focus; widget_class->key_press_event = eel_editable_label_key_press; widget_class->key_release_event = eel_editable_label_key_release; widget_class->focus_in_event = eel_editable_label_focus_in; widget_class->focus_out_event = eel_editable_label_focus_out; widget_class->get_accessible = eel_editable_label_get_accessible; class->move_cursor = eel_editable_label_move_cursor; class->delete_from_cursor = eel_editable_label_delete_from_cursor; class->copy_clipboard = eel_editable_label_copy_clipboard; class->cut_clipboard = eel_editable_label_cut_clipboard; class->paste_clipboard = eel_editable_label_paste_clipboard; class->toggle_overwrite = eel_editable_label_toggle_overwrite; signals[MOVE_CURSOR] = g_signal_new ("move_cursor", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, move_cursor), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT, G_TYPE_BOOLEAN); signals[COPY_CLIPBOARD] = g_signal_new ("copy_clipboard", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, copy_clipboard), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[POPULATE_POPUP] = g_signal_new ("populate_popup", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EelEditableLabelClass, populate_popup), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_MENU); signals[DELETE_FROM_CURSOR] = g_signal_new ("delete_from_cursor", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, delete_from_cursor), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, G_TYPE_INT); signals[CUT_CLIPBOARD] = g_signal_new ("cut_clipboard", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, cut_clipboard), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PASTE_CLIPBOARD] = g_signal_new ("paste_clipboard", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, paste_clipboard), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[TOGGLE_OVERWRITE] = g_signal_new ("toggle_overwrite", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelEditableLabelClass, toggle_overwrite), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_object_class_install_property (gobject_class, PROP_TEXT, g_param_spec_string ("text", _("Text"), _("The text of the label."), NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_JUSTIFY, g_param_spec_enum ("justify", _("Justification"), _("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that."), GTK_TYPE_JUSTIFICATION, GTK_JUSTIFY_LEFT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_WRAP, g_param_spec_boolean ("wrap", _("Line wrap"), _("If set, wrap lines if the text becomes too wide."), FALSE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CURSOR_POSITION, g_param_spec_int ("cursor_position", _("Cursor Position"), _("The current position of the insertion cursor in chars."), 0, G_MAXINT, 0, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, g_param_spec_int ("selection_bound", _("Selection Bound"), _("The position of the opposite end of the selection from the cursor in chars."), 0, G_MAXINT, 0, G_PARAM_READABLE)); /* * Key bindings */ binding_set = gtk_binding_set_by_class (class); /* Moving the insertion point */ add_move_binding (binding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); add_move_binding (binding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); add_move_binding (binding_set, GDK_KEY_KP_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); add_move_binding (binding_set, GDK_KEY_KP_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); add_move_binding (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, GTK_MOVEMENT_LOGICAL_POSITIONS, 1); add_move_binding (binding_set, GDK_KEY_b, GDK_CONTROL_MASK, GTK_MOVEMENT_LOGICAL_POSITIONS, -1); add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); add_move_binding (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, GTK_MOVEMENT_PARAGRAPH_ENDS, -1); add_move_binding (binding_set, GDK_KEY_e, GDK_CONTROL_MASK, GTK_MOVEMENT_PARAGRAPH_ENDS, 1); add_move_binding (binding_set, GDK_KEY_f, GDK_MOD1_MASK, GTK_MOVEMENT_WORDS, 1); add_move_binding (binding_set, GDK_KEY_b, GDK_MOD1_MASK, GTK_MOVEMENT_WORDS, -1); add_move_binding (binding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); add_move_binding (binding_set, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); add_move_binding (binding_set, GDK_KEY_KP_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); add_move_binding (binding_set, GDK_KEY_KP_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); add_move_binding (binding_set, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1); add_move_binding (binding_set, GDK_KEY_KP_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1); add_move_binding (binding_set, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1); add_move_binding (binding_set, GDK_KEY_KP_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1); /* Select all */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "move_cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, -1, G_TYPE_BOOLEAN, FALSE); gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "move_cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, 1, G_TYPE_BOOLEAN, TRUE); /* Deleting text */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, -1); /* Make this do the same as Backspace, to help with mis-typing */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, -1); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, -1); /* Cut/copy/paste */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_x, GDK_CONTROL_MASK, "cut_clipboard", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK, "copy_clipboard", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_v, GDK_CONTROL_MASK, "paste_clipboard", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "cut_clipboard", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_CONTROL_MASK, "copy_clipboard", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_SHIFT_MASK, "paste_clipboard", 0); /* Overwrite */ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, 0, "toggle_overwrite", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0, "toggle_overwrite", 0); } static void eel_editable_label_editable_init (GtkEditableInterface *iface) { iface->do_insert_text = editable_insert_text_emit; iface->do_delete_text = editable_delete_text_emit; iface->insert_text = editable_insert_text; iface->delete_text = editable_delete_text; iface->get_chars = editable_get_chars; iface->set_selection_bounds = editable_set_selection_bounds; iface->get_selection_bounds = editable_get_selection_bounds; iface->set_position = editable_real_set_position; iface->get_position = editable_get_position; } static void eel_editable_label_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (object); switch (prop_id) { case PROP_TEXT: eel_editable_label_set_text (label, g_value_get_string (value)); break; case PROP_JUSTIFY: eel_editable_label_set_justify (label, g_value_get_enum (value)); break; case PROP_WRAP: eel_editable_label_set_line_wrap (label, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void eel_editable_label_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EelEditableLabel *label; gint offset; label = EEL_EDITABLE_LABEL (object); switch (prop_id) { case PROP_TEXT: g_value_set_string (value, label->text); break; case PROP_JUSTIFY: g_value_set_enum (value, label->jtype); break; case PROP_WRAP: g_value_set_boolean (value, label->wrap); break; case PROP_CURSOR_POSITION: offset = g_utf8_pointer_to_offset (label->text, label->text + label->selection_end); g_value_set_int (value, offset); break; case PROP_SELECTION_BOUND: offset = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); g_value_set_int (value, offset); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void eel_editable_label_init (EelEditableLabel *label) { label->jtype = GTK_JUSTIFY_LEFT; label->wrap = FALSE; label->wrap_mode = PANGO_WRAP_WORD; label->layout = NULL; label->text_size = 1; label->text = g_malloc (label->text_size); label->text[0] = '\0'; label->n_bytes = 0; gtk_widget_set_can_focus (GTK_WIDGET (label), TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label)), GTK_STYLE_CLASS_ENTRY); /* This object is completely private. No external entity can gain a reference * to it; so we create it here and destroy it in finalize(). */ label->im_context = gtk_im_multicontext_new (); g_signal_connect (G_OBJECT (label->im_context), "commit", G_CALLBACK (eel_editable_label_commit_cb), label); g_signal_connect (G_OBJECT (label->im_context), "preedit_changed", G_CALLBACK (eel_editable_label_preedit_changed_cb), label); g_signal_connect (G_OBJECT (label->im_context), "retrieve_surrounding", G_CALLBACK (eel_editable_label_retrieve_surrounding_cb), label); g_signal_connect (G_OBJECT (label->im_context), "delete_surrounding", G_CALLBACK (eel_editable_label_delete_surrounding_cb), label); } /** * eel_editable_label_new: * @str: The text of the label * * Creates a new label with the given text inside it. You can * pass %NULL to get an empty label widget. * * Return value: the new #EelEditableLabel **/ GtkWidget* eel_editable_label_new (const gchar *str) { EelEditableLabel *label; label = g_object_new (EEL_TYPE_EDITABLE_LABEL, NULL); if (str && *str) eel_editable_label_set_text (label, str); return GTK_WIDGET (label); } /** * eel_editable_label_set_text: * @label: a #EelEditableLabel * @str: The text you want to set. * * Sets the text within the #EelEditableLabel widget. It overwrites any text that * was there before. * * This will also clear any previously set mnemonic accelerators. **/ void eel_editable_label_set_text (EelEditableLabel *label, const gchar *str) { GtkEditable *editable; int tmp_pos; g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); g_return_if_fail (str != NULL); if (strcmp (label->text, str) == 0) return; editable = GTK_EDITABLE (label); gtk_editable_delete_text (editable, 0, -1); tmp_pos = 0; gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos); } /** * eel_editable_label_get_text: * @label: a #EelEditableLabel * * Fetches the text from a label widget, as displayed on the * screen. This does not include any embedded underlines * indicating mnemonics or Pango markup. (See eel_editable_label_get_label()) * * Return value: the text in the label widget. This is the internal * string used by the label, and must not be modified. **/ const gchar * eel_editable_label_get_text (EelEditableLabel *label) { g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), NULL); return label->text; } /** * eel_editable_label_set_justify: * @label: a #EelEditableLabel * @jtype: a #GtkJustification * * Sets the alignment of the lines in the text of the label relative to * each other. %GTK_JUSTIFY_LEFT is the default value when the * widget is first created with eel_editable_label_new(). If you instead want * to set the alignment of the label as a whole, use * gtk_misc_set_alignment() instead. eel_editable_label_set_justify() has no * effect on labels containing only a single line. **/ void eel_editable_label_set_justify (EelEditableLabel *label, GtkJustification jtype) { g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL); if ((GtkJustification) label->jtype != jtype) { label->jtype = jtype; /* No real need to be this drastic, but easier than duplicating the code */ eel_editable_label_recompute (label); g_object_notify (G_OBJECT (label), "justify"); eel_editable_label_queue_resize (GTK_WIDGET (label)); } } /** * eel_editable_label_get_justify: * @label: a #EelEditableLabel * * Returns the justification of the label. See eel_editable_label_set_justify (). * * Return value: #GtkJustification **/ GtkJustification eel_editable_label_get_justify (EelEditableLabel *label) { g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), 0); return label->jtype; } void eel_editable_label_set_draw_outline (EelEditableLabel *label, gboolean draw_outline) { draw_outline = draw_outline != FALSE; if (label->draw_outline != draw_outline) { label->draw_outline = draw_outline; gtk_widget_queue_draw (GTK_WIDGET (label)); } } /** * eel_editable_label_set_line_wrap: * @label: a #EelEditableLabel * @wrap: the setting * * Toggles line wrapping within the #EelEditableLabel widget. %TRUE makes it break * lines if text exceeds the widget's size. %FALSE lets the text get cut off * by the edge of the widget if it exceeds the widget size. **/ void eel_editable_label_set_line_wrap (EelEditableLabel *label, gboolean wrap) { g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); wrap = wrap != FALSE; if (label->wrap != wrap) { label->wrap = wrap; g_object_notify (G_OBJECT (label), "wrap"); eel_editable_label_queue_resize (GTK_WIDGET (label)); } } void eel_editable_label_set_line_wrap_mode (EelEditableLabel *label, PangoWrapMode mode) { g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); if (label->wrap_mode != mode) { label->wrap_mode = mode; eel_editable_label_queue_resize (GTK_WIDGET (label)); } } /** * eel_editable_label_get_line_wrap: * @label: a #EelEditableLabel * * Returns whether lines in the label are automatically wrapped. See eel_editable_label_set_line_wrap (). * * Return value: %TRUE if the lines of the label are automatically wrapped. */ gboolean eel_editable_label_get_line_wrap (EelEditableLabel *label) { g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE); return label->wrap; } PangoFontDescription * eel_editable_label_get_font_description (EelEditableLabel *label) { if (label->font_desc) return pango_font_description_copy (label->font_desc); return NULL; } void eel_editable_label_set_font_description (EelEditableLabel *label, const PangoFontDescription *desc) { if (label->font_desc) pango_font_description_free (label->font_desc); if (desc) label->font_desc = pango_font_description_copy (desc); else label->font_desc = NULL; eel_editable_label_clear_layout (label); } static void eel_editable_label_finalize (GObject *object) { EelEditableLabel *label; g_assert (EEL_IS_EDITABLE_LABEL (object)); label = EEL_EDITABLE_LABEL (object); if (label->font_desc) { pango_font_description_free (label->font_desc); label->font_desc = NULL; } g_object_unref (G_OBJECT (label->im_context)); label->im_context = NULL; g_free (label->text); label->text = NULL; if (label->layout) { g_object_unref (G_OBJECT (label->layout)); label->layout = NULL; } G_OBJECT_CLASS (eel_editable_label_parent_class)->finalize (object); } static void eel_editable_label_clear_layout (EelEditableLabel *label) { if (label->layout) { g_object_unref (G_OBJECT (label->layout)); label->layout = NULL; } } static void eel_editable_label_recompute (EelEditableLabel *label) { eel_editable_label_clear_layout (label); eel_editable_label_check_cursor_blink (label); } typedef struct _LabelWrapWidth LabelWrapWidth; struct _LabelWrapWidth { gint width; PangoFontDescription *font_desc; }; static void label_wrap_width_free (gpointer data) { LabelWrapWidth *wrap_width = data; pango_font_description_free (wrap_width->font_desc); g_free (wrap_width); } static gint get_label_wrap_width (EelEditableLabel *label) { PangoLayout *layout; GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET (label)); PangoFontDescription *desc; LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width"); if (!wrap_width) { wrap_width = g_new0 (LabelWrapWidth, 1); g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width", wrap_width, label_wrap_width_free); } gtk_style_context_get (style, gtk_widget_get_state_flags (GTK_WIDGET (label)), GTK_STYLE_PROPERTY_FONT, &desc, NULL); if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, desc)) goto out; if (wrap_width->font_desc) pango_font_description_free (wrap_width->font_desc); wrap_width->font_desc = pango_font_description_copy (desc); layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), "This long string gives a good enough length for any line to have."); pango_layout_get_size (layout, &wrap_width->width, NULL); g_object_unref (layout); out: pango_font_description_free (desc); return wrap_width->width; } static void eel_editable_label_ensure_layout (EelEditableLabel *label, gboolean include_preedit) { GtkWidget *widget; PangoRectangle logical_rect; /* Normalize for comparisons */ include_preedit = include_preedit != 0; if (label->preedit_length > 0 && include_preedit != label->layout_includes_preedit) eel_editable_label_clear_layout (label); widget = GTK_WIDGET (label); if (label->layout == NULL) { gchar *preedit_string = NULL; gint preedit_length = 0; PangoAttrList *preedit_attrs = NULL; PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */ PangoAttrList *tmp_attrs = pango_attr_list_new (); if (include_preedit) { gtk_im_context_get_preedit_string (label->im_context, &preedit_string, &preedit_attrs, NULL); preedit_length = label->preedit_length; } if (preedit_length) { GString *tmp_string = g_string_new (NULL); g_string_prepend_len (tmp_string, label->text, label->n_bytes); g_string_insert (tmp_string, label->selection_anchor, preedit_string); label->layout = gtk_widget_create_pango_layout (widget, tmp_string->str); pango_attr_list_splice (tmp_attrs, preedit_attrs, label->selection_anchor, preedit_length); g_string_free (tmp_string, TRUE); } else { label->layout = gtk_widget_create_pango_layout (widget, label->text); } label->layout_includes_preedit = include_preedit; if (label->font_desc != NULL) pango_layout_set_font_description (label->layout, label->font_desc); #ifdef HAVE_PANGO_144 pango_attr_list_insert (tmp_attrs, pango_attr_insert_hyphens_new (FALSE)); #endif pango_layout_set_attributes (label->layout, tmp_attrs); if (preedit_string) g_free (preedit_string); if (preedit_attrs) pango_attr_list_unref (preedit_attrs); pango_attr_list_unref (tmp_attrs); switch (label->jtype) { case GTK_JUSTIFY_LEFT: align = PANGO_ALIGN_LEFT; break; case GTK_JUSTIFY_RIGHT: align = PANGO_ALIGN_RIGHT; break; case GTK_JUSTIFY_CENTER: align = PANGO_ALIGN_CENTER; break; case GTK_JUSTIFY_FILL: /* FIXME: This just doesn't work to do this */ align = PANGO_ALIGN_LEFT; pango_layout_set_justify (label->layout, TRUE); break; default: g_assert_not_reached (); } pango_layout_set_alignment (label->layout, align); if (label->wrap) { gint longest_paragraph; gint width, height; gint set_width; gtk_widget_get_size_request (widget, &set_width, NULL); if (set_width > 0) pango_layout_set_width (label->layout, set_width * PANGO_SCALE); else { gint wrap_width; pango_layout_set_width (label->layout, -1); pango_layout_get_extents (label->layout, NULL, &logical_rect); width = logical_rect.width; /* Try to guess a reasonable maximum width */ longest_paragraph = width; wrap_width = get_label_wrap_width (label); width = MIN (width, wrap_width); width = MIN (width, PANGO_SCALE * (gdk_screen_width () + 1) / 2); pango_layout_set_width (label->layout, width); pango_layout_get_extents (label->layout, NULL, &logical_rect); width = logical_rect.width; height = logical_rect.height; /* Unfortunately, the above may leave us with a very unbalanced looking paragraph, * so we try short search for a narrower width that leaves us with the same height */ if (longest_paragraph > 0) { gint nlines, perfect_width; nlines = pango_layout_get_line_count (label->layout); perfect_width = (longest_paragraph + nlines - 1) / nlines; if (perfect_width < width) { pango_layout_set_width (label->layout, perfect_width); pango_layout_get_extents (label->layout, NULL, &logical_rect); if (logical_rect.height <= height) width = logical_rect.width; else { gint mid_width = (perfect_width + width) / 2; if (mid_width > perfect_width) { pango_layout_set_width (label->layout, mid_width); pango_layout_get_extents (label->layout, NULL, &logical_rect); if (logical_rect.height <= height) width = logical_rect.width; } } } } pango_layout_set_width (label->layout, width); } pango_layout_set_wrap (label->layout, label->wrap_mode); } else /* !label->wrap */ pango_layout_set_width (label->layout, -1); } } static void eel_editable_label_size_request (GtkWidget *widget, GtkRequisition *requisition) { EelEditableLabel *label; gint width, height; PangoRectangle logical_rect; gint set_width; gint xpad, ypad; g_assert (EEL_IS_EDITABLE_LABEL (widget)); g_assert (requisition != NULL); label = EEL_EDITABLE_LABEL (widget); /* * If word wrapping is on, then the height requisition can depend * on: * * - Any width set on the widget via gtk_widget_set_size_request(). * - The padding of the widget (xpad, set by gtk_misc_set_padding) * * Instead of trying to detect changes to these quantities, if we * are wrapping, we just rewrap for each size request. Since * size requisitions are cached by the GTK+ core, this is not * expensive. */ if (label->wrap) eel_editable_label_recompute (label); eel_editable_label_ensure_layout (label, TRUE); gtk_misc_get_padding (&label->misc, &xpad, &ypad); width = xpad * 2; height = ypad * 2; pango_layout_get_extents (label->layout, NULL, &logical_rect); gtk_widget_get_size_request (widget, &set_width, NULL); if (label->wrap && set_width > 0) width += set_width; else width += PANGO_PIXELS (logical_rect.width); height += PANGO_PIXELS (logical_rect.height); requisition->width = width; requisition->height = height; } static void eel_editable_label_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { GtkRequisition requisition; eel_editable_label_size_request (widget, &requisition); *minimum = *natural = requisition.width; } static void eel_editable_label_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { GtkRequisition requisition; eel_editable_label_size_request (widget, &requisition); *minimum = *natural = requisition.height; } static void eel_editable_label_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->size_allocate) (widget, allocation); gdk_window_move_resize (label->text_area, allocation->x, allocation->y, allocation->width, allocation->height); } static void eel_editable_label_state_changed (GtkWidget *widget, GtkStateType prev_state) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (widget); /* clear any selection if we're insensitive */ if (!gtk_widget_is_sensitive (widget)) eel_editable_label_select_region (label, 0, 0); if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed) GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed (widget, prev_state); } static void eel_editable_label_style_updated (GtkWidget *widget) { EelEditableLabel *label; g_assert (EEL_IS_EDITABLE_LABEL (widget)); label = EEL_EDITABLE_LABEL (widget); GTK_WIDGET_CLASS (eel_editable_label_parent_class)->style_updated (widget); /* We have to clear the layout, fonts etc. may have changed */ eel_editable_label_recompute (label); } static void eel_editable_label_direction_changed (GtkWidget *widget, GtkTextDirection previous_dir) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); if (label->layout) pango_layout_context_changed (label->layout); GTK_WIDGET_CLASS (eel_editable_label_parent_class)->direction_changed (widget, previous_dir); } static void get_layout_location (EelEditableLabel *label, gint *xp, gint *yp) { GtkMisc *misc; GtkWidget *widget; gfloat xalign, yalign; GtkRequisition req; gint x, y, xpad, ypad; GtkAllocation allocation; misc = GTK_MISC (label); widget = GTK_WIDGET (label); gtk_misc_get_alignment (misc, &xalign, &yalign); if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) xalign = 1.0 - xalign; gtk_widget_get_preferred_size (widget, &req, NULL); gtk_misc_get_padding (misc, &xpad, &ypad); gtk_widget_get_allocation (widget, &allocation); x = floor (xpad + ((allocation.width - req.width) * xalign) + 0.5); y = floor (ypad + ((allocation.height - req.height) * yalign) + 0.5); if (xp) *xp = x; if (yp) *yp = y; } static gint eel_editable_label_get_cursor_pos (EelEditableLabel *label, PangoRectangle *strong_pos, PangoRectangle *weak_pos) { const gchar *text; const gchar *preedit_text; gint index; eel_editable_label_ensure_layout (label, TRUE); text = pango_layout_get_text (label->layout); preedit_text = text + label->selection_anchor; index = label->selection_anchor + g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor) - preedit_text; pango_layout_get_cursor_pos (label->layout, index, strong_pos, weak_pos); return index; } /* Copied from gtkutil private function */ static gboolean eel_editable_label_get_block_cursor_location (EelEditableLabel *label, gint *index, PangoRectangle *pos, gboolean *at_line_end) { const gchar *text; const gchar *preedit_text; PangoLayoutLine *layout_line; PangoRectangle strong_pos, weak_pos; gint line_no; gboolean rtl; PangoContext *context; PangoFontMetrics *metrics; const PangoFontDescription *font_desc; eel_editable_label_ensure_layout (label, TRUE); text = pango_layout_get_text (label->layout); preedit_text = text + label->selection_anchor; text = g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor); index[0] = label->selection_anchor + text - preedit_text; pango_layout_index_to_pos (label->layout, index[0], pos); index[1] = label->selection_anchor + g_utf8_next_char (text) - preedit_text; if (pos->width != 0) { if (at_line_end) *at_line_end = FALSE; if (pos->width < 0) /* RTL char, shift x value back to top left of rect */ { pos->x += pos->width; pos->width = -pos->width; } return TRUE; } pango_layout_index_to_line_x (label->layout, index[0], FALSE, &line_no, NULL); layout_line = pango_layout_get_line_readonly (label->layout, line_no); if (layout_line == NULL) return FALSE; text = pango_layout_get_text (label->layout); if (index[0] < layout_line->start_index + layout_line->length) { /* this may be a zero-width character in the middle of the line, * or it could be a character where line is wrapped, we do want * block cursor in latter case */ if (g_utf8_next_char (text + index[0]) - text != layout_line->start_index + layout_line->length) { /* zero-width character in the middle of the line, do not * bother with block cursor */ return FALSE; } } /* Cursor is at the line end. It may be an empty line, or it could * be on the left or on the right depending on text direction, or it * even could be in the middle of visual layout in bidi text. */ pango_layout_get_cursor_pos (label->layout, index[0], &strong_pos, &weak_pos); if (strong_pos.x != weak_pos.x) { /* do not show block cursor in this case, since the character typed * in may or may not appear at the cursor position */ return FALSE; } context = pango_layout_get_context (label->layout); /* In case when index points to the end of line, pos->x is always most right * pixel of the layout line, so we need to correct it for RTL text. */ if (layout_line->length) { if (layout_line->resolved_dir == PANGO_DIRECTION_RTL) { PangoLayoutIter *iter; PangoRectangle line_rect; gint i; gint left, right; const gchar *p; p = g_utf8_prev_char (text + index[0]); pango_layout_line_index_to_x (layout_line, p - text, FALSE, &left); pango_layout_line_index_to_x (layout_line, p - text, TRUE, &right); pos->x = MIN (left, right); iter = pango_layout_get_iter (label->layout); for (i = 0; i < line_no; i++) pango_layout_iter_next_line (iter); pango_layout_iter_get_line_extents (iter, NULL, &line_rect); pango_layout_iter_free (iter); rtl = TRUE; pos->x += line_rect.x; } else rtl = FALSE; } else { rtl = pango_context_get_base_dir (context) == PANGO_DIRECTION_RTL; } font_desc = pango_layout_get_font_description (label->layout); if (!font_desc) font_desc = pango_context_get_font_description (context); metrics = pango_context_get_metrics (context, font_desc, NULL); pos->width = pango_font_metrics_get_approximate_char_width (metrics); pango_font_metrics_unref (metrics); if (rtl) pos->x -= pos->width - 1; if (at_line_end) *at_line_end = TRUE; return pos->width != 0; } /* These functions are copies from gtk+, as they are not exported from gtk+ */ static void eel_editable_label_draw_cursor (EelEditableLabel *label, cairo_t *cr, gint xoffset, gint yoffset) { if (gtk_widget_is_drawable (GTK_WIDGET (label))) { GtkWidget *widget = GTK_WIDGET (label); gboolean block; gboolean block_at_line_end; gint range[2]; gint index; GtkStyleContext *context; PangoRectangle strong_pos; context = gtk_widget_get_style_context (widget); index = eel_editable_label_get_cursor_pos (label, NULL, NULL); if (label->overwrite_mode && eel_editable_label_get_block_cursor_location (label, range, &strong_pos, &block_at_line_end)) block = TRUE; else block = FALSE; if (!block) { gtk_render_insertion_cursor (context, cr, xoffset, yoffset, label->layout, index, gdk_keymap_get_direction (gdk_keymap_get_default ())); } else /* Block cursor */ { GdkRGBA fg_color; cairo_region_t *clip; gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg_color); cairo_save (cr); gdk_cairo_set_source_rgba (cr, &fg_color); cairo_rectangle (cr, xoffset + PANGO_PIXELS (strong_pos.x), yoffset + PANGO_PIXELS (strong_pos.y), PANGO_PIXELS (strong_pos.width), PANGO_PIXELS (strong_pos.height)); cairo_fill (cr); if (!block_at_line_end) { GdkRGBA color; clip = gdk_pango_layout_get_clip_region (label->layout, xoffset, yoffset, range, 1); gdk_cairo_region (cr, clip); cairo_clip (cr); gtk_style_context_get_background_color (context, GTK_STATE_FLAG_FOCUSED, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_move_to (cr, xoffset, yoffset); pango_cairo_show_layout (cr, label->layout); cairo_region_destroy (clip); } cairo_restore (cr); } } } static gint eel_editable_label_draw (GtkWidget *widget, cairo_t *cr) { EelEditableLabel *label; GtkStyleContext *style; gint x, y; g_assert (EEL_IS_EDITABLE_LABEL (widget)); label = EEL_EDITABLE_LABEL (widget); style = gtk_widget_get_style_context (widget); gtk_render_background (style, cr, 0, 0, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); eel_editable_label_ensure_layout (label, TRUE); if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) && label->text) { get_layout_location (label, &x, &y); gtk_render_layout (style, cr, x, y, label->layout); if (label->selection_anchor != label->selection_end) { gint range[2]; const char *text; cairo_region_t *clip; GtkStateType state; GdkRGBA background_color; range[0] = label->selection_anchor; range[1] = label->selection_end; /* Handle possible preedit string */ if (label->preedit_length > 0 && range[1] > label->selection_anchor) { text = pango_layout_get_text (label->layout) + label->selection_anchor; range[1] += g_utf8_offset_to_pointer (text, label->preedit_length) - text; } if (range[0] > range[1]) { gint tmp = range[0]; range[0] = range[1]; range[1] = tmp; } clip = gdk_pango_layout_get_clip_region (label->layout, x, y, range, 1); cairo_save (cr); gdk_cairo_region (cr, clip); cairo_clip (cr); state = gtk_widget_get_state_flags (widget); state |= GTK_STATE_FLAG_SELECTED; gtk_style_context_get_background_color (style, state, &background_color); gdk_cairo_set_source_rgba (cr, &background_color); cairo_paint (cr); gtk_style_context_save (style); gtk_style_context_set_state (style, state); gtk_render_layout (style, cr, x, y, label->layout); gtk_style_context_restore (style); cairo_restore (cr); cairo_region_destroy (clip); } else if (gtk_widget_has_focus (widget)) eel_editable_label_draw_cursor (label, cr, x, y); if (label->draw_outline) { gtk_style_context_save (style); gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget)); gtk_render_frame (style, cr, 0, 0, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); gtk_style_context_restore (style); } } return FALSE; } static void eel_editable_label_realize (GtkWidget *widget) { EelEditableLabel *label; GdkWindowAttr attributes; gint attributes_mask; GtkAllocation allocation; GdkWindow *window; GtkStyleContext *style; gtk_widget_set_realized (widget, TRUE); label = EEL_EDITABLE_LABEL (widget); gtk_widget_get_allocation (widget, &allocation); attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.visual = gtk_widget_get_visual (widget); attributes.event_mask = gtk_widget_get_events (widget) | (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gtk_widget_set_window (widget, window); gdk_window_set_user_data (window, widget); attributes.cursor = gdk_cursor_new (GDK_XTERM); attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR; label->text_area = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (label->text_area, widget); gtk_im_context_set_client_window (label->im_context, label->text_area); g_object_unref (attributes.cursor); style = gtk_widget_get_style_context (widget); gtk_style_context_set_background (style, gtk_widget_get_window (widget)); } static void eel_editable_label_unrealize (GtkWidget *widget) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (widget); gtk_im_context_set_client_window (label->im_context, NULL); if (label->text_area) { gdk_window_set_user_data (label->text_area, NULL); gdk_window_destroy (label->text_area); label->text_area = NULL; } (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unrealize) (widget); } static void eel_editable_label_map (GtkWidget *widget) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->map) (widget); gdk_window_show (label->text_area); } static void eel_editable_label_unmap (GtkWidget *widget) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); gdk_window_hide (label->text_area); (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unmap) (widget); } static void window_to_layout_coords (EelEditableLabel *label, gint *x, gint *y) { gint lx, ly; /* get layout location in gtk_widget_get_window (widget) coords */ get_layout_location (label, &lx, &ly); if (x) *x -= lx; /* go to layout */ if (y) *y -= ly; /* go to layout */ } static void get_layout_index (EelEditableLabel *label, gint x, gint y, gint *index) { gint trailing = 0; const gchar *cluster; const gchar *cluster_end; *index = 0; eel_editable_label_ensure_layout (label, TRUE); window_to_layout_coords (label, &x, &y); x *= PANGO_SCALE; y *= PANGO_SCALE; pango_layout_xy_to_index (label->layout, x, y, index, &trailing); if (*index >= label->selection_anchor && label->preedit_length) { if (*index >= label->selection_anchor + label->preedit_length) *index -= label->preedit_length; else { *index = label->selection_anchor; trailing = 0; } } cluster = label->text + *index; cluster_end = cluster; while (trailing) { cluster_end = g_utf8_next_char (cluster_end); --trailing; } *index += (cluster_end - cluster); } static void eel_editable_label_select_word (EelEditableLabel *label) { gint min, max; gint start_index = eel_editable_label_move_backward_word (label, label->selection_end); gint end_index = eel_editable_label_move_forward_word (label, label->selection_end); min = MIN (label->selection_anchor, label->selection_end); max = MAX (label->selection_anchor, label->selection_end); min = MIN (min, start_index); max = MAX (max, end_index); eel_editable_label_select_region_index (label, min, max); } static gint eel_editable_label_button_press (GtkWidget *widget, GdkEventButton *event) { EelEditableLabel *label; gint index = 0; label = EEL_EDITABLE_LABEL (widget); if (event->button == 1) { if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); if (event->type == GDK_3BUTTON_PRESS) { eel_editable_label_select_region_index (label, 0, strlen (label->text)); return TRUE; } if (event->type == GDK_2BUTTON_PRESS) { eel_editable_label_select_word (label); return TRUE; } get_layout_index (label, event->x, event->y, &index); if ((label->selection_anchor != label->selection_end) && (event->state & GDK_SHIFT_MASK)) { gint min, max; /* extend (same as motion) */ min = MIN (label->selection_anchor, label->selection_end); max = MAX (label->selection_anchor, label->selection_end); min = MIN (min, index); max = MAX (max, index); /* ensure the anchor is opposite index */ if (index == min) { gint tmp = min; min = max; max = tmp; } eel_editable_label_select_region_index (label, min, max); } else { if (event->type == GDK_3BUTTON_PRESS) eel_editable_label_select_region_index (label, 0, strlen (label->text)); else if (event->type == GDK_2BUTTON_PRESS) eel_editable_label_select_word (label); else /* start a replacement */ eel_editable_label_select_region_index (label, index, index); } return TRUE; } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { get_layout_index (label, event->x, event->y, &index); eel_editable_label_select_region_index (label, index, index); eel_editable_label_paste (label, GDK_SELECTION_PRIMARY); return TRUE; } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { eel_editable_label_do_popup (label, event); return TRUE; } return FALSE; } static gint eel_editable_label_button_release (GtkWidget *widget, GdkEventButton *event) { if (event->button != 1) return FALSE; /* The goal here is to return TRUE iff we ate the * button press to start selecting. */ return TRUE; } static gint eel_editable_label_motion (GtkWidget *widget, GdkEventMotion *event) { EelEditableLabel *label; gint index; gint x, y; if ((event->state & GDK_BUTTON1_MASK) == 0) return FALSE; label = EEL_EDITABLE_LABEL (widget); gdk_window_get_device_position (label->text_area, event->device, &x, &y, NULL); get_layout_index (label, x, y, &index); eel_editable_label_select_region_index (label, label->selection_anchor, index); return TRUE; } static void get_text_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data_or_owner) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (user_data_or_owner); if ((label->selection_anchor != label->selection_end) && label->text) { gint start, end; gint len; start = MIN (label->selection_anchor, label->selection_end); end = MAX (label->selection_anchor, label->selection_end); len = strlen (label->text); if (end > len) end = len; if (start > len) start = len; gtk_selection_data_set_text (selection_data, label->text + start, end - start); } } static void clear_text_callback (GtkClipboard *clipboard, gpointer user_data_or_owner) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (user_data_or_owner); label->selection_anchor = label->selection_end; gtk_widget_queue_draw (GTK_WIDGET (label)); } static void eel_editable_label_select_region_index (EelEditableLabel *label, gint anchor_index, gint end_index) { GtkClipboard *clipboard; g_assert (EEL_IS_EDITABLE_LABEL (label)); if (label->selection_anchor == anchor_index && label->selection_end == end_index) return; eel_editable_label_reset_im_context (label); label->selection_anchor = anchor_index; label->selection_end = end_index; clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); if (anchor_index != end_index) { GtkTargetList *list; GtkTargetEntry *targets; gint n_targets; list = gtk_target_list_new (NULL, 0); gtk_target_list_add_text_targets (list, 0); targets = gtk_target_table_new_from_list (list, &n_targets); gtk_clipboard_set_with_owner (clipboard, targets, n_targets, get_text_callback, clear_text_callback, G_OBJECT (label)); gtk_clipboard_set_can_store (clipboard, NULL, 0); gtk_target_table_free (targets, n_targets); gtk_target_list_unref (list); } else { if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label)) gtk_clipboard_clear (clipboard); } gtk_widget_queue_draw (GTK_WIDGET (label)); g_object_freeze_notify (G_OBJECT (label)); g_object_notify (G_OBJECT (label), "cursor_position"); g_object_notify (G_OBJECT (label), "selection_bound"); g_object_thaw_notify (G_OBJECT (label)); } /** * eel_editable_label_select_region: * @label: a #EelEditableLabel * @start_offset: start offset (in characters not bytes) * @end_offset: end offset (in characters not bytes) * * Selects a range of characters in the label, if the label is selectable. * See eel_editable_label_set_selectable(). If the label is not selectable, * this function has no effect. If @start_offset or * @end_offset are -1, then the end of the label will be substituted. * **/ void eel_editable_label_select_region (EelEditableLabel *label, gint start_offset, gint end_offset) { g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); if (label->text) { if (start_offset < 0) start_offset = g_utf8_strlen (label->text, -1); if (end_offset < 0) end_offset = g_utf8_strlen (label->text, -1); eel_editable_label_select_region_index (label, g_utf8_offset_to_pointer (label->text, start_offset) - label->text, g_utf8_offset_to_pointer (label->text, end_offset) - label->text); } } /** * eel_editable_label_get_selection_bounds: * @label: a #EelEditableLabel * @start: return location for start of selection, as a character offset * @end: return location for end of selection, as a character offset * * Gets the selected range of characters in the label, returning %TRUE * if there's a selection. * * Return value: %TRUE if selection is non-empty **/ gboolean eel_editable_label_get_selection_bounds (EelEditableLabel *label, gint *start, gint *end) { gint start_index, end_index; gint start_offset, end_offset; gint len; g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE); start_index = MIN (label->selection_anchor, label->selection_end); end_index = MAX (label->selection_anchor, label->selection_end); len = strlen (label->text); if (end_index > len) end_index = len; if (start_index > len) start_index = len; start_offset = g_utf8_strlen (label->text, start_index); end_offset = g_utf8_strlen (label->text, end_index); if (start_offset > end_offset) { gint tmp = start_offset; start_offset = end_offset; end_offset = tmp; } if (start) *start = start_offset; if (end) *end = end_offset; return start_offset != end_offset; } /** * eel_editable_label_get_layout: * @label: a #EelEditableLabel * * Gets the #PangoLayout used to display the label. * The layout is useful to e.g. convert text positions to * pixel positions, in combination with eel_editable_label_get_layout_offsets(). * The returned layout is owned by the label so need not be * freed by the caller. * * Return value: the #PangoLayout for this label **/ PangoLayout* eel_editable_label_get_layout (EelEditableLabel *label) { g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), NULL); eel_editable_label_ensure_layout (label, TRUE); return label->layout; } /** * eel_editable_label_get_layout_offsets: * @label: a #EelEditableLabel * @x: location to store X offset of layout, or %NULL * @y: location to store Y offset of layout, or %NULL * * Obtains the coordinates where the label will draw the #PangoLayout * representing the text in the label; useful to convert mouse events * into coordinates inside the #PangoLayout, e.g. to take some action * if some part of the label is clicked. Of course you will need to * create a #GtkEventBox to receive the events, and pack the label * inside it, since labels are a #GTK_NO_WINDOW widget. Remember * when using the #PangoLayout functions you need to convert to * and from pixels using PANGO_PIXELS() or #PANGO_SCALE. * **/ void eel_editable_label_get_layout_offsets (EelEditableLabel *label, gint *x, gint *y) { g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); get_layout_location (label, x, y); } static void eel_editable_label_pend_cursor_blink (EelEditableLabel *label) { /* TODO */ } static void eel_editable_label_check_cursor_blink (EelEditableLabel *label) { /* TODO */ } static gint eel_editable_label_key_press (GtkWidget *widget, GdkEventKey *event) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); eel_editable_label_pend_cursor_blink (label); if (gtk_im_context_filter_keypress (label->im_context, event)) { /*TODO eel_editable_label_obscure_mouse_cursor (label);*/ label->need_im_reset = TRUE; return TRUE; } if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_press_event (widget, event)) /* Activate key bindings */ return TRUE; return FALSE; } static gint eel_editable_label_key_release (GtkWidget *widget, GdkEventKey *event) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); if (gtk_im_context_filter_keypress (label->im_context, event)) { label->need_im_reset = TRUE; return TRUE; } return GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_release_event (widget, event); } static void eel_editable_label_keymap_direction_changed (GdkKeymap *keymap, EelEditableLabel *label) { gtk_widget_queue_draw (GTK_WIDGET (label)); } static gint eel_editable_label_focus_in (GtkWidget *widget, GdkEventFocus *event) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); gtk_widget_queue_draw (widget); label->need_im_reset = TRUE; gtk_im_context_focus_in (label->im_context); g_signal_connect (gdk_keymap_get_default (), "direction_changed", G_CALLBACK (eel_editable_label_keymap_direction_changed), label); eel_editable_label_check_cursor_blink (label); return FALSE; } static gint eel_editable_label_focus_out (GtkWidget *widget, GdkEventFocus *event) { EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); gtk_widget_queue_draw (widget); label->need_im_reset = TRUE; gtk_im_context_focus_out (label->im_context); eel_editable_label_check_cursor_blink (label); g_signal_handlers_disconnect_by_func (gdk_keymap_get_default (), (gpointer) eel_editable_label_keymap_direction_changed, label); return FALSE; } static void eel_editable_label_delete_text (EelEditableLabel *label, int start_pos, int end_pos) { int anchor, end; if (start_pos < 0) start_pos = 0; if (end_pos < 0 || end_pos > label->n_bytes) end_pos = label->n_bytes; if (start_pos < end_pos) { g_memmove (label->text + start_pos, label->text + end_pos, label->n_bytes + 1 - end_pos); label->n_bytes -= (end_pos - start_pos); anchor = label->selection_anchor; if (anchor > start_pos) anchor -= MIN (anchor, end_pos) - start_pos; end = label->selection_end; if (end > start_pos) end -= MIN (end, end_pos) - start_pos; /* We might have changed the selection */ eel_editable_label_select_region_index (label, anchor, end); eel_editable_label_recompute (label); eel_editable_label_queue_resize (GTK_WIDGET (label)); g_object_notify (G_OBJECT (label), "text"); g_signal_emit_by_name (GTK_EDITABLE (label), "changed"); } } static void eel_editable_label_insert_text (EelEditableLabel *label, const gchar *new_text, gint new_text_length, gint *index) { if (new_text_length + label->n_bytes + 1 > label->text_size) { while (new_text_length + label->n_bytes + 1 > label->text_size) { if (label->text_size == 0) label->text_size = 16; else label->text_size *= 2; } label->text = g_realloc (label->text, label->text_size); } g_object_freeze_notify (G_OBJECT (label)); g_memmove (label->text + *index + new_text_length, label->text + *index, label->n_bytes - *index); memcpy (label->text + *index, new_text, new_text_length); label->n_bytes += new_text_length; /* NUL terminate for safety and convenience */ label->text[label->n_bytes] = '\0'; g_object_notify (G_OBJECT (label), "text"); if (label->selection_anchor > *index) { g_object_notify (G_OBJECT (label), "cursor_position"); g_object_notify (G_OBJECT (label), "selection_bound"); label->selection_anchor += new_text_length; } if (label->selection_end > *index) { label->selection_end += new_text_length; g_object_notify (G_OBJECT (label), "selection_bound"); } *index += new_text_length; eel_editable_label_recompute (label); eel_editable_label_queue_resize (GTK_WIDGET (label)); g_object_thaw_notify (G_OBJECT (label)); g_signal_emit_by_name (GTK_EDITABLE (label), "changed"); } /* Used for im_commit_cb and inserting Unicode chars */ static void eel_editable_label_enter_text (EelEditableLabel *label, const gchar *str) { GtkEditable *editable = GTK_EDITABLE (label); gint tmp_pos; gboolean old_need_im_reset; /* Never reset the im while commiting, as that resets possible im state */ old_need_im_reset = label->need_im_reset; label->need_im_reset = FALSE; if (label->selection_end != label->selection_anchor) gtk_editable_delete_selection (editable); else { if (label->overwrite_mode) eel_editable_label_delete_from_cursor (label, GTK_DELETE_CHARS, 1); } tmp_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); gtk_editable_insert_text (GTK_EDITABLE (label), str, strlen (str), &tmp_pos); tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text; eel_editable_label_select_region_index (label, tmp_pos, tmp_pos); label->need_im_reset = old_need_im_reset; } /* IM Context Callbacks */ static void eel_editable_label_commit_cb (GtkIMContext *context, const gchar *str, EelEditableLabel *label) { eel_editable_label_enter_text (label, str); } static void eel_editable_label_preedit_changed_cb (GtkIMContext *context, EelEditableLabel *label) { gchar *preedit_string; gint cursor_pos; gtk_im_context_get_preedit_string (label->im_context, &preedit_string, NULL, &cursor_pos); label->preedit_length = strlen (preedit_string); cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); label->preedit_cursor = cursor_pos; g_free (preedit_string); eel_editable_label_recompute (label); eel_editable_label_queue_resize (GTK_WIDGET (label)); } static gboolean eel_editable_label_retrieve_surrounding_cb (GtkIMContext *context, EelEditableLabel *label) { gtk_im_context_set_surrounding (context, label->text, strlen (label->text) + 1, label->selection_end); return TRUE; } static gboolean eel_editable_label_delete_surrounding_cb (GtkIMContext *slave, gint offset, gint n_chars, EelEditableLabel *label) { gint current_pos; current_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); gtk_editable_delete_text (GTK_EDITABLE (label), current_pos + offset, current_pos + offset + n_chars); return TRUE; } static gboolean eel_editable_label_focus (GtkWidget *widget, GtkDirectionType direction) { /* We never want to be in the tab chain */ return FALSE; } /* Compute the X position for an offset that corresponds to the "more important * cursor position for that offset. We use this when trying to guess to which * end of the selection we should go to when the user hits the left or * right arrow key. */ static void get_better_cursor (EelEditableLabel *label, gint index, gint *x, gint *y) { GtkTextDirection keymap_direction = (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label)); gboolean split_cursor; PangoRectangle strong_pos, weak_pos; g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)), "gtk-split-cursor", &split_cursor, NULL); eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos); if (split_cursor) { *x = strong_pos.x / PANGO_SCALE; *y = strong_pos.y / PANGO_SCALE; } else { if (keymap_direction == widget_direction) { *x = strong_pos.x / PANGO_SCALE; *y = strong_pos.y / PANGO_SCALE; } else { *x = weak_pos.x / PANGO_SCALE; *y = weak_pos.y / PANGO_SCALE; } } } static gint eel_editable_label_move_logically (EelEditableLabel *label, gint start, gint count) { gint offset = g_utf8_pointer_to_offset (label->text, label->text + start); if (label->text) { PangoLogAttr *log_attrs; gint n_attrs; gint length; eel_editable_label_ensure_layout (label, FALSE); length = g_utf8_strlen (label->text, -1); pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); while (count > 0 && offset < length) { do offset++; while (offset < length && !log_attrs[offset].is_cursor_position); count--; } while (count < 0 && offset > 0) { do offset--; while (offset > 0 && !log_attrs[offset].is_cursor_position); count++; } g_free (log_attrs); } return g_utf8_offset_to_pointer (label->text, offset) - label->text; } static gint eel_editable_label_move_visually (EelEditableLabel *label, gint start, gint count) { gint index; index = start; while (count != 0) { int new_index, new_trailing; gboolean split_cursor; gboolean strong; eel_editable_label_ensure_layout (label, FALSE); g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)), "gtk-split-cursor", &split_cursor, NULL); if (split_cursor) strong = TRUE; else { GtkTextDirection keymap_direction = (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label)); } if (count > 0) { pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing); count--; } else { pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing); count++; } if (new_index < 0 || new_index == G_MAXINT) break; index = new_index; while (new_trailing--) index = g_utf8_next_char (label->text + new_index) - label->text; } return index; } static gint eel_editable_label_move_line (EelEditableLabel *label, gint start, gint count) { int n_lines, i; int x=0; PangoLayoutLine *line; int index; eel_editable_label_ensure_layout (label, FALSE); n_lines = pango_layout_get_line_count (label->layout); for (i = 0; i < n_lines; i++) { line = pango_layout_get_line (label->layout, i); if (start >= line->start_index && start <= line->start_index + line->length) { pango_layout_line_index_to_x (line, start, FALSE, &x); break; } } if (i == n_lines) i = n_lines - 1; i += count; i = CLAMP (i, 0, n_lines - 1); line = pango_layout_get_line (label->layout, i); if (pango_layout_line_x_to_index (line, x, &index, NULL)) return index; else { if (i == n_lines - 1) return line->start_index + line->length; else return line->start_index + line->length - 1; } } static gint eel_editable_label_move_forward_word (EelEditableLabel *label, gint start) { gint new_pos = g_utf8_pointer_to_offset (label->text, label->text + start); gint length; length = g_utf8_strlen (label->text, -1); if (new_pos < length) { PangoLogAttr *log_attrs; gint n_attrs; eel_editable_label_ensure_layout (label, FALSE); pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); /* Find the next word end, (remember, n_attrs is one more than the number of of chars) */ new_pos++; while (new_pos < (n_attrs - 1) && !log_attrs[new_pos].is_word_end) new_pos++; g_free (log_attrs); } return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; } static gint eel_editable_label_move_backward_word (EelEditableLabel *label, gint start) { gint new_pos = g_utf8_pointer_to_offset (label->text, label->text + start); if (new_pos > 0) { PangoLogAttr *log_attrs; gint n_attrs; eel_editable_label_ensure_layout (label, FALSE); pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); new_pos -= 1; /* Find the previous word beginning */ while (new_pos > 0 && !log_attrs[new_pos].is_word_start) new_pos--; g_free (log_attrs); } return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; } static void eel_editable_label_move_cursor (EelEditableLabel *label, GtkMovementStep step, gint count, gboolean extend_selection) { gint new_pos; new_pos = label->selection_end; if (label->selection_end != label->selection_anchor && !extend_selection) { /* If we have a current selection and aren't extending it, move to the * start/or end of the selection as appropriate */ switch (step) { case GTK_MOVEMENT_DISPLAY_LINES: case GTK_MOVEMENT_VISUAL_POSITIONS: { gint end_x, end_y; gint anchor_x, anchor_y; gboolean end_is_left; get_better_cursor (label, label->selection_end, &end_x, &end_y); get_better_cursor (label, label->selection_anchor, &anchor_x, &anchor_y); end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x); if (count < 0) new_pos = end_is_left ? label->selection_end : label->selection_anchor; else new_pos = !end_is_left ? label->selection_end : label->selection_anchor; break; } case GTK_MOVEMENT_LOGICAL_POSITIONS: case GTK_MOVEMENT_WORDS: if (count < 0) new_pos = MIN (label->selection_end, label->selection_anchor); else new_pos = MAX (label->selection_end, label->selection_anchor); break; case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: /* FIXME: Can do better here */ new_pos = count < 0 ? 0 : strlen (label->text); break; case GTK_MOVEMENT_PARAGRAPHS: case GTK_MOVEMENT_PAGES: case GTK_MOVEMENT_HORIZONTAL_PAGES: break; default: g_assert_not_reached (); break; } } else { switch (step) { case GTK_MOVEMENT_LOGICAL_POSITIONS: new_pos = eel_editable_label_move_logically (label, new_pos, count); break; case GTK_MOVEMENT_VISUAL_POSITIONS: new_pos = eel_editable_label_move_visually (label, new_pos, count); break; case GTK_MOVEMENT_WORDS: while (count > 0) { new_pos = eel_editable_label_move_forward_word (label, new_pos); count--; } while (count < 0) { new_pos = eel_editable_label_move_backward_word (label, new_pos); count++; } break; case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: /* FIXME: Can do better here */ new_pos = count < 0 ? 0 : strlen (label->text); break; case GTK_MOVEMENT_DISPLAY_LINES: new_pos = eel_editable_label_move_line (label, new_pos, count); break; break; case GTK_MOVEMENT_PARAGRAPHS: case GTK_MOVEMENT_PAGES: case GTK_MOVEMENT_HORIZONTAL_PAGES: break; default: g_assert_not_reached (); break; } } if (extend_selection) eel_editable_label_select_region_index (label, label->selection_anchor, new_pos); else eel_editable_label_select_region_index (label, new_pos, new_pos); } static void eel_editable_label_reset_im_context (EelEditableLabel *label) { if (label->need_im_reset) { label->need_im_reset = 0; gtk_im_context_reset (label->im_context); } } static void eel_editable_label_delete_from_cursor (EelEditableLabel *label, GtkDeleteType type, gint count) { GtkEditable *editable = GTK_EDITABLE (label); gint start_pos = label->selection_anchor; gint end_pos = label->selection_anchor; eel_editable_label_reset_im_context (label); if (label->selection_anchor != label->selection_end) { gtk_editable_delete_selection (editable); return; } switch (type) { case GTK_DELETE_CHARS: end_pos = eel_editable_label_move_logically (label, start_pos, count); start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); gtk_editable_delete_text (GTK_EDITABLE (label), MIN (start_pos, end_pos), MAX (start_pos, end_pos)); break; case GTK_DELETE_WORDS: if (count < 0) { /* Move to end of current word, or if not on a word, end of previous word */ end_pos = eel_editable_label_move_backward_word (label, end_pos); end_pos = eel_editable_label_move_forward_word (label, end_pos); } else if (count > 0) { /* Move to beginning of current word, or if not on a word, begining of next word */ start_pos = eel_editable_label_move_forward_word (label, start_pos); start_pos = eel_editable_label_move_backward_word (label, start_pos); } /* Fall through */ case GTK_DELETE_WORD_ENDS: while (count < 0) { start_pos = eel_editable_label_move_backward_word (label, start_pos); count++; } while (count > 0) { end_pos = eel_editable_label_move_forward_word (label, end_pos); count--; } start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); gtk_editable_delete_text (GTK_EDITABLE (label), start_pos, end_pos); break; case GTK_DELETE_DISPLAY_LINE_ENDS: case GTK_DELETE_PARAGRAPH_ENDS: end_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); if (count < 0) gtk_editable_delete_text (GTK_EDITABLE (label), 0, end_pos); else gtk_editable_delete_text (GTK_EDITABLE (label), end_pos, -1); break; case GTK_DELETE_DISPLAY_LINES: case GTK_DELETE_PARAGRAPHS: gtk_editable_delete_text (GTK_EDITABLE (label), 0, -1); break; case GTK_DELETE_WHITESPACE: /* TODO eel_editable_label_delete_whitespace (label); */ break; default: g_assert_not_reached (); break; } eel_editable_label_pend_cursor_blink (label); } static void eel_editable_label_copy_clipboard (EelEditableLabel *label) { if (label->text) { gint start, end; gint len; start = MIN (label->selection_anchor, label->selection_end); end = MAX (label->selection_anchor, label->selection_end); len = strlen (label->text); if (end > len) end = len; if (start > len) start = len; if (start != end) gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), label->text + start, end - start); } } static void eel_editable_label_cut_clipboard (EelEditableLabel *label) { if (label->text) { gint start, end; gint len; start = MIN (label->selection_anchor, label->selection_end); end = MAX (label->selection_anchor, label->selection_end); len = strlen (label->text); if (end > len) end = len; if (start > len) start = len; if (start != end) { gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), label->text + start, end - start); start = g_utf8_pointer_to_offset (label->text, label->text + start); end = g_utf8_pointer_to_offset (label->text, label->text + end); gtk_editable_delete_text (GTK_EDITABLE (label), start, end); } } } static void paste_received (GtkClipboard *clipboard, const gchar *text, gpointer data) { EelEditableLabel *label = EEL_EDITABLE_LABEL (data); GtkEditable *editable = GTK_EDITABLE (label); gint tmp_pos; if (text) { if (label->selection_end != label->selection_anchor) gtk_editable_delete_selection (editable); tmp_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); gtk_editable_insert_text (GTK_EDITABLE (label), text, strlen (text), &tmp_pos); tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text; eel_editable_label_select_region_index (label, tmp_pos, tmp_pos); } g_object_unref (G_OBJECT (label)); } static void eel_editable_label_paste (EelEditableLabel *label, GdkAtom selection) { g_object_ref (G_OBJECT (label)); gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (label), selection), paste_received, label); } static void eel_editable_label_paste_clipboard (EelEditableLabel *label) { eel_editable_label_paste (label, GDK_NONE); } static void eel_editable_label_select_all (EelEditableLabel *label) { eel_editable_label_select_region_index (label, 0, strlen (label->text)); } /* Quick hack of a popup menu */ static void activate_cb (GtkWidget *menuitem, EelEditableLabel *label) { const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal"); g_signal_emit_by_name (label, signal); } static void append_action_signal (EelEditableLabel *label, GtkWidget *menu, const gchar *stock_id, const gchar *signal, gboolean sensitive) { GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL); g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal); g_signal_connect (menuitem, "activate", G_CALLBACK (activate_cb), label); gtk_widget_set_sensitive (menuitem, sensitive); gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); } static void popup_menu_detach (GtkWidget *attach_widget, GtkMenu *menu) { EelEditableLabel *label; label = EEL_EDITABLE_LABEL (attach_widget); label->popup_menu = NULL; } static void popup_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) { EelEditableLabel *label; GtkWidget *widget; GtkRequisition req; GtkAllocation allocation; label = EEL_EDITABLE_LABEL (user_data); widget = GTK_WIDGET (label); g_assert (gtk_widget_get_realized (widget)); gdk_window_get_origin (label->text_area, x, y); gtk_widget_get_preferred_size (widget, &req, NULL); gtk_widget_get_allocation (widget, &allocation); *x += allocation.width / 2; *y += allocation.height; *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width)); *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height)); } static void eel_editable_label_toggle_overwrite (EelEditableLabel *label) { label->overwrite_mode = !label->overwrite_mode; gtk_widget_queue_draw (GTK_WIDGET (label)); } typedef struct { EelEditableLabel *label; gint button; guint time; } PopupInfo; static void popup_targets_received (GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data) { GtkWidget *menuitem, *submenu; gboolean have_selection; gboolean clipboard_contains_text; PopupInfo *info; EelEditableLabel *label; info = user_data; label = info->label; if (gtk_widget_get_realized (GTK_WIDGET (label))) { if (label->popup_menu) gtk_widget_destroy (label->popup_menu); label->popup_menu = gtk_menu_new (); gtk_menu_attach_to_widget (GTK_MENU (label->popup_menu), GTK_WIDGET (label), popup_menu_detach); have_selection = label->selection_anchor != label->selection_end; clipboard_contains_text = gtk_selection_data_targets_include_text (data); append_action_signal (label, label->popup_menu, GTK_STOCK_CUT, "cut_clipboard", have_selection); append_action_signal (label, label->popup_menu, GTK_STOCK_COPY, "copy_clipboard", have_selection); append_action_signal (label, label->popup_menu, GTK_STOCK_PASTE, "paste_clipboard", clipboard_contains_text); menuitem = gtk_menu_item_new_with_label (_("Select All")); g_signal_connect_object (menuitem, "activate", G_CALLBACK (eel_editable_label_select_all), label, G_CONNECT_SWAPPED); gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); menuitem = gtk_separator_menu_item_new (); gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); menuitem = gtk_menu_item_new_with_label (_("Input Methods")); gtk_widget_show (menuitem); submenu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (label->im_context), GTK_MENU_SHELL (submenu)); g_signal_emit (label, signals[POPULATE_POPUP], 0, label->popup_menu); if (info->button) gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, NULL, NULL, info->button, info->time); else { gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, popup_position_func, label, info->button, info->time); gtk_menu_shell_select_first (GTK_MENU_SHELL (label->popup_menu), FALSE); } } g_object_unref (label); g_free (info); } static void eel_editable_label_do_popup (EelEditableLabel *label, GdkEventButton *event) { PopupInfo *info = g_new (PopupInfo, 1); /* In order to know what entries we should make sensitive, we * ask for the current targets of the clipboard, and when * we get them, then we actually pop up the menu. */ info->label = g_object_ref (label); if (event) { info->button = event->button; info->time = event->time; } else { info->button = 0; info->time = gtk_get_current_event_time (); } gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD), gdk_atom_intern ("TARGETS", FALSE), popup_targets_received, info); } /************ Editable implementation ****************/ static void editable_insert_text_emit (GtkEditable *editable, const gchar *new_text, gint new_text_length, gint *position) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); gchar buf[64]; gchar *text; int text_length; text_length = g_utf8_strlen (label->text, -1); if (*position < 0 || *position > text_length) *position = text_length; g_object_ref (G_OBJECT (editable)); if (new_text_length <= 63) text = buf; else text = g_new (gchar, new_text_length + 1); text[new_text_length] = '\0'; strncpy (text, new_text, new_text_length); g_signal_emit_by_name (editable, "insert_text", text, new_text_length, position); if (new_text_length > 63) g_free (text); g_object_unref (G_OBJECT (editable)); } static void editable_delete_text_emit (GtkEditable *editable, gint start_pos, gint end_pos) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); int text_length; text_length = g_utf8_strlen (label->text, -1); if (end_pos < 0 || end_pos > text_length) end_pos = text_length; if (start_pos < 0) start_pos = 0; if (start_pos > end_pos) start_pos = end_pos; g_object_ref (G_OBJECT (editable)); g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos); g_object_unref (G_OBJECT (editable)); } static void editable_insert_text (GtkEditable *editable, const gchar *new_text, gint new_text_length, gint *position) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); gint index; if (new_text_length < 0) new_text_length = strlen (new_text); index = g_utf8_offset_to_pointer (label->text, *position) - label->text; eel_editable_label_insert_text (label, new_text, new_text_length, &index); *position = g_utf8_pointer_to_offset (label->text, label->text + index); } static void editable_delete_text (GtkEditable *editable, gint start_pos, gint end_pos) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); int text_length; gint start_index, end_index; text_length = g_utf8_strlen (label->text, -1); if (end_pos < 0 || end_pos > text_length) end_pos = text_length; if (start_pos < 0) start_pos = 0; if (start_pos > end_pos) start_pos = end_pos; start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; eel_editable_label_delete_text (label, start_index, end_index); } static gchar * editable_get_chars (GtkEditable *editable, gint start_pos, gint end_pos) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); int text_length; gint start_index, end_index; text_length = g_utf8_strlen (label->text, -1); if (end_pos < 0 || end_pos > text_length) end_pos = text_length; if (start_pos < 0) start_pos = 0; if (start_pos > end_pos) start_pos = end_pos; start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; return g_strndup (label->text + start_index, end_index - start_index); } static void editable_set_selection_bounds (GtkEditable *editable, gint start, gint end) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); int text_length; gint start_index, end_index; text_length = g_utf8_strlen (label->text, -1); if (end < 0 || end > text_length) end = text_length; if (start < 0) start = text_length; if (start > text_length) start = text_length; eel_editable_label_reset_im_context (label); start_index = g_utf8_offset_to_pointer (label->text, start) - label->text; end_index = g_utf8_offset_to_pointer (label->text, end) - label->text; eel_editable_label_select_region_index (label, start_index, end_index); } static gboolean editable_get_selection_bounds (GtkEditable *editable, gint *start, gint *end) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); *start = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); *end = g_utf8_pointer_to_offset (label->text, label->text + label->selection_end); return (label->selection_anchor != label->selection_end); } static void editable_real_set_position (GtkEditable *editable, gint position) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); int text_length; int index; text_length = g_utf8_strlen (label->text, -1); if (position < 0 || position > text_length) position = text_length; index = g_utf8_offset_to_pointer (label->text, position) - label->text; if (index != label->selection_anchor || index != label->selection_end) { eel_editable_label_select_region_index (label, index, index); } } static gint editable_get_position (GtkEditable *editable) { EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); return g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); } static AtkObjectClass *a11y_parent_class = NULL; static const char* eel_editable_label_accessible_data = "eel-editable-label-accessible-data"; /************ Accessible implementation ****************/ typedef struct { GailTextUtil *textutil; gint selection_anchor; gint selection_end; const gchar *signal_name; gint position; gint length; } EelEditableLabelAccessiblePrivate; typedef struct { EelEditableLabel* label; gint position; } EelEditableLabelAccessiblePaste; static gchar* eel_editable_label_accessible_get_text (AtkText *text, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabelAccessiblePrivate *priv; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); return gail_text_util_get_substring (priv->textutil, start_pos, end_pos); } static gunichar eel_editable_label_accessible_get_character_at_offset (AtkText *text, gint offset) { GtkWidget *widget; EelEditableLabelAccessiblePrivate *priv; gchar *string; gchar *index; gunichar unichar; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return '\0'; priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); string = gail_text_util_get_substring (priv->textutil, 0, -1); if (offset >= g_utf8_strlen (string, -1)) { unichar = '\0'; } else { index = g_utf8_offset_to_pointer (string, offset); unichar = g_utf8_get_char(index); } g_free(string); return unichar; } static gchar* eel_editable_label_accessible_get_text_before_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GtkWidget *widget; EelEditableLabel *label; EelEditableLabelAccessiblePrivate *priv; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; label = EEL_EDITABLE_LABEL (widget); priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); return gail_text_util_get_text (priv->textutil, eel_editable_label_get_layout (label), GAIL_BEFORE_OFFSET, boundary_type, offset, start_offset, end_offset); } static gchar* eel_editable_label_accessible_get_text_at_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GtkWidget *widget; EelEditableLabel *label; EelEditableLabelAccessiblePrivate *priv; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; label = EEL_EDITABLE_LABEL (widget); priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); return gail_text_util_get_text (priv->textutil, eel_editable_label_get_layout (label), GAIL_AT_OFFSET, boundary_type, offset, start_offset, end_offset); } static gchar* eel_editable_label_accessible_get_text_after_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { GtkWidget *widget; EelEditableLabel *label; EelEditableLabelAccessiblePrivate *priv; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; label = EEL_EDITABLE_LABEL (widget); priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); return gail_text_util_get_text (priv->textutil, eel_editable_label_get_layout (label), GAIL_AFTER_OFFSET, boundary_type, offset, start_offset, end_offset); } static gint eel_editable_label_accessible_get_caret_offset (AtkText *text) { GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return 0; return gtk_editable_get_position (GTK_EDITABLE (widget)); } static gboolean eel_editable_label_accessible_set_caret_offset (AtkText *text, gint offset) { GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return FALSE; gtk_editable_set_position (GTK_EDITABLE (widget), offset); return TRUE; } static gint eel_editable_label_accessible_get_character_count (AtkText *text) { GtkWidget *widget; EelEditableLabel *label; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return 0; label = EEL_EDITABLE_LABEL (widget); return g_utf8_strlen (eel_editable_label_get_text (label), -1); } static gint eel_editable_label_accessible_get_n_selections (AtkText *text) { GtkWidget *widget; EelEditableLabel *label; gint select_start, select_end; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return -1; label = EEL_EDITABLE_LABEL (widget); gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, &select_end); if (select_start != select_end) return 1; else return 0; } static gchar* eel_editable_label_accessible_get_selection (AtkText *text, gint selection_num, gint *start_pos, gint *end_pos) { GtkWidget *widget; EelEditableLabel *label; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; /* Only let the user get the selection if one is set, and if the * selection_num is 0. */ if (selection_num != 0) return NULL; label = EEL_EDITABLE_LABEL (widget); gtk_editable_get_selection_bounds (GTK_EDITABLE (label), start_pos, end_pos); if (*start_pos != *end_pos) return gtk_editable_get_chars (GTK_EDITABLE (label), *start_pos, *end_pos); else return NULL; } static gboolean eel_editable_label_accessible_add_selection (AtkText *text, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabel *label; gint select_start, select_end; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return FALSE; label = EEL_EDITABLE_LABEL (widget); gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, &select_end); /* If there is already a selection, then don't allow another to be added, * since EelEditableLabel only supports one selected region. */ if (select_start == select_end) { gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); return TRUE; } else return FALSE; } static gboolean eel_editable_label_accessible_remove_selection (AtkText *text, gint selection_num) { GtkWidget *widget; EelEditableLabel *label; gint select_start, select_end, caret_pos; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return FALSE; if (selection_num != 0) return FALSE; label = EEL_EDITABLE_LABEL (widget); gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, &select_end); if (select_start != select_end) { /* Setting the start & end of the selected region to the caret position * turns off the selection. */ caret_pos = gtk_editable_get_position (GTK_EDITABLE (label)); gtk_editable_select_region (GTK_EDITABLE (label), caret_pos, caret_pos); return TRUE; } else return FALSE; } static gboolean eel_editable_label_accessible_set_selection (AtkText *text, gint selection_num, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabel *label; gint select_start, select_end; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return FALSE; /* Only let the user move the selection if one is set, and if the * selection_num is 0 */ if (selection_num != 0) return FALSE; label = EEL_EDITABLE_LABEL (widget); gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, &select_end); if (select_start != select_end) { gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); return TRUE; } else return FALSE; } static AtkAttributeSet* eel_editable_label_accessible_get_run_attributes (AtkText *text, gint offset, gint *start_offset, gint *end_offset) { GtkWidget *widget; EelEditableLabel *label; AtkAttributeSet *at_set = NULL; GtkTextDirection dir; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; label = EEL_EDITABLE_LABEL (widget); dir = gtk_widget_get_direction (widget); if (dir == GTK_TEXT_DIR_RTL) { at_set = gail_misc_add_attribute (at_set, ATK_TEXT_ATTR_DIRECTION, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir))); } at_set = gail_misc_layout_get_run_attributes (at_set, eel_editable_label_get_layout (label), label->text, offset, start_offset, end_offset); return at_set; } static AtkAttributeSet* eel_editable_label_accessible_get_default_attributes (AtkText *text) { GtkWidget *widget; EelEditableLabel *label; AtkAttributeSet *at_set = NULL; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return NULL; label = EEL_EDITABLE_LABEL (widget); at_set = gail_misc_get_default_attributes (at_set, eel_editable_label_get_layout (label), widget); return at_set; } static void eel_editable_label_accessible_get_character_extents (AtkText *text, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords) { GtkWidget *widget; EelEditableLabel *label; PangoRectangle char_rect; gint index, cursor_index, x_layout, y_layout; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); index = g_utf8_offset_to_pointer (label->text, offset) - label->text; cursor_index = label->selection_anchor; if (index > cursor_index) index += label->preedit_length; pango_layout_index_to_pos (eel_editable_label_get_layout(label), index, &char_rect); gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, x_layout, y_layout, x, y, width, height, coords); } static gint eel_editable_label_accessible_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { GtkWidget *widget; EelEditableLabel *label; gint index, cursor_index, x_layout, y_layout; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return -1; label = EEL_EDITABLE_LABEL (widget); eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); index = gail_misc_get_index_at_point_in_layout (widget, eel_editable_label_get_layout(label), x_layout, y_layout, x, y, coords); if (index == -1) { if (coords == ATK_XY_SCREEN || coords == ATK_XY_WINDOW) return g_utf8_strlen (label->text, -1); return index; } else { cursor_index = label->selection_anchor; if (index >= cursor_index && label->preedit_length) { if (index >= cursor_index + label->preedit_length) index -= label->preedit_length; else index = cursor_index; } return g_utf8_pointer_to_offset (label->text, label->text + index); } } static void atk_text_interface_init (AtkTextIface *iface) { g_assert (iface != NULL); iface->get_text = eel_editable_label_accessible_get_text; iface->get_character_at_offset = eel_editable_label_accessible_get_character_at_offset; iface->get_text_before_offset = eel_editable_label_accessible_get_text_before_offset; iface->get_text_at_offset = eel_editable_label_accessible_get_text_at_offset; iface->get_text_after_offset = eel_editable_label_accessible_get_text_after_offset; iface->get_caret_offset = eel_editable_label_accessible_get_caret_offset; iface->set_caret_offset = eel_editable_label_accessible_set_caret_offset; iface->get_character_count = eel_editable_label_accessible_get_character_count; iface->get_n_selections = eel_editable_label_accessible_get_n_selections; iface->get_selection = eel_editable_label_accessible_get_selection; iface->add_selection = eel_editable_label_accessible_add_selection; iface->remove_selection = eel_editable_label_accessible_remove_selection; iface->set_selection = eel_editable_label_accessible_set_selection; iface->get_run_attributes = eel_editable_label_accessible_get_run_attributes; iface->get_default_attributes = eel_editable_label_accessible_get_default_attributes; iface->get_character_extents = eel_editable_label_accessible_get_character_extents; iface->get_offset_at_point = eel_editable_label_accessible_get_offset_at_point; } static void eel_editable_label_accessible_set_text_contents (AtkEditableText *text, const gchar *string) { GtkWidget *widget; EelEditableLabel *label; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); eel_editable_label_set_text (label, string); } static void eel_editable_label_accessible_insert_text (AtkEditableText *text, const gchar *string, gint length, gint *position) { GtkWidget *widget; EelEditableLabel *label; GtkEditable *editable; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); editable = GTK_EDITABLE (label); gtk_editable_insert_text (editable, string, length, position); } static void eel_editable_label_accessible_copy_text (AtkEditableText *text, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabel *label; GtkEditable *editable; gchar *str; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); editable = GTK_EDITABLE (label); str = gtk_editable_get_chars (editable, start_pos, end_pos); gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); } static void eel_editable_label_accessible_cut_text (AtkEditableText *text, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabel *label; GtkEditable *editable; gchar *str; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); editable = GTK_EDITABLE (label); str = gtk_editable_get_chars (editable, start_pos, end_pos); gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); gtk_editable_delete_text (editable, start_pos, end_pos); } static void eel_editable_label_accessible_delete_text (AtkEditableText *text, gint start_pos, gint end_pos) { GtkWidget *widget; EelEditableLabel *label; GtkEditable *editable; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; label = EEL_EDITABLE_LABEL (widget); editable = GTK_EDITABLE (label); gtk_editable_delete_text (editable, start_pos, end_pos); } static void eel_editable_label_accessible_paste_received (GtkClipboard *clipboard, const gchar *text, gpointer data) { EelEditableLabelAccessiblePaste* paste_struct = (EelEditableLabelAccessiblePaste *)data; if (text) gtk_editable_insert_text (GTK_EDITABLE (paste_struct->label), text, -1, &(paste_struct->position)); g_object_unref (paste_struct->label); } static void eel_editable_label_accessible_paste_text (AtkEditableText *text, gint position) { GtkWidget *widget; GtkEditable *editable; EelEditableLabelAccessiblePaste paste_struct; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); if (widget == NULL) /* State is defunct */ return; editable = GTK_EDITABLE (widget); if (!gtk_editable_get_editable (editable)) return; paste_struct.label = EEL_EDITABLE_LABEL (widget); paste_struct.position = position; g_object_ref (paste_struct.label); gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE), eel_editable_label_accessible_paste_received, &paste_struct); } static void atk_editable_text_interface_init (AtkEditableTextIface *iface) { g_assert (iface != NULL); iface->set_text_contents = eel_editable_label_accessible_set_text_contents; iface->insert_text = eel_editable_label_accessible_insert_text; iface->copy_text = eel_editable_label_accessible_copy_text; iface->cut_text = eel_editable_label_accessible_cut_text; iface->delete_text = eel_editable_label_accessible_delete_text; iface->paste_text = eel_editable_label_accessible_paste_text; } static void eel_editable_label_accessible_notify_insert (AtkObject *accessible) { EelEditableLabelAccessiblePrivate *priv; priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); if (priv->signal_name) { g_signal_emit_by_name (accessible, priv->signal_name, priv->position, priv->length); priv->signal_name = NULL; } } static gboolean eel_editable_label_accessible_idle_notify_insert (gpointer data) { eel_editable_label_accessible_notify_insert (data); return FALSE; } /* Note arg1 returns the character at the start of the insert. * arg2 returns the number of characters inserted. */ static void eel_editable_label_accessible_insert_text_cb (EelEditableLabel *label, gchar *arg1, gint arg2, gpointer arg3) { AtkObject *accessible; EelEditableLabelAccessiblePrivate *priv; gint *position = (gint *) arg3; accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); if (!priv->signal_name) { priv->signal_name = "text_changed::insert"; priv->position = *position; priv->length = arg2; } /* * The signal will be emitted when the cursor position is updated. * or in an idle handler if it not updated. */ g_idle_add (eel_editable_label_accessible_idle_notify_insert, accessible); } /* Note arg1 returns the start of the delete range, arg2 returns the * end of the delete range if multiple characters are deleted. */ static void eel_editable_label_accessible_delete_text_cb (EelEditableLabel *label, gint arg1, gint arg2) { AtkObject *accessible; /* * Zero length text deleted so ignore */ if (arg2 - arg1 == 0) return; accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); g_signal_emit_by_name (accessible, "text_changed::delete", arg1, arg2 - arg1); } static void eel_editable_label_accessible_changed_cb (EelEditableLabel *label) { AtkObject *accessible; EelEditableLabelAccessiblePrivate *priv; accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (label)); } static gboolean check_for_selection_change (AtkObject *accessible, GtkWidget *widget) { EelEditableLabelAccessiblePrivate *priv; EelEditableLabel *label; gboolean ret_val = FALSE; priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); label = EEL_EDITABLE_LABEL (widget); if (label->selection_anchor != label->selection_end) { if (label->selection_anchor != priv->selection_anchor || label->selection_end != priv->selection_end) /* * This check is here as this function can be called * for notification of selection_end and selection_anchor. * The values of selection_anchor and selection_end may be the same * for both notifications and we only want to generate one * text_selection_changed signal. */ ret_val = TRUE; } else { /* We had a selection */ ret_val = (priv->selection_anchor != priv->selection_end); } priv->selection_anchor = label->selection_anchor; priv->selection_end = label->selection_end; return ret_val; } static void eel_editable_label_accessible_notify_gtk (GObject *obj, GParamSpec *pspec) { GtkWidget *widget; AtkObject *accessible; EelEditableLabel *label; widget = GTK_WIDGET (obj); label = EEL_EDITABLE_LABEL (widget); accessible = gtk_widget_get_accessible (widget); if (strcmp (pspec->name, "cursor-position") == 0) { eel_editable_label_accessible_notify_insert (accessible); if (check_for_selection_change (accessible, widget)) g_signal_emit_by_name (accessible, "text_selection_changed"); /* * The label cursor position has moved so generate the signal. */ g_signal_emit_by_name (accessible, "text_caret_moved", g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor)); } else if (strcmp (pspec->name, "selection-bound") == 0) { eel_editable_label_accessible_notify_insert (accessible); if (check_for_selection_change (accessible, widget)) g_signal_emit_by_name (accessible, "text_selection_changed"); } } static void eel_editable_label_accessible_initialize (AtkObject *accessible, gpointer widget) { EelEditableLabelAccessiblePrivate *priv; EelEditableLabel *label; a11y_parent_class->initialize (accessible, widget); label = EEL_EDITABLE_LABEL (widget); priv = g_new0 (EelEditableLabelAccessiblePrivate, 1); priv->textutil = gail_text_util_new (); gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (EEL_EDITABLE_LABEL (widget))); priv->selection_anchor = label->selection_anchor; priv->selection_end = label->selection_end; g_object_set_data (G_OBJECT (accessible), eel_editable_label_accessible_data, priv); g_signal_connect (widget, "insert-text", G_CALLBACK (eel_editable_label_accessible_insert_text_cb), NULL); g_signal_connect (widget, "delete-text", G_CALLBACK (eel_editable_label_accessible_delete_text_cb), NULL); g_signal_connect (widget, "changed", G_CALLBACK (eel_editable_label_accessible_changed_cb), NULL); g_signal_connect (widget, "notify", G_CALLBACK (eel_editable_label_accessible_notify_gtk), NULL); atk_object_set_role (accessible, ATK_ROLE_TEXT); } static const gchar* eel_editable_label_accessible_get_name (AtkObject *accessible) { if (accessible->name != NULL) return accessible->name; else { GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (widget == NULL) /* State is defunct */ return NULL; g_assert (EEL_IS_EDITABLE_LABEL (widget)); return eel_editable_label_get_text (EEL_EDITABLE_LABEL (widget)); } } static AtkStateSet* eel_editable_label_accessible_ref_state_set (AtkObject *accessible) { AtkStateSet *state_set; GtkWidget *widget; state_set = a11y_parent_class->ref_state_set (accessible); widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (widget == NULL) return state_set; atk_state_set_add_state (state_set, ATK_STATE_EDITABLE); atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE); return state_set; } static void eel_editable_label_accessible_finalize (GObject *object) { EelEditableLabelAccessiblePrivate *priv; priv = g_object_get_data (object, eel_editable_label_accessible_data); g_object_unref (priv->textutil); g_free (priv); G_OBJECT_CLASS (a11y_parent_class)->finalize (object); } static void eel_editable_label_accessible_class_init (AtkObjectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); a11y_parent_class = g_type_class_peek_parent (klass); klass->initialize = eel_editable_label_accessible_initialize; klass->get_name = eel_editable_label_accessible_get_name; klass->ref_state_set = eel_editable_label_accessible_ref_state_set; gobject_class->finalize = eel_editable_label_accessible_finalize; } static AtkObject * eel_editable_label_get_accessible (GtkWidget *widget) { static GType type = 0; AtkObject *accessible; if ((accessible = eel_accessibility_get_atk_object (widget))) return accessible; if (!type) { const GInterfaceInfo atk_editable_text_info = { (GInterfaceInitFunc) atk_editable_text_interface_init, (GInterfaceFinalizeFunc) NULL, NULL }; const GInterfaceInfo atk_text_info = { (GInterfaceInitFunc) atk_text_interface_init, (GInterfaceFinalizeFunc) NULL, NULL }; type = eel_accessibility_create_derived_type ("EelEditableLabelAccessible", G_TYPE_FROM_INSTANCE (widget), eel_editable_label_accessible_class_init); if (!type) return NULL; g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info); } accessible = g_object_new (type, NULL); return eel_accessibility_set_atk_object_return (widget, accessible); } nemo-4.4.2/eel/eel-editable-label.h000066400000000000000000000131261357442400300167730ustar00rootroot00000000000000/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #ifndef __EEL_EDITABLE_LABEL_H__ #define __EEL_EDITABLE_LABEL_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define EEL_TYPE_EDITABLE_LABEL eel_editable_label_get_type() #define EEL_EDITABLE_LABEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_EDITABLE_LABEL, EelEditableLabel)) #define EEL_EDITABLE_LABEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_EDITABLE_LABEL, EelEditableLabelClass)) #define EEL_IS_EDITABLE_LABEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_EDITABLE_LABEL)) #define EEL_IS_EDITABLE_LABEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_EDITABLE_LABEL)) #define EEL_EDITABLE_LABEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_EDITABLE_LABEL, EelEditableLabelClass)) typedef struct _EelEditableLabel EelEditableLabel; typedef struct _EelEditableLabelClass EelEditableLabelClass; typedef struct _EelEditableLabelSelectionInfo EelEditableLabelSelectionInfo; struct _EelEditableLabel { GtkMisc misc; guint jtype : 2; guint wrap : 1; guint overwrite_mode : 1; guint draw_outline : 1; guint layout_includes_preedit : 1; guint padding:2; PangoWrapMode wrap_mode; GdkWindow *text_area; gchar *text; int text_size; /* allocated size, in bytes */ int n_bytes; /* length in use (not including terminating zero), in bytes */ PangoLayout *layout; int selection_anchor; /* cursor pos, byte index */ int selection_end; /* byte index */ GtkWidget *popup_menu; GtkIMContext *im_context; gboolean need_im_reset; int preedit_length; /* length of preedit string, in bytes */ int preedit_cursor; /* offset of cursor within preedit string, in chars */ PangoFontDescription *font_desc; }; struct _EelEditableLabelClass { GtkMiscClass parent_class; void (* move_cursor) (EelEditableLabel *label, GtkMovementStep step, gint count, gboolean extend_selection); void (* insert_at_cursor) (EelEditableLabel *label, const gchar *str); void (* delete_from_cursor) (EelEditableLabel *label, GtkDeleteType type, gint count); void (* cut_clipboard) (EelEditableLabel *label); void (* copy_clipboard) (EelEditableLabel *label); void (* paste_clipboard) (EelEditableLabel *label); void (* toggle_overwrite) (EelEditableLabel *label); /* Hook to customize right-click popup for selectable labels */ void (* populate_popup) (EelEditableLabel *label, GtkMenu *menu); }; GType eel_editable_label_get_type (void) G_GNUC_CONST; GtkWidget* eel_editable_label_new (const char *str); void eel_editable_label_set_text (EelEditableLabel *label, const char *str); const gchar* eel_editable_label_get_text (EelEditableLabel *label); void eel_editable_label_set_justify (EelEditableLabel *label, GtkJustification jtype); GtkJustification eel_editable_label_get_justify (EelEditableLabel *label); void eel_editable_label_set_line_wrap (EelEditableLabel *label, gboolean wrap); void eel_editable_label_set_line_wrap_mode (EelEditableLabel *label, PangoWrapMode mode); gboolean eel_editable_label_get_line_wrap (EelEditableLabel *label); void eel_editable_label_set_draw_outline (EelEditableLabel *label, gboolean wrap); void eel_editable_label_select_region (EelEditableLabel *label, gint start_offset, gint end_offset); gboolean eel_editable_label_get_selection_bounds (EelEditableLabel *label, gint *start, gint *end); PangoLayout * eel_editable_label_get_layout (EelEditableLabel *label); void eel_editable_label_get_layout_offsets (EelEditableLabel *label, gint *x, gint *y); PangoFontDescription *eel_editable_label_get_font_description (EelEditableLabel *label); void eel_editable_label_set_font_description (EelEditableLabel *label, const PangoFontDescription *desc); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __EEL_EDITABLE_LABEL_H__ */ nemo-4.4.2/eel/eel-gdk-extensions.c000066400000000000000000000045361357442400300171070ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gdk-extensions.c: Graphics routines to augment what's in gdk. Copyright (C) 1999, 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler , Pavel Cisler , Ramiro Estrugo */ #include #include "eel-gdk-extensions.h" #include "eel-glib-extensions.h" #include "eel-string.h" #include #include #include #include #include EelGdkGeometryFlags eel_gdk_parse_geometry (const char *string, int *x_return, int *y_return, guint *width_return, guint *height_return) { int x11_flags; EelGdkGeometryFlags gdk_flags; g_return_val_if_fail (string != NULL, EEL_GDK_NO_VALUE); g_return_val_if_fail (x_return != NULL, EEL_GDK_NO_VALUE); g_return_val_if_fail (y_return != NULL, EEL_GDK_NO_VALUE); g_return_val_if_fail (width_return != NULL, EEL_GDK_NO_VALUE); g_return_val_if_fail (height_return != NULL, EEL_GDK_NO_VALUE); x11_flags = XParseGeometry (string, x_return, y_return, width_return, height_return); gdk_flags = EEL_GDK_NO_VALUE; if (x11_flags & XValue) { gdk_flags |= EEL_GDK_X_VALUE; } if (x11_flags & YValue) { gdk_flags |= EEL_GDK_Y_VALUE; } if (x11_flags & WidthValue) { gdk_flags |= EEL_GDK_WIDTH_VALUE; } if (x11_flags & HeightValue) { gdk_flags |= EEL_GDK_HEIGHT_VALUE; } if (x11_flags & XNegative) { gdk_flags |= EEL_GDK_X_NEGATIVE; } if (x11_flags & YNegative) { gdk_flags |= EEL_GDK_Y_NEGATIVE; } return gdk_flags; } nemo-4.4.2/eel/eel-gdk-extensions.h000066400000000000000000000034171357442400300171110ustar00rootroot00000000000000// /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gdk-extensions.h: Graphics routines to augment what's in gdk. Copyright (C) 1999, 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler , Ramiro Estrugo */ #ifndef EEL_GDK_EXTENSIONS_H #define EEL_GDK_EXTENSIONS_H #include /* Bits returned by eel_gdk_parse_geometry */ typedef enum { EEL_GDK_NO_VALUE = 0x00, EEL_GDK_X_VALUE = 0x01, EEL_GDK_Y_VALUE = 0x02, EEL_GDK_WIDTH_VALUE = 0x04, EEL_GDK_HEIGHT_VALUE = 0x08, EEL_GDK_ALL_VALUES = 0x0f, EEL_GDK_X_NEGATIVE = 0x10, EEL_GDK_Y_NEGATIVE = 0x20 } EelGdkGeometryFlags; /* Wrapper for XParseGeometry */ EelGdkGeometryFlags eel_gdk_parse_geometry (const char *string, int *x_return, int *y_return, guint *width_return, guint *height_return); #endif /* EEL_GDK_EXTENSIONS_H */ nemo-4.4.2/eel/eel-glib-extensions.c000066400000000000000000000222721357442400300172540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-glib-extensions.c - implementation of new functions that conceptually belong in glib. Perhaps some of these will be actually rolled into glib someday. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #include #include "eel-glib-extensions.h" #include "eel-debug.h" #include "eel-lib-self-check-functions.h" #include "eel-string.h" #include #include #include /** * eel_g_str_list_equal * * Compares two lists of C strings to see if they are equal. * @list_a: First list. * @list_b: Second list. * * Return value: TRUE if the lists contain the same strings. **/ gboolean eel_g_str_list_equal (GList *list_a, GList *list_b) { GList *p, *q; for (p = list_a, q = list_b; p != NULL && q != NULL; p = p->next, q = q->next) { if (g_strcmp0 (p->data, q->data) != 0) { return FALSE; } } return p == NULL && q == NULL; } /** * eel_g_str_list_copy * * @list: List of strings and/or NULLs to copy. * Return value: Deep copy of @list. **/ GList * eel_g_str_list_copy (GList *list) { return g_list_copy_deep (list, (GCopyFunc) g_strdup, NULL); } gboolean eel_g_strv_equal (char **a, char **b) { int i; if (g_strv_length (a) != g_strv_length (b)) { return FALSE; } for (i = 0; a[i] != NULL; i++) { if (strcmp (a[i], b[i]) != 0) { return FALSE; } } return TRUE; } static int compare_pointers (gconstpointer pointer_1, gconstpointer pointer_2) { if ((const char *) pointer_1 < (const char *) pointer_2) { return -1; } if ((const char *) pointer_1 > (const char *) pointer_2) { return +1; } return 0; } gboolean eel_g_lists_sort_and_check_for_intersection (GList **list_1, GList **list_2) { GList *node_1, *node_2; int compare_result; *list_1 = g_list_sort (*list_1, compare_pointers); *list_2 = g_list_sort (*list_2, compare_pointers); node_1 = *list_1; node_2 = *list_2; while (node_1 != NULL && node_2 != NULL) { compare_result = compare_pointers (node_1->data, node_2->data); if (compare_result == 0) { return TRUE; } if (compare_result <= 0) { node_1 = node_1->next; } if (compare_result >= 0) { node_2 = node_2->next; } } return FALSE; } /** * eel_g_list_partition * * Parition a list into two parts depending on whether the data * elements satisfy a provided predicate. Order is preserved in both * of the resulting lists, and the original list is consumed. A list * of the items that satisfy the predicate is returned, and the list * of items not satisfying the predicate is returned via the failed * out argument. * * @list: List to partition. * @predicate: Function to call on each element. * @user_data: Data to pass to function. * @failed: The GList * variable pointed to by this argument will be * set to the list of elements for which the predicate returned * false. */ GList * eel_g_list_partition (GList *list, EelPredicateFunction predicate, gpointer user_data, GList **failed) { GList *predicate_true; GList *predicate_false; GList *reverse; GList *p; GList *next; predicate_true = NULL; predicate_false = NULL; reverse = g_list_reverse (list); for (p = reverse; p != NULL; p = next) { next = p->next; if (next != NULL) { next->prev = NULL; } if (predicate (p->data, user_data)) { p->next = predicate_true; if (predicate_true != NULL) { predicate_true->prev = p; } predicate_true = p; } else { p->next = predicate_false; if (predicate_false != NULL) { predicate_false->prev = p; } predicate_false = p; } } *failed = predicate_false; return predicate_true; } typedef struct { GList *keys; GList *values; } FlattenedHashTable; static void flatten_hash_table_element (gpointer key, gpointer value, gpointer callback_data) { FlattenedHashTable *flattened_table; flattened_table = callback_data; flattened_table->keys = g_list_prepend (flattened_table->keys, key); flattened_table->values = g_list_prepend (flattened_table->values, value); } void eel_g_hash_table_safe_for_each (GHashTable *hash_table, GHFunc callback, gpointer callback_data) { FlattenedHashTable flattened; GList *p, *q; flattened.keys = NULL; flattened.values = NULL; g_hash_table_foreach (hash_table, flatten_hash_table_element, &flattened); for (p = flattened.keys, q = flattened.values; p != NULL; p = p->next, q = q->next) { (* callback) (p->data, q->data, callback_data); } g_list_free (flattened.keys); g_list_free (flattened.values); } /** * eel_g_object_list_copy * * Copy the list of objects, ref'ing each one. * @list: GList of objects. **/ GList * eel_g_object_list_copy (GList *list) { g_list_foreach (list, (GFunc) g_object_ref, NULL); return g_list_copy (list); } #if !defined (EEL_OMIT_SELF_CHECK) static gboolean eel_test_predicate (gpointer data, gpointer callback_data) { return g_ascii_strcasecmp (data, callback_data) <= 0; } void eel_self_check_glib_extensions (void) { GList *compare_list_1; GList *compare_list_2; GList *compare_list_3; GList *compare_list_4; GList *compare_list_5; GList *list_to_partition; GList *expected_passed; GList *expected_failed; GList *actual_passed; GList *actual_failed; /* eel_g_str_list_equal */ /* We g_strdup because identical string constants can be shared. */ compare_list_1 = NULL; compare_list_1 = g_list_append (compare_list_1, g_strdup ("Apple")); compare_list_1 = g_list_append (compare_list_1, g_strdup ("zebra")); compare_list_1 = g_list_append (compare_list_1, g_strdup ("!@#!@$#@$!")); compare_list_2 = NULL; compare_list_2 = g_list_append (compare_list_2, g_strdup ("Apple")); compare_list_2 = g_list_append (compare_list_2, g_strdup ("zebra")); compare_list_2 = g_list_append (compare_list_2, g_strdup ("!@#!@$#@$!")); compare_list_3 = NULL; compare_list_3 = g_list_append (compare_list_3, g_strdup ("Apple")); compare_list_3 = g_list_append (compare_list_3, g_strdup ("zebra")); compare_list_4 = NULL; compare_list_4 = g_list_append (compare_list_4, g_strdup ("Apple")); compare_list_4 = g_list_append (compare_list_4, g_strdup ("zebra")); compare_list_4 = g_list_append (compare_list_4, g_strdup ("!@#!@$#@$!")); compare_list_4 = g_list_append (compare_list_4, g_strdup ("foobar")); compare_list_5 = NULL; compare_list_5 = g_list_append (compare_list_5, g_strdup ("Apple")); compare_list_5 = g_list_append (compare_list_5, g_strdup ("zzzzzebraaaaaa")); compare_list_5 = g_list_append (compare_list_5, g_strdup ("!@#!@$#@$!")); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_2), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_3), FALSE); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_4), FALSE); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_5), FALSE); g_list_free_full (compare_list_1, g_free); g_list_free_full (compare_list_2, g_free); g_list_free_full (compare_list_3, g_free); g_list_free_full (compare_list_4, g_free); g_list_free_full (compare_list_5, g_free); /* eel_g_list_partition */ list_to_partition = NULL; list_to_partition = g_list_append (list_to_partition, (gpointer) "Cadillac"); list_to_partition = g_list_append (list_to_partition, (gpointer) "Pontiac"); list_to_partition = g_list_append (list_to_partition, (gpointer) "Ford"); list_to_partition = g_list_append (list_to_partition, (gpointer) "Range Rover"); expected_passed = NULL; expected_passed = g_list_append (expected_passed, (gpointer) "Cadillac"); expected_passed = g_list_append (expected_passed, (gpointer) "Ford"); expected_failed = NULL; expected_failed = g_list_append (expected_failed, (gpointer) "Pontiac"); expected_failed = g_list_append (expected_failed, (gpointer) "Range Rover"); actual_passed = eel_g_list_partition (list_to_partition, eel_test_predicate, (gpointer) "m", &actual_failed); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (expected_passed, actual_passed), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (expected_failed, actual_failed), TRUE); /* Don't free "list_to_partition", since it is consumed * by eel_g_list_partition. */ g_list_free (expected_passed); g_list_free (actual_passed); g_list_free (expected_failed); g_list_free (actual_failed); } #endif /* !EEL_OMIT_SELF_CHECK */ nemo-4.4.2/eel/eel-glib-extensions.h000066400000000000000000000050741357442400300172620ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-glib-extensions.h - interface for new functions that conceptually belong in glib. Perhaps some of these will be actually rolled into glib someday. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #ifndef EEL_GLIB_EXTENSIONS_H #define EEL_GLIB_EXTENSIONS_H #include #include /* A gboolean variant for bit fields. */ typedef guint eel_boolean_bit; /* Predicate. */ typedef gboolean (* EelPredicateFunction) (gpointer data, gpointer callback_data); /* GList functions. */ gboolean eel_g_lists_sort_and_check_for_intersection (GList **list_a, GList **list_b); GList * eel_g_list_partition (GList *list, EelPredicateFunction predicate, gpointer user_data, GList **removed); /* List functions for lists of C strings. */ gboolean eel_g_str_list_equal (GList *str_list_a, GList *str_list_b); GList * eel_g_str_list_copy (GList *str_list); /* List functions for lists of objects */ GList * eel_g_object_list_copy (GList *list); /* GHashTable functions */ void eel_g_hash_table_safe_for_each (GHashTable *hash_table, GHFunc callback, gpointer callback_data); /* NULL terminated string arrays (strv). */ gboolean eel_g_strv_equal (char **a, char **b); #endif /* EEL_GLIB_EXTENSIONS_H */ nemo-4.4.2/eel/eel-gnome-extensions.c000066400000000000000000000103771357442400300174470ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gnome-extensions.c - implementation of new functions that operate on gnome classes. Perhaps some of these should be rolled into gnome someday. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include "eel-gnome-extensions.h" #include /* Adapted from gio - gdesktopappinfo.c - prepend_terminal_to_vector */ static char * prepend_terminal_to_command_line (const char *command_line) { GSettings *settings; gchar *prefix = NULL; gchar *terminal = NULL; gchar *ret = NULL; g_return_val_if_fail (command_line != NULL, g_strdup (command_line)); settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal"); terminal = g_settings_get_string (settings, "exec"); if (terminal != NULL) { gchar *term_path = NULL; term_path = g_find_program_in_path (terminal); if (term_path != NULL) { gchar *exec_flag = NULL; exec_flag = g_settings_get_string (settings, "exec-arg"); if (exec_flag == NULL) { prefix = g_strdup (term_path); } else { prefix = g_strdup_printf ("%s %s", term_path, exec_flag); } g_free (exec_flag); } g_free (term_path); } g_object_unref (settings); g_free (terminal); if (prefix == NULL) { gchar *check = NULL; check = g_find_program_in_path ("gnome-terminal"); if (check != NULL) { /* Note that gnome-terminal takes -x and * as -e in gnome-terminal is broken we use that. */ prefix = g_strdup_printf ("gnome-terminal -x"); } else { check = g_find_program_in_path ("nxterm"); if (check == NULL) check = g_find_program_in_path ("color-xterm"); if (check == NULL) check = g_find_program_in_path ("rxvt"); if (check == NULL) check = g_find_program_in_path ("xterm"); if (check == NULL) check = g_find_program_in_path ("dtterm"); if (check == NULL) { check = g_strdup ("xterm"); g_warning ("couldn't find a terminal, falling back to xterm"); } prefix = g_strdup_printf ("%s -e", check); } g_free (check); } ret = g_strdup_printf ("%s %s", prefix, command_line); g_free (prefix); return ret; } /* Return a command string containing the path to a terminal on this system. */ void eel_gnome_open_terminal_on_screen (const gchar *command, GdkScreen *screen) { gchar *command_line; GAppInfo *app; GdkAppLaunchContext *ctx; GError *error = NULL; GdkDisplay *display; command_line = prepend_terminal_to_command_line (command); app = g_app_info_create_from_commandline (command_line, NULL, 0, &error); if (app != NULL && screen != NULL) { display = gdk_screen_get_display (screen); ctx = gdk_display_get_app_launch_context (display); gdk_app_launch_context_set_screen (ctx, screen); g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (ctx), &error); g_object_unref (app); g_object_unref (ctx); } if (error != NULL) { g_message ("Could not start application on terminal: %s", error->message); g_error_free (error); } } nemo-4.4.2/eel/eel-gnome-extensions.h000066400000000000000000000027431357442400300174520ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gnome-extensions.h - interface for new functions that operate on gnome classes. Perhaps some of these should be rolled into gnome someday. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #ifndef EEL_GNOME_EXTENSIONS_H #define EEL_GNOME_EXTENSIONS_H #include /* Open up a new terminal, optionally passing in a command to execute */ void eel_gnome_open_terminal_on_screen (const char *command, GdkScreen *screen); #endif /* EEL_GNOME_EXTENSIONS_H */ nemo-4.4.2/eel/eel-graphic-effects.c000066400000000000000000000233571357442400300172010ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Eel - pixbuf manipulation routines for graphical effects. * * Copyright (C) 2000 Eazel, Inc * * Author: Andy Hertzfeld * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ /* This file contains pixbuf manipulation routines used for graphical effects like pre-lighting and selection hilighting */ #include #include "eel-graphic-effects.h" #include "eel-glib-extensions.h" #include #include /* shared utility to create a new pixbuf from the passed-in one */ static GdkPixbuf * create_new_pixbuf (GdkPixbuf *src) { g_assert (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB); g_assert ((!gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 3) || (gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 4)); return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), gdk_pixbuf_get_has_alpha (src), gdk_pixbuf_get_bits_per_sample (src), gdk_pixbuf_get_width (src), gdk_pixbuf_get_height (src)); } /* utility routine to bump the level of a color component with pinning */ static guchar lighten_component (guchar cur_value) { int new_value = cur_value; new_value += 10 + (new_value >> 3); if (new_value > 255) { new_value = 255; } return (guchar) new_value; } GdkPixbuf * eel_create_spotlight_pixbuf (GdkPixbuf* src) { GdkPixbuf *dest; int i, j; int width, height, has_alpha, src_row_stride, dst_row_stride; guchar *target_pixels, *original_pixels; guchar *pixsrc, *pixdest; g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 3) || (gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 4), NULL); g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); dest = create_new_pixbuf (src); has_alpha = gdk_pixbuf_get_has_alpha (src); width = gdk_pixbuf_get_width (src); height = gdk_pixbuf_get_height (src); dst_row_stride = gdk_pixbuf_get_rowstride (dest); src_row_stride = gdk_pixbuf_get_rowstride (src); target_pixels = gdk_pixbuf_get_pixels (dest); original_pixels = gdk_pixbuf_get_pixels (src); for (i = 0; i < height; i++) { pixdest = target_pixels + i * dst_row_stride; pixsrc = original_pixels + i * src_row_stride; for (j = 0; j < width; j++) { *pixdest++ = lighten_component (*pixsrc++); *pixdest++ = lighten_component (*pixsrc++); *pixdest++ = lighten_component (*pixsrc++); if (has_alpha) { *pixdest++ = *pixsrc++; } } } return dest; } /* this routine colorizes the passed-in pixbuf by multiplying each pixel with the passed in color */ GdkPixbuf * eel_create_colorized_pixbuf (GdkPixbuf *src, GdkRGBA *color) { int i, j; int width, height, has_alpha, src_row_stride, dst_row_stride; guchar *target_pixels; guchar *original_pixels; guchar *pixsrc; guchar *pixdest; GdkPixbuf *dest; gint red_value, green_value, blue_value; g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 3) || (gdk_pixbuf_get_has_alpha (src) && gdk_pixbuf_get_n_channels (src) == 4), NULL); g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); red_value = (gint) floor (color->red * 255); green_value = (gint) floor (color->green * 255); blue_value = (gint) floor (color->blue * 255); dest = create_new_pixbuf (src); has_alpha = gdk_pixbuf_get_has_alpha (src); width = gdk_pixbuf_get_width (src); height = gdk_pixbuf_get_height (src); src_row_stride = gdk_pixbuf_get_rowstride (src); dst_row_stride = gdk_pixbuf_get_rowstride (dest); target_pixels = gdk_pixbuf_get_pixels (dest); original_pixels = gdk_pixbuf_get_pixels (src); for (i = 0; i < height; i++) { pixdest = target_pixels + i*dst_row_stride; pixsrc = original_pixels + i*src_row_stride; for (j = 0; j < width; j++) { *pixdest++ = (*pixsrc++ * red_value) >> 8; *pixdest++ = (*pixsrc++ * green_value) >> 8; *pixdest++ = (*pixsrc++ * blue_value) >> 8; if (has_alpha) { *pixdest++ = *pixsrc++; } } } return dest; } /* utility to stretch a frame to the desired size */ static void draw_frame_row (GdkPixbuf *frame_image, int target_width, int source_width, int source_v_position, int dest_v_position, GdkPixbuf *result_pixbuf, int left_offset, int height) { int remaining_width, h_offset, slab_width; remaining_width = target_width; h_offset = 0; while (remaining_width > 0) { slab_width = remaining_width > source_width ? source_width : remaining_width; gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width, height, result_pixbuf, left_offset + h_offset, dest_v_position); remaining_width -= slab_width; h_offset += slab_width; } } /* utility to draw the middle section of the frame in a loop */ static void draw_frame_column (GdkPixbuf *frame_image, int target_height, int source_height, int source_h_position, int dest_h_position, GdkPixbuf *result_pixbuf, int top_offset, int width) { int remaining_height, v_offset, slab_height; remaining_height = target_height; v_offset = 0; while (remaining_height > 0) { slab_height = remaining_height > source_height ? source_height : remaining_height; gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height, result_pixbuf, dest_h_position, top_offset + v_offset); remaining_height -= slab_height; v_offset += slab_height; } } static GdkPixbuf * eel_stretch_frame_image (GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset, int dest_width, int dest_height, gboolean fill_flag) { GdkPixbuf *result_pixbuf; guchar *pixels_ptr; int frame_width, frame_height; int y, row_stride; int target_width, target_frame_width; int target_height, target_frame_height; frame_width = gdk_pixbuf_get_width (frame_image); frame_height = gdk_pixbuf_get_height (frame_image ); if (fill_flag) { result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST); } else { result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height); } row_stride = gdk_pixbuf_get_rowstride (result_pixbuf); pixels_ptr = gdk_pixbuf_get_pixels (result_pixbuf); /* clear the new pixbuf */ if (!fill_flag) { for (y = 0; y < dest_height; y++) { memset (pixels_ptr, 255, row_stride); pixels_ptr += row_stride; } } target_width = dest_width - left_offset - right_offset; target_frame_width = frame_width - left_offset - right_offset; target_height = dest_height - top_offset - bottom_offset; target_frame_height = frame_height - top_offset - bottom_offset; /* draw the left top corner and top row */ gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0, 0); draw_frame_row (frame_image, target_width, target_frame_width, 0, 0, result_pixbuf, left_offset, top_offset); /* draw the right top corner and left column */ gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset, result_pixbuf, dest_width - right_offset, 0); draw_frame_column (frame_image, target_height, target_frame_height, 0, 0, result_pixbuf, top_offset, left_offset); /* draw the bottom right corner and bottom row */ gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset, right_offset, bottom_offset, result_pixbuf, dest_width - right_offset, dest_height - bottom_offset); draw_frame_row (frame_image, target_width, target_frame_width, frame_height - bottom_offset, dest_height - bottom_offset, result_pixbuf, left_offset, bottom_offset); /* draw the bottom left corner and the right column */ gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset, result_pixbuf, 0, dest_height - bottom_offset); draw_frame_column (frame_image, target_height, target_frame_height, frame_width - right_offset, dest_width - right_offset, result_pixbuf, top_offset, right_offset); return result_pixbuf; } /* draw an arbitrary frame around an image, with the result passed back in a newly allocated pixbuf */ GdkPixbuf * eel_embed_image_in_frame (GdkPixbuf *source_image, GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset) { GdkPixbuf *result_pixbuf; int source_width, source_height; int dest_width, dest_height; source_width = gdk_pixbuf_get_width (source_image); source_height = gdk_pixbuf_get_height (source_image); dest_width = source_width + left_offset + right_offset; dest_height = source_height + top_offset + bottom_offset; result_pixbuf = eel_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset, dest_width, dest_height, FALSE); /* Finally, copy the source image into the framed area */ gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset, top_offset); return result_pixbuf; } nemo-4.4.2/eel/eel-graphic-effects.h000066400000000000000000000031771357442400300172040ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-graphic-effects.h: Pixmap manipulation routines for graphical effects. Copyright (C) 2000 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Andy Hertzfeld */ #ifndef EEL_GRAPHIC_EFFECTS_H #define EEL_GRAPHIC_EFFECTS_H #include #include /* return a lightened pixbuf for pre-lighting */ GdkPixbuf *eel_create_spotlight_pixbuf (GdkPixbuf *source_pixbuf); /* return a pixbuf colorized with the color specified by the parameters */ GdkPixbuf* eel_create_colorized_pixbuf (GdkPixbuf *source_pixbuf, GdkRGBA *color); /* embed in image in a frame */ GdkPixbuf *eel_embed_image_in_frame (GdkPixbuf *source_image, GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset); #endif /* EEL_GRAPHIC_EFFECTS_H */ nemo-4.4.2/eel/eel-gtk-extensions.c000066400000000000000000000261771357442400300171340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gtk-extensions.c - implementation of new functions that operate on gtk classes. Perhaps some of these should be rolled into gtk someday. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan Ramiro Estrugo Darin Adler */ #include #include "eel-gtk-extensions.h" #include "eel-glib-extensions.h" #include "eel-gnome-extensions.h" #include "eel-string.h" #include #include #include #include #include #include #include #include /* This number is fairly arbitrary. Long enough to show a pretty long * menu title, but not so long to make a menu grotesquely wide. */ #define MAXIMUM_MENU_TITLE_LENGTH 48 /* Used for window position & size sanity-checking. The sizes are big enough to prevent * at least normal-sized gnome panels from obscuring the window at the screen edges. */ #define MINIMUM_ON_SCREEN_WIDTH 100 #define MINIMUM_ON_SCREEN_HEIGHT 100 /** * eel_gtk_window_get_geometry_string: * @window: a #GtkWindow * * Obtains the geometry string for this window, suitable for * set_geometry_string(); assumes the window has NorthWest gravity * * Return value: geometry string, must be freed **/ char* eel_gtk_window_get_geometry_string (GtkWindow *window) { char *str; int w, h, x, y; g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); g_return_val_if_fail (gtk_window_get_gravity (window) == GDK_GRAVITY_NORTH_WEST, NULL); gtk_window_get_position (window, &x, &y); gtk_window_get_size (window, &w, &h); str = g_strdup_printf ("%dx%d+%d+%d", w, h, x, y); return str; } static void sanity_check_window_position (int *left, int *top) { g_assert (left != NULL); g_assert (top != NULL); /* Make sure the top of the window is on screen, for * draggability (might not be necessary with all window managers, * but seems reasonable anyway). Make sure the top of the window * isn't off the bottom of the screen, or so close to the bottom * that it might be obscured by the panel. */ *top = CLAMP (*top, 0, gdk_screen_height() - MINIMUM_ON_SCREEN_HEIGHT); /* FIXME bugzilla.eazel.com 669: * If window has negative left coordinate, set_uposition sends it * somewhere else entirely. Not sure what level contains this bug (XWindows?). * Hacked around by pinning the left edge to zero, which just means you * can't set a window to be partly off the left of the screen using * this routine. */ /* Make sure the left edge of the window isn't off the right edge of * the screen, or so close to the right edge that it might be * obscured by the panel. */ *left = CLAMP (*left, 0, gdk_screen_width() - MINIMUM_ON_SCREEN_WIDTH); } static void sanity_check_window_dimensions (guint *width, guint *height) { g_assert (width != NULL); g_assert (height != NULL); /* Pin the size of the window to the screen, so we don't end up in * a state where the window is so big essential parts of it can't * be reached (might not be necessary with all window managers, * but seems reasonable anyway). */ *width = MIN ((int)*width, gdk_screen_width()); *height = MIN ((int)*height, gdk_screen_height()); } /** * eel_gtk_window_set_initial_geometry: * * Sets the position and size of a GtkWindow before the * GtkWindow is shown. It is an error to call this on a window that * is already on-screen. Takes into account screen size, and does * some sanity-checking on the passed-in values. * * @window: A non-visible GtkWindow * @geometry_flags: A EelGdkGeometryFlags value defining which of * the following parameters have defined values * @left: pixel coordinate for left of window * @top: pixel coordinate for top of window * @width: width of window in pixels * @height: height of window in pixels */ static void eel_gtk_window_set_initial_geometry (GtkWindow *window, EelGdkGeometryFlags geometry_flags, int left, int top, guint width, guint height) { GdkScreen *screen; int real_left, real_top; int screen_width, screen_height; g_return_if_fail (GTK_IS_WINDOW (window)); /* Setting the default size doesn't work when the window is already showing. * Someday we could make this move an already-showing window, but we don't * need that functionality yet. */ g_return_if_fail (!gtk_widget_get_visible (GTK_WIDGET (window))); if ((geometry_flags & EEL_GDK_X_VALUE) && (geometry_flags & EEL_GDK_Y_VALUE)) { real_left = left; real_top = top; screen = gtk_window_get_screen (window); screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); /* This is sub-optimal. GDK doesn't allow us to set win_gravity * to South/East types, which should be done if using negative * positions (so that the right or bottom edge of the window * appears at the specified position, not the left or top). * However it does seem to be consistent with other GNOME apps. */ if (geometry_flags & EEL_GDK_X_NEGATIVE) { real_left = screen_width - real_left; } if (geometry_flags & EEL_GDK_Y_NEGATIVE) { real_top = screen_height - real_top; } sanity_check_window_position (&real_left, &real_top); gtk_window_move (window, real_left, real_top); } if ((geometry_flags & EEL_GDK_WIDTH_VALUE) && (geometry_flags & EEL_GDK_HEIGHT_VALUE)) { sanity_check_window_dimensions (&width, &height); gtk_window_set_default_size (GTK_WINDOW (window), (int)width, (int)height); } } /** * eel_gtk_window_set_initial_geometry_from_string: * * Sets the position and size of a GtkWindow before the * GtkWindow is shown. The geometry is passed in as a string. * It is an error to call this on a window that * is already on-screen. Takes into account screen size, and does * some sanity-checking on the passed-in values. * * @window: A non-visible GtkWindow * @geometry_string: A string suitable for use with eel_gdk_parse_geometry * @minimum_width: If the width from the string is smaller than this, * use this for the width. * @minimum_height: If the height from the string is smaller than this, * use this for the height. * @ignore_position: If true position data from string will be ignored. */ void eel_gtk_window_set_initial_geometry_from_string (GtkWindow *window, const char *geometry_string, guint minimum_width, guint minimum_height, gboolean ignore_position) { int left, top; guint width, height; EelGdkGeometryFlags geometry_flags; g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (geometry_string != NULL); /* Setting the default size doesn't work when the window is already showing. * Someday we could make this move an already-showing window, but we don't * need that functionality yet. */ g_return_if_fail (!gtk_widget_get_visible (GTK_WIDGET (window))); geometry_flags = eel_gdk_parse_geometry (geometry_string, &left, &top, &width, &height); /* Make sure the window isn't smaller than makes sense for this window. * Other sanity checks are performed in set_initial_geometry. */ if (geometry_flags & EEL_GDK_WIDTH_VALUE) { width = MAX (width, minimum_width); } if (geometry_flags & EEL_GDK_HEIGHT_VALUE) { height = MAX (height, minimum_height); } /* Ignore saved window position if requested. */ if (ignore_position) { geometry_flags &= ~(EEL_GDK_X_VALUE | EEL_GDK_Y_VALUE); } eel_gtk_window_set_initial_geometry (window, geometry_flags, left, top, width, height); } /** * eel_pop_up_context_menu: * * Pop up a context menu under the mouse. * The menu is sunk after use, so it will be destroyed unless the * caller first ref'ed it. * * This function is more of a helper function than a gtk extension, * so perhaps it belongs in a different file. * * @menu: The menu to pop up under the mouse. * @offset_x: Ignored. * @offset_y: Ignored. * @event: The event that invoked this popup menu, or #NULL if there * is no event available. This is used to get the timestamp for the menu's popup. * In case no event is provided, gtk_get_current_event_time() will be used automatically. **/ void eel_pop_up_context_menu (GtkMenu *menu, GdkEventButton *event) { int button; g_return_if_fail (GTK_IS_MENU (menu)); /* The event button needs to be 0 if we're popping up this menu from * a button release, else a 2nd click outside the menu with any button * other than the one that invoked the menu will be ignored (instead * of dismissing the menu). This is a subtle fragility of the GTK menu code. */ if (event) { button = event->type == GDK_BUTTON_RELEASE ? 0 : event->button; } else { button = 0; } if (button > 0) { gtk_menu_popup_at_pointer (menu, (GdkEvent *) event); } else { gtk_menu_popup (menu, /* menu */ NULL, /* parent_menu_shell */ NULL, /* parent_menu_item */ NULL, /* popup_position_func */ NULL, /* popup_position_data */ button, /* button */ event ? event->time : gtk_get_current_event_time ()); /* activate_time */ } g_object_ref_sink (menu); g_object_unref (menu); } GtkMenuItem * eel_gtk_menu_append_separator (GtkMenu *menu) { return eel_gtk_menu_insert_separator (menu, -1); } GtkMenuItem * eel_gtk_menu_insert_separator (GtkMenu *menu, int index) { GtkWidget *menu_item; menu_item = gtk_separator_menu_item_new (); gtk_widget_show (menu_item); gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menu_item, index); return GTK_MENU_ITEM (menu_item); } void eel_gtk_message_dialog_set_details_label (GtkMessageDialog *dialog, const gchar *details_text) { GtkWidget *content_area, *expander, *label; content_area = gtk_message_dialog_get_message_area (dialog); expander = gtk_expander_new_with_mnemonic (_("Show more _details")); gtk_expander_set_spacing (GTK_EXPANDER (expander), 6); label = gtk_label_new (details_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_selectable (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (expander), label); gtk_box_pack_start (GTK_BOX (content_area), expander, FALSE, FALSE, 0); gtk_widget_show (label); gtk_widget_show (expander); } nemo-4.4.2/eel/eel-gtk-extensions.h000066400000000000000000000045251357442400300171320ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-gtk-extensions.h - interface for new functions that operate on gtk classes. Perhaps some of these should be rolled into gtk someday. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan Ramiro Estrugo */ #ifndef EEL_GTK_EXTENSIONS_H #define EEL_GTK_EXTENSIONS_H #include #include #include /* GtkWindow */ void eel_gtk_window_set_initial_geometry_from_string (GtkWindow *window, const char *geometry_string, guint minimum_width, guint minimum_height, gboolean ignore_position); char * eel_gtk_window_get_geometry_string (GtkWindow *window); /* GtkMenu and GtkMenuItem */ void eel_pop_up_context_menu (GtkMenu *menu, GdkEventButton *event); GtkMenuItem * eel_gtk_menu_append_separator (GtkMenu *menu); GtkMenuItem * eel_gtk_menu_insert_separator (GtkMenu *menu, int index); /* GtkMessageDialog */ void eel_gtk_message_dialog_set_details_label (GtkMessageDialog *dialog, const gchar *details_text); #endif /* EEL_GTK_EXTENSIONS_H */ nemo-4.4.2/eel/eel-lib-self-check-functions.c000066400000000000000000000023341357442400300207150ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-lib-self-check-functions.c: Wrapper for all self check functions in Eel proper. Copyright (C) 2000 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #if ! defined (EEL_OMIT_SELF_CHECK) #include "eel-lib-self-check-functions.h" void eel_run_lib_self_checks (void) { EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_CALL_SELF_CHECK_FUNCTION) } #endif /* ! EEL_OMIT_SELF_CHECK */ nemo-4.4.2/eel/eel-lib-self-check-functions.h000066400000000000000000000034231357442400300207220ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-lib-self-check-functions.h: Wrapper and prototypes for all self-check functions in libeel. Copyright (C) 2000 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include "eel-self-checks.h" void eel_run_lib_self_checks (void); /* Putting the prototypes for these self-check functions in each header file for the files they are defined in would make compiling the self-check framework take way too long (since one file would have to include everything). So we put the list of functions here instead. Instead of just putting prototypes here, we put this macro that can be used to do operations on the whole list of functions. */ #define EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ macro (eel_self_check_glib_extensions) \ macro (eel_self_check_string) \ /* Add new self-check functions to the list above this line. */ /* Generate prototypes for all the functions. */ EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_SELF_CHECK_FUNCTION_PROTOTYPE) nemo-4.4.2/eel/eel-self-checks.c000066400000000000000000000102071357442400300163240ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-self-checks.c: The self-check framework. Copyright (C) 1999 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #if ! defined (EEL_OMIT_SELF_CHECK) #include "eel-self-checks.h" #include #include #include static gboolean failed; static const char *current_expression; static const char *current_file_name; static int current_line_number; void eel_exit_if_self_checks_failed (void) { if (!failed) { return; } printf ("\n"); exit (EXIT_FAILURE); } void eel_report_check_failure (char *result, char *expected) { if (!failed) { fprintf (stderr, "\n"); } fprintf (stderr, "FAIL: check failed in %s, line %d\n", current_file_name, current_line_number); fprintf (stderr, " evaluated: %s\n", current_expression); fprintf (stderr, " expected: %s\n", expected == NULL ? "NULL" : expected); fprintf (stderr, " got: %s\n", result == NULL ? "NULL" : result); failed = TRUE; g_free (result); g_free (expected); } static char * eel_strdup_boolean (gboolean boolean) { if (boolean == FALSE) { return g_strdup ("FALSE"); } if (boolean == TRUE) { return g_strdup ("TRUE"); } return g_strdup_printf ("gboolean(%d)", boolean); } void eel_before_check (const char *expression, const char *file_name, int line_number) { current_expression = expression; current_file_name = file_name; current_line_number = line_number; } void eel_after_check (void) { /* It would be good to check here if there was a memory leak. */ } void eel_check_boolean_result (gboolean result, gboolean expected) { if (result != expected) { eel_report_check_failure (eel_strdup_boolean (result), eel_strdup_boolean (expected)); } eel_after_check (); } void eel_check_rectangle_result (EelIRect result, int expected_x0, int expected_y0, int expected_x1, int expected_y1) { if (result.x0 != expected_x0 || result.y0 != expected_y0 || result.x1 != expected_x1 || result.y1 != expected_y1) { eel_report_check_failure (g_strdup_printf ("x0=%d, y0=%d, x1=%d, y1=%d", result.x0, result.y0, result.x1, result.y1), g_strdup_printf ("x0=%d, y0=%d, x1=%d, y1=%d", expected_x0, expected_y0, expected_x1, expected_y1)); } eel_after_check (); } void eel_check_integer_result (long result, long expected) { if (result != expected) { eel_report_check_failure (g_strdup_printf ("%ld", result), g_strdup_printf ("%ld", expected)); } eel_after_check (); } void eel_check_double_result (double result, double expected) { if (result != expected) { eel_report_check_failure (g_strdup_printf ("%f", result), g_strdup_printf ("%f", expected)); } eel_after_check (); } void eel_check_string_result (char *result, const char *expected) { gboolean match; /* Stricter than eel_strcmp. * NULL does not match "" in this test. */ if (expected == NULL) { match = result == NULL; } else { match = result != NULL && strcmp (result, expected) == 0; } if (!match) { eel_report_check_failure (result, g_strdup (expected)); } else { g_free (result); } eel_after_check (); } void eel_before_check_function (const char *name) { fprintf (stderr, "running %s\n", name); } void eel_after_check_function (void) { } #endif /* ! EEL_OMIT_SELF_CHECK */ nemo-4.4.2/eel/eel-self-checks.h000066400000000000000000000064431357442400300163400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-self-checks.h: The self-check framework. Copyright (C) 1999 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef EEL_SELF_CHECKS_H #define EEL_SELF_CHECKS_H #include #include #define EEL_CHECK_RESULT(type, expression, expected_value) \ G_STMT_START { \ eel_before_check (#expression, __FILE__, __LINE__); \ eel_check_##type##_result (expression, expected_value); \ } G_STMT_END #define EEL_CHECK_BOOLEAN_RESULT(expression, expected_value) \ EEL_CHECK_RESULT(boolean, expression, expected_value) #define EEL_CHECK_INTEGER_RESULT(expression, expected_value) \ EEL_CHECK_RESULT(integer, expression, expected_value) #define EEL_CHECK_DOUBLE_RESULT(expression, expected_value) \ EEL_CHECK_RESULT(double, expression, expected_value) #define EEL_CHECK_STRING_RESULT(expression, expected_value) \ EEL_CHECK_RESULT(string, expression, expected_value) #define EEL_CHECK_RECTANGLE_RESULT(expression, expected_x0, expected_y0, expected_x1, expected_y1) \ G_STMT_START { \ eel_before_check (#expression, __FILE__, __LINE__); \ eel_check_rectangle_result (expression, expected_x0, expected_y0, expected_x1, expected_y1); \ } G_STMT_END void eel_exit_if_self_checks_failed (void); void eel_before_check_function (const char *name); void eel_after_check_function (void); void eel_before_check (const char *expression, const char *file_name, int line_number); void eel_after_check (void); /* Both 'result' and 'expected' get freed with g_free */ void eel_report_check_failure (char *result, char *expected); void eel_check_boolean_result (gboolean result, gboolean expected_value); void eel_check_integer_result (long result, long expected_value); void eel_check_double_result (double result, double expected_value); void eel_check_rectangle_result (EelIRect result, int expected_x0, int expected_y0, int expected_x1, int expected_y1); void eel_check_string_result (char *result, const char *expected_value); #define EEL_SELF_CHECK_FUNCTION_PROTOTYPE(function) \ void function (void); #define EEL_CALL_SELF_CHECK_FUNCTION(function) \ eel_before_check_function (#function); \ function (); \ eel_after_check_function (); #endif /* EEL_SELF_CHECKS_H */ nemo-4.4.2/eel/eel-stock-dialogs.c000066400000000000000000000367661357442400300167220ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-stock-dialogs.c: Various standard dialogs for Eel. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #include #include "eel-stock-dialogs.h" #include "eel-glib-extensions.h" #include "eel-gtk-extensions.h" #include #include #define TIMED_WAIT_STANDARD_DURATION 2000 #define TIMED_WAIT_MIN_TIME_UP 3000 #define TIMED_WAIT_MINIMUM_DIALOG_WIDTH 300 #define RESPONSE_DETAILS 1000 typedef struct { EelCancelCallback cancel_callback; gpointer callback_data; /* Parameters for creation of the window. */ char *wait_message; GtkWindow *parent_window; /* Timer to determine when we need to create the window. */ guint timeout_handler_id; /* Window, once it's created. */ GtkDialog *dialog; /* system time (microseconds) when dialog was created */ gint64 dialog_creation_time; } TimedWait; static GHashTable *timed_wait_hash_table; static void timed_wait_dialog_destroy_callback (GtkWidget *object, gpointer callback_data); static guint timed_wait_hash (gconstpointer value) { const TimedWait *wait; wait = value; return GPOINTER_TO_UINT (wait->cancel_callback) ^ GPOINTER_TO_UINT (wait->callback_data); } static gboolean timed_wait_hash_equal (gconstpointer value1, gconstpointer value2) { const TimedWait *wait1, *wait2; wait1 = value1; wait2 = value2; return wait1->cancel_callback == wait2->cancel_callback && wait1->callback_data == wait2->callback_data; } static void timed_wait_delayed_close_destroy_dialog_callback (GtkWidget *object, gpointer callback_data) { g_source_remove (GPOINTER_TO_UINT (callback_data)); } static gboolean timed_wait_delayed_close_timeout_callback (gpointer callback_data) { guint handler_id; handler_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (callback_data), "eel-stock-dialogs/delayed_close_handler_timeout_id")); g_signal_handlers_disconnect_by_func (G_OBJECT (callback_data), G_CALLBACK (timed_wait_delayed_close_destroy_dialog_callback), GUINT_TO_POINTER (handler_id)); gtk_widget_destroy (GTK_WIDGET (callback_data)); return FALSE; } static void timed_wait_free (TimedWait *wait) { guint delayed_close_handler_id; guint64 time_up; g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) != NULL); g_hash_table_remove (timed_wait_hash_table, wait); g_free (wait->wait_message); if (wait->parent_window != NULL) { g_object_unref (wait->parent_window); } if (wait->timeout_handler_id != 0) { g_source_remove (wait->timeout_handler_id); } if (wait->dialog != NULL) { /* Make sure to detach from the "destroy" signal, or we'll * double-free. */ g_signal_handlers_disconnect_by_func (G_OBJECT (wait->dialog), G_CALLBACK (timed_wait_dialog_destroy_callback), wait); /* compute time up in milliseconds */ time_up = (g_get_monotonic_time () - wait->dialog_creation_time) / 1000; if (time_up < TIMED_WAIT_MIN_TIME_UP) { delayed_close_handler_id = g_timeout_add (TIMED_WAIT_MIN_TIME_UP - time_up, timed_wait_delayed_close_timeout_callback, wait->dialog); g_object_set_data (G_OBJECT (wait->dialog), "eel-stock-dialogs/delayed_close_handler_timeout_id", GUINT_TO_POINTER (delayed_close_handler_id)); g_signal_connect (wait->dialog, "destroy", G_CALLBACK (timed_wait_delayed_close_destroy_dialog_callback), GUINT_TO_POINTER (delayed_close_handler_id)); } else { gtk_widget_destroy (GTK_WIDGET (wait->dialog)); } } /* And the wait object itself. */ g_free (wait); } static void timed_wait_dialog_destroy_callback (GtkWidget *object, gpointer callback_data) { TimedWait *wait; wait = callback_data; g_assert (GTK_DIALOG (object) == wait->dialog); wait->dialog = NULL; /* When there's no cancel_callback, the originator will/must * call eel_timed_wait_stop which will call timed_wait_free. */ if (wait->cancel_callback != NULL) { (* wait->cancel_callback) (wait->callback_data); timed_wait_free (wait); } } static void trash_dialog_response_callback (GtkDialog *dialog, int response_id, TimedWait *wait) { gtk_widget_destroy (GTK_WIDGET (dialog)); } static gboolean timed_wait_callback (gpointer callback_data) { TimedWait *wait; GtkDialog *dialog; const char *button; wait = callback_data; /* Put up the timed wait window. */ button = wait->cancel_callback != NULL ? GTK_STOCK_CANCEL : GTK_STOCK_OK; dialog = GTK_DIALOG (gtk_message_dialog_new (wait->parent_window, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, NULL)); g_object_set (dialog, "text", wait->wait_message, "secondary-text", _("You can stop this operation by clicking cancel."), NULL); gtk_dialog_add_button (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); /* The contents are often very small, causing tiny little * dialogs with their titles clipped if you just let gtk * sizing do its thing. This enforces a minimum width to * make it more likely that the title won't be clipped. */ gtk_window_set_default_size (GTK_WINDOW (dialog), TIMED_WAIT_MINIMUM_DIALOG_WIDTH, -1); wait->dialog_creation_time = g_get_monotonic_time (); gtk_widget_show (GTK_WIDGET (dialog)); /* FIXME bugzilla.eazel.com 2441: * Could parent here, but it's complicated because we * don't want this window to go away just because the parent * would go away first. */ /* Make the dialog cancel the timed wait when it goes away. * Connect to "destroy" instead of "response" since we want * to be called no matter how the dialog goes away. */ g_signal_connect (dialog, "destroy", G_CALLBACK (timed_wait_dialog_destroy_callback), wait); g_signal_connect (dialog, "response", G_CALLBACK (trash_dialog_response_callback), wait); wait->timeout_handler_id = 0; wait->dialog = dialog; return FALSE; } void eel_timed_wait_start_with_duration (int duration, EelCancelCallback cancel_callback, gpointer callback_data, const char *wait_message, GtkWindow *parent_window) { TimedWait *wait; g_return_if_fail (callback_data != NULL); g_return_if_fail (wait_message != NULL); g_return_if_fail (parent_window == NULL || GTK_IS_WINDOW (parent_window)); /* Create the timed wait record. */ wait = g_new0 (TimedWait, 1); wait->wait_message = g_strdup (wait_message); wait->cancel_callback = cancel_callback; wait->callback_data = callback_data; wait->parent_window = parent_window; if (parent_window != NULL) { g_object_ref (parent_window); } /* Start the timer. */ wait->timeout_handler_id = g_timeout_add (duration, timed_wait_callback, wait); /* Put in the hash table so we can find it later. */ if (timed_wait_hash_table == NULL) { timed_wait_hash_table = g_hash_table_new (timed_wait_hash, timed_wait_hash_equal); } g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) == NULL); g_hash_table_insert (timed_wait_hash_table, wait, wait); g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) == wait); } void eel_timed_wait_start (EelCancelCallback cancel_callback, gpointer callback_data, const char *wait_message, GtkWindow *parent_window) { eel_timed_wait_start_with_duration (TIMED_WAIT_STANDARD_DURATION, cancel_callback, callback_data, wait_message, parent_window); } void eel_timed_wait_stop (EelCancelCallback cancel_callback, gpointer callback_data) { TimedWait key; TimedWait *wait; g_return_if_fail (callback_data != NULL); key.cancel_callback = cancel_callback; key.callback_data = callback_data; wait = g_hash_table_lookup (timed_wait_hash_table, &key); g_return_if_fail (wait != NULL); timed_wait_free (wait); } int eel_run_simple_dialog (GtkWidget *parent, gboolean ignore_close_box, GtkMessageType message_type, const char *primary_text, const char *secondary_text, ...) { va_list button_title_args; const char *button_title; GtkWidget *dialog; GtkWidget *top_widget, *chosen_parent; int result; int response_id; /* Parent it if asked to. */ chosen_parent = NULL; if (parent != NULL) { top_widget = gtk_widget_get_toplevel (parent); if (GTK_IS_WINDOW (top_widget)) { chosen_parent = top_widget; } } /* Create the dialog. */ dialog = gtk_message_dialog_new (GTK_WINDOW (chosen_parent), 0, message_type, GTK_BUTTONS_NONE, NULL); g_object_set (dialog, "text", primary_text, "secondary-text", secondary_text, NULL); va_start (button_title_args, secondary_text); response_id = 0; while (1) { button_title = va_arg (button_title_args, const char *); if (button_title == NULL) { break; } gtk_dialog_add_button (GTK_DIALOG (dialog), button_title, response_id); gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id); response_id++; } va_end (button_title_args); /* Run it. */ gtk_widget_show (dialog); result = gtk_dialog_run (GTK_DIALOG (dialog)); while ((result == GTK_RESPONSE_NONE || result == GTK_RESPONSE_DELETE_EVENT) && ignore_close_box) { gtk_widget_show (GTK_WIDGET (dialog)); result = gtk_dialog_run (GTK_DIALOG (dialog)); } gtk_widget_destroy (dialog); return result; } static GtkDialog * create_message_dialog (const char *primary_text, const char *secondary_text, GtkMessageType type, GtkButtonsType buttons_type, GtkWindow *parent) { GtkWidget *dialog; dialog = gtk_message_dialog_new (parent, 0, type, buttons_type, NULL); g_object_set (dialog, "text", primary_text, "secondary-text", secondary_text, NULL); return GTK_DIALOG (dialog); } static GtkDialog * show_message_dialog (const char *primary_text, const char *secondary_text, GtkMessageType type, GtkButtonsType buttons_type, const char *details_text, GtkWindow *parent) { GtkDialog *dialog; dialog = create_message_dialog (primary_text, secondary_text, type, buttons_type, parent); if (details_text != NULL) { eel_gtk_message_dialog_set_details_label (GTK_MESSAGE_DIALOG (dialog), details_text); } gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); return dialog; } static GtkDialog * show_ok_dialog (const char *primary_text, const char *secondary_text, GtkMessageType type, GtkWindow *parent) { GtkDialog *dialog; dialog = show_message_dialog (primary_text, secondary_text, type, GTK_BUTTONS_OK, NULL, parent); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); return dialog; } GtkDialog * eel_create_info_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent) { return create_message_dialog (primary_text, secondary_text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, parent); } GtkDialog * eel_show_info_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent) { return show_ok_dialog (primary_text, secondary_text, GTK_MESSAGE_INFO, parent); } GtkDialog * eel_show_info_dialog_with_details (const char *primary_text, const char *secondary_text, const char *detailed_info, GtkWindow *parent) { GtkDialog *dialog; if (detailed_info == NULL || strcmp (primary_text, detailed_info) == 0) { return eel_show_info_dialog (primary_text, secondary_text, parent); } dialog = show_message_dialog (primary_text, secondary_text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, detailed_info, parent); return dialog; } GtkDialog * eel_show_warning_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent) { return show_ok_dialog (primary_text, secondary_text, GTK_MESSAGE_WARNING, parent); } GtkDialog * eel_show_error_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent) { return show_ok_dialog (primary_text, secondary_text, GTK_MESSAGE_ERROR, parent); } GtkDialog * eel_show_error_dialog_with_details (const char *primary_text, const char *secondary_text, const char *detailed_error_message, GtkWindow *parent) { GtkDialog *dialog; g_return_val_if_fail (primary_text != NULL, NULL); g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); if (detailed_error_message == NULL || strcmp (primary_text, detailed_error_message) == 0) { return eel_show_error_dialog (primary_text, secondary_text, parent); } dialog = show_message_dialog (primary_text, secondary_text, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, detailed_error_message, parent); return dialog; } /** * eel_show_yes_no_dialog: * * Create and show a dialog asking a question with two choices. * The caller needs to set up any necessary callbacks * for the buttons. Use eel_create_question_dialog instead * if any visual changes need to be made, to avoid flashiness. * @question: The text of the question. * @yes_label: The label of the "yes" button. * @no_label: The label of the "no" button. * @parent: The parent window for this dialog. */ GtkDialog * eel_show_yes_no_dialog (const char *primary_text, const char *secondary_text, const char *yes_label, const char *no_label, GtkWindow *parent) { GtkDialog *dialog = NULL; dialog = eel_create_question_dialog (primary_text, secondary_text, no_label, GTK_RESPONSE_CANCEL, yes_label, GTK_RESPONSE_YES, GTK_WINDOW (parent)); gtk_widget_show (GTK_WIDGET (dialog)); return dialog; } /** * eel_create_question_dialog: * * Create a dialog asking a question with at least two choices. * The caller needs to set up any necessary callbacks * for the buttons. The dialog is not yet shown, so that the * caller can add additional buttons or make other visual changes * without causing flashiness. * @question: The text of the question. * @answer_0: The label of the leftmost button (index 0) * @answer_1: The label of the 2nd-to-leftmost button (index 1) * @parent: The parent window for this dialog. */ GtkDialog * eel_create_question_dialog (const char *primary_text, const char *secondary_text, const char *answer_1, int response_1, const char *answer_2, int response_2, GtkWindow *parent) { GtkDialog *dialog; dialog = create_message_dialog (primary_text, secondary_text, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, parent); gtk_dialog_add_buttons (dialog, answer_1, response_1, answer_2, response_2, NULL); return dialog; } nemo-4.4.2/eel/eel-stock-dialogs.h000066400000000000000000000100621357442400300167040ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-stock-dialogs.h: Various standard dialogs for Eel. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #ifndef EEL_STOCK_DIALOGS_H #define EEL_STOCK_DIALOGS_H #include typedef void (* EelCancelCallback) (gpointer callback_data); /* Dialog for cancelling something that normally is fast enough not to need a dialog. */ void eel_timed_wait_start (EelCancelCallback cancel_callback, gpointer callback_data, const char *wait_message, GtkWindow *parent_window); void eel_timed_wait_start_with_duration (int duration, EelCancelCallback cancel_callback, gpointer callback_data, const char *wait_message, GtkWindow *parent_window); void eel_timed_wait_stop (EelCancelCallback cancel_callback, gpointer callback_data); /* Basic dialog with buttons. */ int eel_run_simple_dialog (GtkWidget *parent, gboolean ignore_close_box, GtkMessageType message_type, const char *primary_text, const char *secondary_text, ...); /* Variations on gnome stock dialogs; these do line wrapping, we don't * bother with non-parented versions, we allow setting the title, * primary, and secondary messages, and we return GtkDialog pointers * instead of GtkWidget pointers. */ GtkDialog *eel_show_info_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent); GtkDialog *eel_show_info_dialog_with_details (const char *primary_text, const char *secondary_text, const char *detailed_informative_message, GtkWindow *parent); GtkDialog *eel_show_warning_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent); GtkDialog *eel_show_error_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent); GtkDialog *eel_show_error_dialog_with_details (const char *primary_text, const char *secondary_text, const char *detailed_error_message, GtkWindow *parent); GtkDialog *eel_show_yes_no_dialog (const char *primary_text, const char *secondary_text, const char *yes_label, const char *no_label, GtkWindow *parent); GtkDialog *eel_create_question_dialog (const char *primary_text, const char *secondary_text, const char *answer_one, int response_one, const char *answer_two, int response_two, GtkWindow *parent); GtkDialog *eel_create_info_dialog (const char *primary_text, const char *secondary_text, GtkWindow *parent); #endif /* EEL_STOCK_DIALOGS_H */ nemo-4.4.2/eel/eel-string.c000066400000000000000000000533621357442400300154540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-string.c: String routines to augment . Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #include #include "eel-string.h" #include #include #include #include #include #if !defined (EEL_OMIT_SELF_CHECK) #include "eel-lib-self-check-functions.h" #endif char * eel_str_double_underscores (const char *string) { int underscores; const char *p; char *q; char *escaped; if (string == NULL) { return NULL; } underscores = 0; for (p = string; *p != '\0'; p++) { underscores += (*p == '_'); } if (underscores == 0) { return g_strdup (string); } escaped = g_new (char, strlen (string) + underscores + 1); for (p = string, q = escaped; *p != '\0'; p++, q++) { /* Add an extra underscore. */ if (*p == '_') { *q++ = '_'; } *q = *p; } *q = '\0'; return escaped; } char * eel_str_escape_spaces (const char *string) { int spaces; const char *p; char *q; char *escaped; if (string == NULL) { return NULL; } spaces = 0; for (p = string; *p != '\0'; p++) { spaces += (*p == ' '); } if (spaces == 0) { return g_strdup (string); } escaped = g_new (char, strlen (string) + spaces + 1); for (p = string, q = escaped; *p != '\0'; p++, q++) { /* Add an extra underscore. */ if (*p == ' ') { *q++ = '\\'; } *q = *p; } *q = '\0'; return escaped; } char * eel_str_escape_quotes (const char *string) { int quotes; const char *p; char *q; char *escaped; if (string == NULL) { return NULL; } quotes = 0; for (p = string; *p != '\0'; p++) { quotes += (*p == '\'') || (*p == '\"'); } if (quotes == 0) { return g_strdup (string); } escaped = g_new (char, strlen (string) + quotes + 1); for (p = string, q = escaped; *p != '\0'; p++, q++) { if ((*p == '\'') || (*p == '\"')) { *q++ = '\\'; } *q = *p; } *q = '\0'; return escaped; } char * eel_str_capitalize (const char *string) { char *capitalized; if (string == NULL) { return NULL; } capitalized = g_strdup (string); capitalized[0] = g_ascii_toupper (capitalized[0]); return capitalized; } /* Note: eel_string_ellipsize_* that use a length in pixels * rather than characters can be found in eel_gdk_extensions.h * * FIXME bugzilla.eazel.com 5089: * we should coordinate the names of eel_string_ellipsize_* * and eel_str_*_truncate so that they match better and reflect * their different behavior. */ char * eel_str_middle_truncate (const char *string, guint truncate_length) { char *truncated; guint length; guint num_left_chars; guint num_right_chars; if (string == NULL) { return NULL; } const char delimter[] = "..."; const guint delimter_length = strlen (delimter); const guint min_truncate_length = delimter_length + 2; /* It doesnt make sense to truncate strings to less than * the size of the delimiter plus 2 characters (one on each * side) */ if (truncate_length < min_truncate_length) { return g_strdup (string); } length = g_utf8_strlen (string, -1); /* Make sure the string is not already small enough. */ if (length <= truncate_length) { return g_strdup (string); } /* Find the 'middle' where the truncation will occur. */ num_left_chars = (truncate_length - delimter_length) / 2; num_right_chars = truncate_length - num_left_chars - delimter_length; truncated = g_new (char, strlen (string) + 1); g_utf8_strncpy (truncated, string, num_left_chars); strcat (truncated, delimter); strcat (truncated, g_utf8_offset_to_pointer (string, length - num_right_chars)); return truncated; } char * eel_str_strip_substring_and_after (const char *string, const char *substring) { const char *substring_position; g_return_val_if_fail (substring != NULL, g_strdup (string)); g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); if (string == NULL) { return NULL; } substring_position = strstr (string, substring); if (substring_position == NULL) { return g_strdup (string); } return g_strndup (string, substring_position - string); } char * eel_str_replace_substring (const char *string, const char *substring, const char *replacement) { int substring_length, replacement_length, result_length, remaining_length; const char *p, *substring_position; char *result, *result_position; g_return_val_if_fail (substring != NULL, g_strdup (string)); g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); if (string == NULL) { return NULL; } substring_length = substring ? strlen (substring) : 0; replacement_length = replacement ? strlen (replacement) : 0; result_length = strlen (string); for (p = string; ; p = substring_position + substring_length) { substring_position = strstr (p, substring); if (substring_position == NULL) { break; } result_length += replacement_length - substring_length; } result = g_malloc (result_length + 1); result_position = result; for (p = string; ; p = substring_position + substring_length) { substring_position = strstr (p, substring); if (substring_position == NULL) { remaining_length = strlen (p); memcpy (result_position, p, remaining_length); result_position += remaining_length; break; } memcpy (result_position, p, substring_position - p); result_position += substring_position - p; memcpy (result_position, replacement, replacement_length); result_position += replacement_length; } g_assert (result_position - result == result_length); result_position[0] = '\0'; return result; } /**************** Custom printf ***********/ typedef struct { const char *start; const char *end; GString *format; int arg_pos; int width_pos; int width_format_index; int precision_pos; int precision_format_index; } ConversionInfo; enum { ARG_TYPE_INVALID, ARG_TYPE_INT, ARG_TYPE_LONG, ARG_TYPE_LONG_LONG, ARG_TYPE_SIZE, ARG_TYPE_LONG_DOUBLE, ARG_TYPE_DOUBLE, ARG_TYPE_POINTER }; typedef int ArgType; /* An int, because custom are < 0 */ static const char * get_position (const char *format, int *i) { const char *p; p = format; if (g_ascii_isdigit (*p)) { p++; while (g_ascii_isdigit (*p)) { p++; } if (*p == '$') { if (i != NULL) { *i = atoi (format) - 1; } return p + 1; } } return format; } static gboolean is_flag (char c) { return strchr ("#0- +'I", c) != NULL; } static gboolean is_length_modifier (char c) { return strchr ("hlLjzt", c) != NULL; } static ArgType get_arg_type_from_format (EelPrintfHandler *custom_handlers, const char *format, int len) { int i; char c; c = format[len-1]; if (custom_handlers != NULL) { for (i = 0; custom_handlers[i].character != 0; i++) { if (custom_handlers[i].character == c) { return -(i + 1); } } } switch (c) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': if (g_str_has_prefix (format, "ll")) { return ARG_TYPE_LONG_LONG; } if (g_str_has_prefix (format, "l")) { return ARG_TYPE_LONG; } if (g_str_has_prefix (format, "l")) { return ARG_TYPE_LONG; } if (g_str_has_prefix (format, "z")) { return ARG_TYPE_SIZE; } return ARG_TYPE_INT; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': if (g_str_has_prefix (format, "L")) { return ARG_TYPE_LONG_DOUBLE; } return ARG_TYPE_DOUBLE; case 'c': return ARG_TYPE_INT; case 's': case 'p': case 'n': return ARG_TYPE_POINTER; default: break; } return ARG_TYPE_INVALID; } static void skip_argv (va_list *va, ArgType type, EelPrintfHandler *custom_handlers) { if (type < 0) { custom_handlers[-type - 1].skip (va); return; } switch (type) { default: case ARG_TYPE_INVALID: return; case ARG_TYPE_INT: (void) va_arg (*va, int); break; case ARG_TYPE_LONG: (void) va_arg (*va, long int); break; case ARG_TYPE_LONG_LONG: (void) va_arg (*va, long long int); break; case ARG_TYPE_SIZE: (void) va_arg (*va, gsize); break; case ARG_TYPE_LONG_DOUBLE: (void) va_arg (*va, long double); break; case ARG_TYPE_DOUBLE: (void) va_arg (*va, double); break; case ARG_TYPE_POINTER: (void) va_arg (*va, void *); break; } } static void skip_to_arg (va_list *va, ArgType *types, EelPrintfHandler *custom_handlers, int n) { int i; for (i = 0; i < n; i++) { skip_argv (va, types[i], custom_handlers); } } char * eel_strdup_vprintf_with_custom (EelPrintfHandler *custom, const char *format, va_list va_orig) { va_list va; const char *p; int num_args, i, j; ArgType *args; ArgType type; ConversionInfo *conversions; GString *f, *str; const char *flags, *width, *prec, *mod, *pos; char *s; num_args = 0; for (p = format; *p != 0; p++) { if (*p == '%') { p++; if (*p != '%') { num_args++; } } } args = g_new0 (ArgType, num_args * 3 + 1); conversions = g_new0 (ConversionInfo, num_args); /* i indexes conversions, j indexes args */ i = 0; j = 0; p = format; while (*p != 0) { if (*p != '%') { p++; continue; } p++; if (*p == '%') { p++; continue; } /* We got a real conversion: */ f = g_string_new ("%"); conversions[i].start = p - 1; /* First comes the positional arg */ pos = p; p = get_position (p, NULL); /* Then flags */ flags = p; while (is_flag (*p)) { p++; } g_string_append_len (f, flags, p - flags); /* Field width */ if (*p == '*') { p++; p = get_position (p, &j); args[j] = ARG_TYPE_INT; conversions[i].width_pos = j++; conversions[i].width_format_index = f->len; } else { conversions[i].width_pos = -1; conversions[i].width_format_index = -1; width = p; while (g_ascii_isdigit (*p)) { p++; } g_string_append_len (f, width, p - width); } /* Precision */ conversions[i].precision_pos = -1; conversions[i].precision_format_index = -1; if (*p == '.') { g_string_append_c (f, '.'); p++; if (*p == '*') { p++; p = get_position (p, &j); args[j] = ARG_TYPE_INT; conversions[i].precision_pos = j++; conversions[i].precision_format_index = f->len; } else { prec = p; while (g_ascii_isdigit (*p) || *p == '-') { p++; } g_string_append_len (f, prec, p - prec); } } /* length modifier */ mod = p; while (is_length_modifier (*p)) { p++; } /* conversion specifier */ if (*p != 0) p++; g_string_append_len (f, mod, p - mod); get_position (pos, &j); args[j] = get_arg_type_from_format (custom, mod, p - mod); conversions[i].arg_pos = j++; conversions[i].format = f; conversions[i].end = p; i++; } g_assert (i == num_args); str = g_string_new (""); p = format; for (i = 0; i < num_args; i++) { g_string_append_len (str, p, conversions[i].start - p); p = conversions[i].end; if (conversions[i].precision_pos != -1) { char *val; G_VA_COPY(va, va_orig); skip_to_arg (&va, args, custom, conversions[i].precision_pos); val = g_strdup_vprintf ("%d", va); va_end (va); g_string_insert (conversions[i].format, conversions[i].precision_format_index, val); g_free (val); } if (conversions[i].width_pos != -1) { char *val; G_VA_COPY(va, va_orig); skip_to_arg (&va, args, custom, conversions[i].width_pos); val = g_strdup_vprintf ("%d", va); va_end (va); g_string_insert (conversions[i].format, conversions[i].width_format_index, val); g_free (val); } G_VA_COPY(va, va_orig); skip_to_arg (&va, args, custom, conversions[i].arg_pos); type = args[conversions[i].arg_pos]; if (type < 0) { s = custom[-type - 1].to_string (conversions[i].format->str, va); g_string_append (str, s); g_free (s); } else{ g_string_append_vprintf (str, conversions[i].format->str, va); } va_end (va); g_string_free (conversions[i].format, TRUE); } g_string_append (str, p); g_free (args); g_free (conversions); return g_string_free (str, FALSE); } char * eel_strdup_printf_with_custom (EelPrintfHandler *handlers, const char *format, ...) { va_list va; char *res; va_start (va, format); res = eel_strdup_vprintf_with_custom (handlers, format, va); va_end (va); return res; } /*********** refcounted strings ****************/ G_LOCK_DEFINE_STATIC (unique_ref_strs); static GHashTable *unique_ref_strs = NULL; static eel_ref_str eel_ref_str_new_internal (const char *string, int start_count) { char *res; volatile gint *count; gsize len; len = strlen (string); res = g_malloc (sizeof (gint) + len + 1); count = (volatile gint *)res; *count = start_count; res += sizeof(gint); memcpy (res, string, len + 1); return res; } eel_ref_str eel_ref_str_new (const char *string) { if (string == NULL) { return NULL; } return eel_ref_str_new_internal (string, 1); } eel_ref_str eel_ref_str_get_unique (const char *string) { eel_ref_str res; if (string == NULL) { return NULL; } G_LOCK (unique_ref_strs); if (unique_ref_strs == NULL) { unique_ref_strs = g_hash_table_new (g_str_hash, g_str_equal); } res = g_hash_table_lookup (unique_ref_strs, string); if (res != NULL) { eel_ref_str_ref (res); } else { res = eel_ref_str_new_internal (string, 0x80000001); g_hash_table_insert (unique_ref_strs, res, res); } G_UNLOCK (unique_ref_strs); return res; } eel_ref_str eel_ref_str_ref (eel_ref_str str) { volatile gint *count; count = (volatile gint *)((char *)str - sizeof (gint)); g_atomic_int_add (count, 1); return str; } void eel_ref_str_unref (eel_ref_str str) { volatile gint *count; gint old_ref; if (str == NULL) return; count = (volatile gint *)((char *)str - sizeof (gint)); retry_atomic_decrement: old_ref = g_atomic_int_get (count); if (old_ref == 1) { g_free ((char *)count); } else if (old_ref == 0x80000001) { G_LOCK (unique_ref_strs); /* Need to recheck after taking lock to avoid races with _get_unique() */ if (g_atomic_int_add (count, -1) == 0x80000001) { g_hash_table_remove (unique_ref_strs, (char *)str); g_free ((char *)count); } G_UNLOCK (unique_ref_strs); } else if (!g_atomic_int_compare_and_exchange (count, old_ref, old_ref - 1)) { goto retry_atomic_decrement; } } GList * eel_strv_to_glist (gchar **strv) { GList *list; gint i; if (strv == NULL) { return NULL; } list = NULL; i = 0; while (strv[i] != NULL) { list = g_list_prepend (list, g_strdup (strv[i])); i++; } list = g_list_reverse (list); return list; } #if !defined (EEL_OMIT_SELF_CHECK) static void verify_printf (const char *format, ...) { va_list va; char *orig, *new; va_start (va, format); orig = g_strdup_vprintf (format, va); va_end (va); va_start (va, format); new = eel_strdup_vprintf_with_custom (NULL, format, va); va_end (va); EEL_CHECK_STRING_RESULT (new, orig); g_free (orig); } static char * custom1_to_string (char *format, va_list va) { int i; i = va_arg (va, int); return g_strdup_printf ("c1-%d-", i); } static void custom1_skip (va_list *va) { (void) va_arg (*va, int); } static char * custom2_to_string (char *format, va_list va) { char *s; s = va_arg (va, char *); return g_strdup_printf ("c2-%s-", s); } static void custom2_skip (va_list *va) { (void) va_arg (*va, char *); } static EelPrintfHandler handlers[] = { { 'N', custom1_to_string, custom1_skip }, { 'Y', custom2_to_string, custom2_skip }, { 0 } }; static void verify_custom (const char *orig, const char *format, ...) { char *new; va_list va; va_start (va, format); new = eel_strdup_vprintf_with_custom (handlers, format, va); va_end (va); EEL_CHECK_STRING_RESULT (new, orig); } void eel_self_check_string (void) { EEL_CHECK_STRING_RESULT (eel_str_double_underscores (NULL), NULL); EEL_CHECK_STRING_RESULT (eel_str_double_underscores (""), ""); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_"), "__"); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo"), "foo"); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar"), "foo__bar"); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar_2"), "foo__bar__2"); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_foo"), "__foo"); EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_"), "foo__"); EEL_CHECK_STRING_RESULT (eel_str_capitalize (NULL), NULL); EEL_CHECK_STRING_RESULT (eel_str_capitalize (""), ""); EEL_CHECK_STRING_RESULT (eel_str_capitalize ("foo"), "Foo"); EEL_CHECK_STRING_RESULT (eel_str_capitalize ("Foo"), "Foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 0), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 1), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 3), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 4), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 5), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 6), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 7), "foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 0), "a_much_longer_foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 1), "a_much_longer_foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 2), "a_much_longer_foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 3), "a_much_longer_foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 4), "a_much_longer_foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 5), "a...o"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 6), "a...oo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 7), "a_...oo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 8), "a_...foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 9), "a_m...foo"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 8), "so...ven"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 8), "so...odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 9), "som...ven"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 9), "som...odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 10), "som...even"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 10), "som..._odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 11), "some...even"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 11), "some..._odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 12), "some..._even"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 12), "some...g_odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 13), "somet..._even"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 14), "something_even"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("ääääääääää", 5), "ä...ä"); EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("ã‚ãƒã„ã…ã†ã‡ãˆã‰", 7), "ã‚ãƒ...ãˆã‰"); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after (NULL, "bar"), NULL); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("", "bar"), ""); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo", "bar"), "foo"); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar", "bar"), "foo "); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar xxx", "bar"), "foo "); EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("bar", "bar"), ""); EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", NULL), NULL); EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", "bar"), NULL); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", NULL), "bar"); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", ""), ""); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", "bar"), ""); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", ""), "bar"); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("xxx", "x", "foo"), "foofoofoo"); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("fff", "f", "foo"), "foofoofoo"); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "foo", "f"), "fff"); EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "f", ""), "oooooo"); verify_printf ("%.*s", 2, "foo"); verify_printf ("%*.*s", 2, 4, "foo"); verify_printf ("before %5$*1$.*2$s between %6$*3$.*4$d after", 4, 5, 6, 7, "foo", G_PI); verify_custom ("c1-42- c2-foo-","%N %Y", 42 ,"foo"); verify_custom ("c1-42- bar c2-foo-","%N %s %Y", 42, "bar" ,"foo"); verify_custom ("c1-42- bar c2-foo-","%3$N %2$s %1$Y","foo", "bar", 42); } #endif /* !EEL_OMIT_SELF_CHECK */ nemo-4.4.2/eel/eel-string.h000066400000000000000000000061311357442400300154510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- eel-string.h: String routines to augment . Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #ifndef EEL_STRING_H #define EEL_STRING_H #include #include #include /* We use the "str" abbrevation to mean char * string, since * "string" usually means g_string instead. We use the "istr" * abbreviation to mean a case-insensitive char *. */ #define THOU_TO_STR(c) g_strdup_printf ("%'d", c); /* NULL is allowed for all the str parameters to these functions. */ /* Escape function for '_' character. */ char * eel_str_double_underscores (const char *str); /* Escape function for spaces */ char * eel_str_escape_spaces (const char *str); /* Escape function for quotes */ char * eel_str_escape_quotes (const char *str); /* Capitalize a string */ char * eel_str_capitalize (const char *str); /* Middle truncate a string to a maximum of truncate_length characters. * The resulting string will be truncated in the middle with a "..." * delimiter. */ char * eel_str_middle_truncate (const char *str, guint truncate_length); /* Remove all characters after the passed-in substring. */ char * eel_str_strip_substring_and_after (const char *str, const char *substring); /* Replace all occurrences of substring with replacement. */ char * eel_str_replace_substring (const char *str, const char *substring, const char *replacement); typedef char * eel_ref_str; eel_ref_str eel_ref_str_new (const char *string); eel_ref_str eel_ref_str_get_unique (const char *string); eel_ref_str eel_ref_str_ref (eel_ref_str str); void eel_ref_str_unref (eel_ref_str str); #define eel_ref_str_peek(__str) ((const char *)(__str)) GList *eel_strv_to_glist (gchar **strv); typedef struct { char character; char *(*to_string) (char *format, va_list va); void (*skip) (va_list *va); } EelPrintfHandler; char *eel_strdup_printf_with_custom (EelPrintfHandler *handlers, const char *format, ...); char *eel_strdup_vprintf_with_custom (EelPrintfHandler *custom, const char *format, va_list va); #endif /* EEL_STRING_H */ nemo-4.4.2/eel/eel-vfs-extensions.c000066400000000000000000000104741357442400300171360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-vfs-extensions.c - gnome-vfs extensions. Its likely some of these will be part of gnome-vfs in the future. Copyright (C) 1999, 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler Pavel Cisler Mike Fleming John Sullivan */ #include #include "eel-vfs-extensions.h" #include "eel-glib-extensions.h" #include "eel-lib-self-check-functions.h" #include #include #include #include "eel-string.h" #include #include gboolean eel_uri_is_trash (const char *uri) { return g_str_has_prefix (uri, "trash:"); } gboolean eel_uri_is_recent (const char *uri) { return g_str_has_prefix (uri, "recent:"); } gboolean eel_uri_is_search (const char *uri) { return g_str_has_prefix (uri, EEL_SEARCH_URI); } gboolean eel_uri_is_desktop (const char *uri) { return g_str_has_prefix (uri, EEL_DESKTOP_URI); } gboolean eel_uri_is_network (const char *uri) { return g_str_has_prefix (uri, "smb:") || g_str_has_prefix (uri, "network:"); } char * eel_make_valid_utf8 (const char *name) { GString *string; const char *remainder, *invalid; int remaining_bytes, valid_bytes; string = NULL; remainder = name; remaining_bytes = strlen (name); while (remaining_bytes != 0) { if (g_utf8_validate (remainder, remaining_bytes, &invalid)) { break; } valid_bytes = invalid - remainder; if (string == NULL) { string = g_string_sized_new (remaining_bytes); } g_string_append_len (string, remainder, valid_bytes); g_string_append_c (string, '?'); remaining_bytes -= valid_bytes + 1; remainder = invalid + 1; } if (string == NULL) { return g_strdup (name); } g_string_append (string, remainder); g_string_append (string, _(" (invalid Unicode)")); g_assert (g_utf8_validate (string->str, -1, NULL)); return g_string_free (string, FALSE); } char * eel_filename_get_extension_offset (const char *filename) { char *end, *end2; const char *start; if (filename == NULL || filename[0] == '\0') { return NULL; } /* basename must have at least one char */ start = filename + 1; end = strrchr (start, '.'); if (end == NULL || end[1] == '\0') { return NULL; } if (end != start) { if (strcmp (end, ".gz") == 0 || strcmp (end, ".bz2") == 0 || strcmp (end, ".sit") == 0 || strcmp (end, ".bz") == 0 || strcmp (end, ".xz") == 0 || strcmp (end, ".Z") == 0) { end2 = end - 1; while (end2 > start && *end2 != '.') { end2--; } if (end2 != start) { end = end2; } } } return end; } char * eel_filename_strip_extension (const char * filename_with_extension) { char *filename, *end; if (filename_with_extension == NULL) { return NULL; } filename = g_strdup (filename_with_extension); end = eel_filename_get_extension_offset (filename); if (end && end != filename) { *end = '\0'; } return filename; } void eel_filename_get_rename_region (const char *filename, int *start_offset, int *end_offset) { char *filename_without_extension; g_return_if_fail (start_offset != NULL); g_return_if_fail (end_offset != NULL); *start_offset = 0; *end_offset = 0; g_return_if_fail (filename != NULL); filename_without_extension = eel_filename_strip_extension (filename); *end_offset = g_utf8_strlen (filename_without_extension, -1); g_free (filename_without_extension); } nemo-4.4.2/eel/eel-vfs-extensions.h000066400000000000000000000047301357442400300171410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-vfs-extensions.h - gnome-vfs extensions. Its likely some of these will be part of gnome-vfs in the future. Copyright (C) 1999, 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler Pavel Cisler Mike Fleming John Sullivan */ #ifndef EEL_VFS_EXTENSIONS_H #define EEL_VFS_EXTENSIONS_H #include G_BEGIN_DECLS #define EEL_TRASH_URI "trash:" #define EEL_DESKTOP_URI "x-nemo-desktop:" #define EEL_SEARCH_URI "x-nemo-search:" gboolean eel_uri_is_trash (const char *uri); gboolean eel_uri_is_trash_folder (const char *uri); gboolean eel_uri_is_in_trash (const char *uri); gboolean eel_uri_is_desktop (const char *uri); gboolean eel_uri_is_search (const char *uri); gboolean eel_uri_is_recent (const char *uri); gboolean eel_uri_is_network (const char *uri); char * eel_make_valid_utf8 (const char *name); char * eel_filename_strip_extension (const char *filename); void eel_filename_get_rename_region (const char *filename, int *start_offset, int *end_offset); char * eel_filename_get_extension_offset (const char *filename); G_END_DECLS #endif /* EEL_VFS_EXTENSIONS_H */ nemo-4.4.2/eel/eel.h000066400000000000000000000025141357442400300141460ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel.h Copyright (C) 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Maciej Stachowiak */ #ifndef EEL_H #define EEL_H #include #include #include #include #include #include #include #include #include #include #endif /* EEL_H */ nemo-4.4.2/eel/meson.build000066400000000000000000000016571357442400300154010ustar00rootroot00000000000000 eel_sources = [ 'eel-accessibility.c', 'eel-art-extensions.c', 'eel-canvas.c', 'eel-debug.c', 'eel-editable-label.c', 'eel-gdk-extensions.c', 'eel-glib-extensions.c', 'eel-gnome-extensions.c', 'eel-graphic-effects.c', 'eel-gtk-extensions.c', 'eel-lib-self-check-functions.c', 'eel-self-checks.c', 'eel-stock-dialogs.c', 'eel-string.c', 'eel-vfs-extensions.c', ] eel_deps = [ gtk, libxml, gail ] eel_lib = static_library('eel', eel_sources, dependencies: eel_deps, include_directories: [ rootInclude, ], install: false, c_args: '-DG_LOG_DOMAIN="Eel"' ) eel = declare_dependency( include_directories: include_directories('.'), link_with: [ eel_lib ], dependencies: eel_deps, ) test('Eel test', executable('check-program', 'check-program.c', dependencies: eel, include_directories: [ rootInclude, ], install: false ), args: ['--g-fatal-warnings', '--sm-disable'] ) nemo-4.4.2/files/000077500000000000000000000000001357442400300135635ustar00rootroot00000000000000nemo-4.4.2/files/meson.build000066400000000000000000000004351357442400300157270ustar00rootroot00000000000000message('Copying ./files structure') install_subdir('usr/share/gtksourceview-2.0', install_dir: get_option('datadir'), ) install_subdir('usr/share/gtksourceview-3.0', install_dir: get_option('datadir'), ) install_subdir('usr/share/nemo', install_dir: get_option('datadir'), ) nemo-4.4.2/files/usr/000077500000000000000000000000001357442400300143745ustar00rootroot00000000000000nemo-4.4.2/files/usr/share/000077500000000000000000000000001357442400300154765ustar00rootroot00000000000000nemo-4.4.2/files/usr/share/gtksourceview-2.0/000077500000000000000000000000001357442400300206745ustar00rootroot00000000000000nemo-4.4.2/files/usr/share/gtksourceview-2.0/language-specs/000077500000000000000000000000001357442400300235725ustar00rootroot00000000000000nemo-4.4.2/files/usr/share/gtksourceview-2.0/language-specs/nemo_action.lang000066400000000000000000000101451357442400300267310ustar00rootroot00000000000000 application/nemo-action *.nemo_action # False True 2 True False 0 0 none True False True False vertical True False vertical button True True True True True 2 False True 5 False True 5 True True 0 -1 True False end 12 25 True False nemo-horizontal-layout-symbolic False True 1 True True Adjust horizontal grid spacing adjustment1 False False False True True 6 2 True False 32 nemo-horizontal-layout-wide-symbolic False True 3 True False end 6 25 vertical True False 5 5 nemo-vertical-layout-symbolic False False 0 True True Adjust vertical grid spacing False vertical adjustment2 False False False True True 1 True False 5 32 nemo-vertical-layout-wide-symbolic False True 2 1 True True 2 substack_enabled page0 True False center vertical 10 True False <b><big>Desktop icons are not currently enabled for this monitor.</big></b> True False True 0 button True True True none False True 2 substack_disabled page1 1 view preferences-desktop-display-symbolic False True 0 nemo-4.4.2/gresources/nemo-desktop-preferences.glade000066400000000000000000000752311357442400300225540ustar00rootroot00000000000000 50 200 100 10 10 75 200 100 10 10 True False 6 vertical 5 True False 10 10 True False start Desktop Layout True True 0 True False end False No desktop icons Show desktop icons on primary monitor only Show desktop icons on non-primary monitor(s) only Show desktop icons on all monitors False True 2 False True 0 True False Desktop Icons 0 False True 1 True False 10 0 0 in True False True False vertical True False vertical True False True True False False True False 20 20 5 20 True False Computer False True 6 0 True True center False True end 1 False True 0 False True 2 True False vertical True False False True 0 True False True True False False True False 20 20 5 20 True False Home False True 6 0 True True center False True end 1 False True 1 False True 3 True False vertical True False False True 0 True False True True False False True False 20 20 5 20 True False Trash False True 6 0 True True center False True end 1 False True 1 False True 4 True False vertical True False False True 0 True False True True False False True False 20 20 5 20 True False Mounted Drives False True 6 0 True True center False True end 1 False True 1 False True 5 True False vertical True False False True 0 True False True True False False True False 20 20 5 20 True False Network False True 6 0 True True center False True end 1 False True 1 False True 6 False True 2 True False Options 0 False True 3 True False 2 0 0 in True False True False vertical True False vertical True False True True False False True False 20 20 5 20 True False Show icons from missing monitors False True 6 0 True True center False True end 1 False True 0 False True 2 False True 4 nemo-4.4.2/gresources/nemo-directory-view-ui.xml000066400000000000000000000266201357442400300217150ustar00rootroot00000000000000 nemo-4.4.2/gresources/nemo-file-management-properties.glade000066400000000000000000010432501357442400300240240ustar00rootroot00000000000000 True True True False go-previous-symbolic True False edit-find-symbolic True False view-grid-symbolic True False view-list-symbolic True False view-compact-symbolic True False xapp-prefs-preview-symbolic True False go-next-symbolic True False go-up-symbolic True False view-refresh-symbolic True False computer-symbolic True False go-home-symbolic True False location-symbolic True False utilities-terminal-symbolic True False folder-new-symbolic Icon View List View Compact View Always Local Files Only Never Decimal Decimal (long format) Binary Binary (long format) By Name By Size By Type By Detailed Type By Modification Date By Access Date By Trashed Date 33% 50% 66% 100% 150% 200% 400% 100 KB 500 KB 1 MB 3 MB 5 MB 10 MB 100 MB 1 GB 2 GB 4 GB 8 GB 16 GB 32 GB 33% 50% 66% 100% 150% 200% 400% 33% 50% 66% 100% 150% 200% 400% Always Local Files Only Never Yes Local Files Only No False File Management Preferences center 800 530 dialog True False vertical True False True False page_stack False True 0 True False crossfade True True True False True False vertical True False 6 vertical 6 True False <b>Default View</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False View _new folders using: True default_view_combobox 0 False False 0 True False model1 0 False True 1 False True 0 _Inherit view type from parent True True False True 0 True False False 1 True False 12 True False _Arrange items: True sort_order_combobox 0 False False 0 True False model2 0 False True 1 False True 2 Reverse sort True True False True 0 True False False 3 Sort _folders before files True True False True 0 True False False 4 False True 1 False True 0 True False 6 vertical 6 True False <b>Icon View Defaults</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False Default _zoom level: True icon_view_zoom_combobox 0 False False 0 True False model3 0 False True 1 False True 0 _Text beside icons True True False True 0 True False False 1 False True 1 False True 1 True False 6 vertical 6 True False <b>Compact View Defaults</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False _Default zoom level: True compact_view_zoom_combobox 0 False False 0 True False model4 0 False True 1 False True 0 A_ll columns have the same width True True False True 0 True False False 1 False True 1 False True 2 True False 6 vertical 6 True False <b>List View Defaults</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False D_efault zoom level: True list_view_zoom_combobox 0 False False 0 True False model5 0 False True 1 False True 0 False True 1 False True 3 True False 6 vertical 6 True False <b>Tree View Defaults</b> True 0 False False 0 True False 40 True False vertical 6 Show _only folders True True False True 0 True False False 0 False True 1 False True 4 views Views view-grid-symbolic True True True False True False vertical True False 6 vertical 6 True False <b>Behavior</b> True 0 False False 0 True False 40 True False vertical _Single click to open items True True False True 0 True True False False 0 _Double click to open items True True False True 0 True single_click_radiobutton False False 3 1 Click on a file's name twice to rename it True True False True 0 True False False 3 2 Open each _folder in its own window True True False True 0 True False False 3 3 Always start in dual-pane view True True False True 0 True False False 3 4 Ignore per-folder view preferences True True False True 0 True False False 3 5 Disable file operation queueing True True False True 0 True False False 3 6 Double-click on a blank area to go to the parent folder True True False True 0 True False False 3 7 False False 1 False True 0 True False 6 vertical 6 True False <b>Executable Text Files</b> True 0 False False 0 True False 40 True False vertical 6 _Run executable text files when they are opened True True False True 0 True True False False 0 _View executable text files when they are opened True True False True 0 True scripts_execute_radiobutton False False 1 _Ask each time True True False True 0 True scripts_execute_radiobutton False False 2 False False 1 False True 1 True False 6 vertical 6 True False <b>Trash</b> True 0 False False 0 True False 40 True False vertical 6 Ask before moving files to the Trash True True False True 0 True False False 0 Ask before _emptying the Trash or deleting files True True False True 0 True False False 1 I_nclude a Delete command that bypasses Trash True True False True 0 True False False 2 Bypass the Trash when the Delete key is pressed True True False 0 True False False 3 False False 1 False True 2 True False 6 vertical 6 True False <b>Media Handling</b> True 0 False False 0 True False 40 True False vertical 6 Automatically mount removeable media when inserted and on startup True True False True 0 True False False 0 Automatically open a folder for automounted media True True False True 0 True False False 1 Prompt or autorun/autostart programs when media are inserted True True False True 0 True False False 2 Automatically close the device's tab, pane, or window when a device is unmounted or ejected True True False True 0 True False False 3 False False 1 False True 3 True False 6 vertical 6 True False <b>Bulk Rename</b> True 0 False False 0 True False 40 40 True False vertical True False 4 True False Command to invoke when renaming multiple items: 0 False True 0 True True True â— out False True 1 False True 0 False False 1 False True 4 behavior Behavior xapp-prefs-behavior-symbolic 1 True True True False True False vertical True False 6 vertical 6 True False <b>Icon Captions</b> True 0 False False 0 True False 40 True False vertical 6 True False Choose the order of information to appear beneath icon names. More information will appear when zooming in closer. True 0 False False 0 True False True False False False 0 True False False False 1 False False 1 True False True False True False False 0 True False False False 1 False False 2 True False True False False False 0 True False False False 1 False False 3 False False 1 False True 0 True False 6 vertical 6 True False <b>Date</b> True 0 False False 0 True False 40 True False 12 True False _Format: True date_format_combobox False False 0 True False False False 1 False False 1 False False 1 True False 6 vertical 6 True False <b>Window and Tab Titles</b> True 0 False False 0 True False 40 True False vertical 6 Show the full p_ath in the title bar and tab bars True True False True 0 True False False 0 False False 1 False True 2 True False 6 vertical 6 True False <b>File Size</b> True 0 False False 0 True False 40 True False 12 True False _Prefixes: True size_prefixes_combobox False False 0 True False model11 0 False False 1 False False 1 False False 3 True False 6 vertical 6 True False <b>File Properties</b> True 0 False False 0 True False 40 True False vertical 6 Show advanced permissions in the file property dialog True True False True 0 True False False 0 False False 2 False False 4 True False 6 vertical 6 True False <b>Move/Copy To Menu</b> True 0 False False 0 True False 40 True False vertical 6 List bookmarks in the menu True True False True 0 True False False 0 List devices and network locations in the menu True True False True 0 True False False 1 False False 1 False True 5 display Display xapp-prefs-display-symbolic 2 True True True False True False vertical True False 6 vertical 6 True False <b>List Columns</b> True 0 False False 0 True False 12 True False vertical 6 True False Choose the order of information to appear in the list view. True 0 False False 0 True True 1 True True 0 list-columns List Columns view-list-symbolic 3 True True True False True False vertical True False 6 vertical 6 True False <b>Previewable Files</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False Show _thumbnails: True preview_image_combobox 0 False False 0 True False model7 0 False False 1 False False 0 _Inherit thumbnail visibility from parent True True False True 0 True False False 1 True False 12 True False _Only for files smaller than: True preview_image_size_combobox 0 False False 0 True False model32 0 False True 1 False True 2 False True 1 False True 0 True False 6 vertical 6 True False <b>Folders</b> True 0 False False 0 True False 40 True False vertical 6 True False 12 True False Count _number of items: True preview_folder_combobox 0 False False 0 True False model10 0 False True 1 False True 0 False True 1 False True 1 True False 6 vertical 6 True False <b>Tooltips</b> True 0 False False 0 True False 40 True False vertical 3 Show tooltips in icon and compact views True True False True 0 True False False 3 0 Show tooltips in list views True True False True 0 True False False 3 1 Show tooltips on the desktop True True False True 0 True False False 3 2 True False <i>By default, a folder tooltip shows the item count, and files display their size. Select additional information to display in the tooltip:</i> True 0 False True 3 3 True False 40 True False vertical 6 Detailed file type True True False 0 True False False 0 Modified date True True False 0 True False False 1 Created date True True False True 0 True False False 2 Accessed date True True False True 0 True False False 3 File or folder location True True False True 0 True False False 4 False True 4 False False 1 False True 2 preview Preview xapp-prefs-preview-symbolic 4 True True True False True False vertical True False 6 vertical 6 True False Visible Buttons 0 False True 0 True False 40 3 6 6 True True True False 6 show_previous_icon_toolbar_togglebutton True True True image1 False True 0 True False Previous False True 1 0 0 True False 6 show_previous_icon_toolbar_togglebutton True True True image2 False True 0 True False Next False True 1 1 0 True False 6 show_previous_icon_toolbar_togglebutton True True True image3 False True 0 True False Up False True 1 0 1 True False 6 show_previous_icon_toolbar_togglebutton True True True image4 False True 0 True False Refresh False True 1 1 1 True False 6 show_previous_icon_toolbar_togglebutton True True True image5 False True 0 True False Computer False True 1 0 2 True False 6 show_previous_icon_toolbar_togglebutton True True True image6 False True 0 True False Home False True 1 1 2 True False 6 show_previous_icon_toolbar_togglebutton True True True image7 False True 0 True False Location entry toggle False True 1 0 3 True False 6 show_previous_icon_toolbar_togglebutton True True True image8 False True 0 True False Open in terminal False True 1 1 3 True False 6 show_previous_icon_toolbar_togglebutton True True True image9 False True 0 True False New folder False True 1 0 4 True False 6 show_previous_icon_toolbar_togglebutton True True True image10 False True 0 True False Search False True 1 1 4 True False 6 show_previous_icon_toolbar_togglebutton True True True image11 False True 0 True False Icon view False True 1 0 5 True False 6 show_previous_icon_toolbar_togglebutton True True True image12 False True 0 True False List view False True 1 1 5 True False 6 show_previous_icon_toolbar_togglebutton True True True image13 False True 0 True False Compact view False True 1 0 6 True False 6 show_show_thumbnails_icon_toolbar_togglebutton True True True image14 False True 0 True False Show Thumbnails False True 1 1 6 False True 2 True True 0 toolbar Toolbar xapp-prefs-toolbar-symbolic 5 True True True False True False 6 vertical True False Visible Entries 0 False True 0 True False True False vertical 5 True False vertical True False Selection False True 5 0 True False True True False _Open True True False 2 2 True True True True False Open in New _Tab True True False 2 2 True True True True False Open in New _Window True True False 2 2 True True True True False _Scripts True True False 2 2 True True True True False Cu_t True True False 2 2 True True True True False _Copy True True False 2 2 True True True True False _Paste True True False 2 2 True True True True False D_uplicate True True False 2 2 True True True True False P_in True True False 2 2 True True True True False Ma_ke Link True True False 2 2 True True True True False _Rename... True True False 2 2 True True True True False Cop_y to True True False 2 2 True True True True False M_ove to True True False 2 2 True True True True False Open in Terminal True True False 2 2 True True True False Open as Root True True False 2 2 True True True False Mo_ve to Trash True True False 2 2 True True True True False _Properties True True False 2 2 True True False True 1 False True 2 True False 0 True False vertical 5 True False vertical True False Background False True 5 0 True False True True False Create New _Folder True True False 2 2 True True True True False _Scripts True True False 2 2 True True True True False Open in Terminal True True False 2 2 True True True False Open as Root True True False 2 2 True True True False Show _Hidden Files True True False 2 2 True True True True False _Paste True True False 2 2 True True True True False _Properties True True False 2 2 True True False True 1 False True 4 True False vertical True False Icon View False True 5 0 True False True True False Arran_ge Items True True False 2 2 True True True True False _Organize by Name True True False 2 2 True True False True 1 True False 5 True False vertical True False Desktop False True 5 0 True False True True False _Customize True True False 2 2 True True False True 1 False True 6 True False 1 True False 1 True False Visible action and extension entries can be configured in the Plugins tab True True True end 2 page0 Context Menus open-menu-symbolic 6 True True True False True False vertical plugins Plugins xapp-prefs-plugins-symbolic 7 True True 1 True True 0 Always Local Files Only Never nemo-4.4.2/gresources/nemo-icon-view-ui.xml000066400000000000000000000036031357442400300206350ustar00rootroot00000000000000 nemo-4.4.2/gresources/nemo-list-view-ui.xml000066400000000000000000000002151357442400300206540ustar00rootroot00000000000000 nemo-4.4.2/gresources/nemo-shell-ui.xml000066400000000000000000000114231357442400300200430ustar00rootroot00000000000000 nemo-4.4.2/gresources/nemo-shortcuts.ui000066400000000000000000000465411357442400300202050ustar00rootroot00000000000000 False True shortcuts 12 True General True New window <Primary>N True Close window or tab <Primary>W True Close all windows <Primary>Q True Toggle extra pane F3 True Search <Primary>F True Bookmark current location <Primary>D True Edit bookmarks <Primary>B True Make link <Primary>M True Pin/Unpin selection <Primary><shift>D True Show help F1 True Shortcuts <Primary>F1 True Opening True Open Return <Primary>O True Open in new tab <Primary><shift>T True Open in new window <Primary><shift>O True Open item location (recent files and search only) <Primary><alt>O True Tabs True New tab <Primary>T True Go to previous tab <Primary>Page_Up True Go to next tab <Primary>Page_Down True Switch to tab <alt>0...8 True Move tab left <shift><Primary>Page_Up True Move tab right <shift><Primary>Page_Down True Navigation True Go back BackSpace <alt>Left True Go forward <alt>Right True Go up <alt>Up True Go down <alt>Down True Go to home folder <alt>Home True Toggle location entry <Primary>L True View True Zoom in <Primary>plus True Zoom out <Primary>minus True Reset zoom <Primary>0 True Refresh view F5 <Primary>R True Show/hide hidden files <Primary>H True Show/hide sidebar F9 True Show/hide action menu F10 True List view <Primary>1 True Grid view <Primary>2 True Compact view <Primary>3 True Editing True Create folder <shift><Primary>N True Rename F2 True Move to trash Delete True Delete permanently <shift>Delete True Cut <Primary>X True Copy <Primary>C True Paste <Primary>V True Select all <Primary>A True Invert selection <shift><Primary>I True Select items matching <Primary>S True Undo <Primary>z True Redo <Primary>y True Show item properties <Primary>I <alt>Return nemo-4.4.2/gresources/nemo-statusbar-ui.xml000066400000000000000000000004171357442400300207450ustar00rootroot00000000000000 nemo-4.4.2/gresources/nemo-style-application.css000066400000000000000000000035171357442400300217570ustar00rootroot00000000000000/* Desktop text stuff */ .nemo-window.nemo-desktop-window notebook, .nemo-window.nemo-desktop-window paned { background-color: transparent; } .nemo-desktop-window, .nemo-desktop-window:backdrop { box-shadow: none; } NemoDesktopWindow GtkPaned { background-color: transparent; } .nemo-canvas-item { border-radius: 3px; } .nemo-desktop { -NemoIconContainer-activate-prelight-icon-label: true; } .nemo-desktop.nemo-canvas-item { color: #eeeeee; text-shadow: 1px 1px alpha(black, 0.8); } .nemo-desktop.nemo-canvas-item:hover { background-color: alpha(black, 0.5); background-image: none; text-shadow: none; } .nemo-desktop.nemo-canvas-item:selected { background-color: alpha(@theme_selected_bg_color, 0.8); background-image: none; text-shadow: none; color: #f5f5f5; } /* EelEditableLabel (icon labels) */ .nemo-desktop.view .entry, .nemo-desktop.view .entry:active, .nemo-desktop.view .entry:focus, .nemo-desktop.view .entry:backdrop { border-image: none; border-style: solid; border-width: 1px; border-color: #000000; border-radius: 3px; color: #000000; caret-color: #000000; text-shadow: none; background-image: -gtk-gradient(linear, left top, left bottom, from (shade(rgba(255,255,255,1), 0.86)), color-stop (0.15, shade(rgba(255,255,255,1), 0.96)), color-stop (0.50, shade(rgba(255,255,255,1), 0.98)), to (shade(rgba(255,255,255,1), 1.00))); } .nemo-desktop.view .entry:selected, .nemo-desktop.view .entry:focus:selected, .nemo-desktop.view .entry:backdrop:selected { background-color: @theme_selected_bg_color; color: @theme_selected_fg_color; text-shadow: none; } nemo-4.4.2/gresources/nemo-style-fallback-mandatory.css000066400000000000000000000014771357442400300232120ustar00rootroot00000000000000/* Things that can traditionally be controlled by the user theme, but that we *must* * have regardless, for a usable application. A couple things that we cannot do without. */ /* Inactive F3 pane shading */ .nemo-window .nemo-inactive-pane .view, .nemo-window .nemo-inactive-pane iconview { background-color: @theme_unfocused_bg_color; } /* Rename box styling in the icon view. */ .nemo-window .nemo-window-pane widget.entry { border: 1px solid; border-radius: 3px; color: @theme_fg_color; border-color: @theme_selected_bg_color; background-color: @theme_bg_color; } .nemo-window .nemo-window-pane widget.entry:selected { border: 1px solid; border-radius: 3px; color: @theme_selected_fg_color; border-color: @theme_selected_bg_color; background-color: @theme_selected_bg_color; } nemo-4.4.2/gresources/nemo-style-fallback.css000066400000000000000000000012401357442400300212020ustar00rootroot00000000000000/* For Places Sidebar diskfull indicators */ .places-treeview { -NemoPlacesTreeView-disk-full-bg-color: shade(@theme_bg_color, .65); -NemoPlacesTreeView-disk-full-fg-color: shade(@theme_selected_bg_color, 1.0); -NemoPlacesTreeView-disk-full-bar-width: 2px; -NemoPlacesTreeView-disk-full-bar-radius: 1px; -NemoPlacesTreeView-disk-full-bottom-padding: 1px; -NemoPlacesTreeView-disk-full-max-length: 70px; } .places-treeview:selected { -NemoPlacesTreeView-disk-full-bg-color: shade(@theme_bg_color, 2.0); -NemoPlacesTreeView-disk-full-fg-color: shade(@theme_fg_color, 2.0); } .places-treeview:hover { } .places-treeview:selected:hover { } nemo-4.4.2/gresources/nemo.gresource.xml000066400000000000000000000017261357442400300203250ustar00rootroot00000000000000 nemo-bookmarks-window.glade nemo-file-management-properties.glade nemo-desktop-overlay.glade nemo-desktop-preferences.glade nemo-shortcuts.ui nemo-icon-view-ui.xml nemo-directory-view-ui.xml nemo-desktop-icon-view-ui.xml nemo-desktop-icon-grid-view-ui.xml nemo-list-view-ui.xml nemo-shell-ui.xml nemo-statusbar-ui.xml thumbnail_frame.png knob.png nemo-style-fallback.css nemo-style-fallback-mandatory.css nemo-style-application.css nemo-4.4.2/gresources/thumbnail_frame.png000066400000000000000000000042701357442400300205100ustar00rootroot00000000000000‰PNG  IHDRôxÔúsRGB®ÎérIDATxÚíÛ½jG€áw%}Ф²{ßÿ½8EŒ„SÈÑÏl AQŠãoçy`ø,©9 ûÎÊ.àÌöyþõM༮çù‡+{€S»™ŸGõûü|pnoççsõT=T÷Îíý¼õ?V_ª»ê“€s{WŸ«ßÊ¿€³»™oþª~­¶êVÀ¹]Ϩú¥úXýì¿À¹íóÖ¿Uoúúö°V ìÕ&`Ñ @€ @€` @€ @€ @€ @€ @€ @€ ücžCÀZÿ½Ú,Z€ @€ @ ¬ @€ @€¬dÌsXëâ¿W›€EK€ @€ @€€ @€ @°°1Ï!`­‹ÿ^m-@€ @€ V€ @€ @ÀÂÆ<‡€µ.þ{µ X´@€ @€ @X@€ @€  óÖºøïÕ&`Ñ @€ @€` @€ @€,lÌsXëâ¿W›€EK€ @€ @€€ @€ @°°1Ï!`­‹ÿ^m-@€ @€ V€ @€ @ÀÂÆ<‡€µ.þ{µ X´@€ @€ @X@€ @€  óÖºøïÕ&`Ñ @€ @€` @€ @€,lÌsXëâ¿W›€EK€ @€ @€€ @€ @°°1Ï!`­‹ÿ^m-@€ @€ V€ @€ @ÀÂÆ<‡€µ.þ{µ X´@€ @€ @X@€ @€ð_®^„ÀuuS½­ÞWïæ××Bί՘Ÿßþ \ž——øñíù~õâ÷óaÿ\=VÕ—ùóÍþàâ=VOÕxýài>ôÿ¬nçƒÿM~ð=pßf2“™Ìd¦ËŸé±úT}®î_ÀCuW}˜_œà À÷sü€û6“™Ìd&3]þLóáÿ¡º{÷³ªþ¨~š#üÅ1“™Ìd&3]öL£¯oùïªÛ¿']Šç¼w`ôIEND®B`‚nemo-4.4.2/install-scripts/000077500000000000000000000000001357442400300156145ustar00rootroot00000000000000nemo-4.4.2/install-scripts/meson.build000066400000000000000000000013201357442400300177520ustar00rootroot00000000000000# These scripts run as post-installation scripts. # They're designed to do nothing if DESTDIR is set, which happens # during debian builds for instance - there's a fake install target # so running these would be pointless. # When using deb packaging, these aren't needed, as these operations # are run automatically by the package manager. # They're really only necessary in straight builds where 'ninja install' # will be run directly, to install the program onto the system. # Re-compile gsettings meson.add_install_script('meson_install_schemas.py') # Update mime info meson.add_install_script('meson_update_mime_database.py') # Update the Gtk icon cache meson.add_install_script('meson_update_icon_cache.py') nemo-4.4.2/install-scripts/meson_install_schemas.py000066400000000000000000000004261357442400300225420ustar00rootroot00000000000000#!/usr/bin/python3 import os import subprocess schemadir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') if not os.environ.get('DESTDIR'): print('Compiling gsettings schemas...') subprocess.call(['glib-compile-schemas', schemadir]) nemo-4.4.2/install-scripts/meson_update_icon_cache.py000066400000000000000000000004501357442400300230030ustar00rootroot00000000000000#!/usr/bin/python3 import os import subprocess themedir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'icons', 'hicolor') if not os.environ.get('DESTDIR'): print('Updating gtk icon cache... %s' % themedir) subprocess.call(['gtk-update-icon-cache', '-f', '-t', themedir]) nemo-4.4.2/install-scripts/meson_update_mime_database.py000066400000000000000000000003761357442400300235120ustar00rootroot00000000000000#!/usr/bin/python3 import os import subprocess mimedir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'mime') if not os.environ.get('DESTDIR'): print('Updating mime database...') subprocess.call(['update-mime-database', mimedir]) nemo-4.4.2/libnemo-extension/000077500000000000000000000000001357442400300161205ustar00rootroot00000000000000nemo-4.4.2/libnemo-extension/libnemo-extension.pc.in000066400000000000000000000004611357442400300225110ustar00rootroot00000000000000prefix=@prefix@ libdir=${prefix}/@libdir@ includedir=${prefix}/@includedir@ extensiondir=@extensiondir@ Name: libnemo-extension Description: A library to create Nemo view extensions Version: @version@ Requires: gio-2.0, glib-2.0, gtk+-3.0 Libs: -L${libdir} -lnemo-extension Cflags: -I${includedir}/nemo nemo-4.4.2/libnemo-extension/meson.build000066400000000000000000000052261357442400300202670ustar00rootroot00000000000000 nemo_extension_sources = [ gresources, 'nemo-column-provider.c', 'nemo-column.c', 'nemo-desktop-preferences.c', 'nemo-extension-i18n.h', 'nemo-extension-private.h', 'nemo-file-info.c', 'nemo-info-provider.c', 'nemo-location-widget-provider.c', 'nemo-menu-item.c', 'nemo-menu-provider.c', 'nemo-name-and-desc-provider.c', 'nemo-property-page-provider.c', 'nemo-property-page.c', 'nemo-menu.c', 'nemo-simple-button.c', ] nemo_extension_headers = [ 'nemo-column-provider.h', 'nemo-column.h', 'nemo-desktop-preferences.h', 'nemo-extension-types.h', 'nemo-file-info.h', 'nemo-info-provider.h', 'nemo-location-widget-provider.h', 'nemo-menu-item.h', 'nemo-menu-provider.h', 'nemo-name-and-desc-provider.h', 'nemo-property-page-provider.h', 'nemo-property-page.h', 'nemo-menu.h', 'nemo-simple-button.h', ] nemo_extension_incdir = include_directories('.') nemo_extension_deps = [ glib, gtk ] nemo_extension_lib = shared_library('nemo-extension', nemo_extension_sources, dependencies: nemo_extension_deps, include_directories: [ rootInclude, ], install: true, version: '1.4.0', link_args: [ '-Wl,-no-undefined' ], ) install_headers(nemo_extension_headers, subdir: join_paths('nemo', 'libnemo-extension') ) nemo_extension = declare_dependency( include_directories: include_directories('.'), link_with: [ nemo_extension_lib ], dependencies: nemo_extension_deps, ) gnome.generate_gir(nemo_extension_lib, sources: nemo_extension_sources + nemo_extension_headers, nsversion: '3.0', namespace: 'Nemo', includes: [ 'Gtk-3.0', 'Gio-2.0', 'GLib-2.0', ], include_directories: [ rootInclude, ], install_dir_typelib: join_paths(go_intr.get_pkgconfig_variable('libdir'), 'girepository-1.0'), install: true, ) if meson.version().version_compare('>=0.41.0') pkgconfig.generate(filebase: 'libnemo-extension', name: 'libnemo-extension', description: 'A library to create Nemo view extensions', version: meson.project_version(), requires: [ 'gio-2.0', 'glib-2.0', 'gtk+-3.0' ], libraries: nemo_extension_lib, subdirs: 'nemo', variables: 'extensiondir=${libdir}/@0@/@1@'.format('nemo', 'extensions-3.0'), ) else pc_conf = configuration_data() pc_conf.set('prefix', get_option('prefix')) pc_conf.set('libdir', get_option('libdir')) pc_conf.set('includedir', get_option('includedir')) pc_conf.set('version', meson.project_version()) pc_conf.set('extensiondir', nemoExtensionPath) configure_file( input : 'libnemo-extension.pc.in', output: 'libnemo-extension.pc', configuration: pc_conf, install: true, install_dir: join_paths(get_option('libdir'), 'pkgconfig'), ) endif nemo-4.4.2/libnemo-extension/nemo-column-provider.c000066400000000000000000000040161357442400300223460ustar00rootroot00000000000000/* * nemo-column-provider.c - Interface for Nemo extensions * that provide column specifications. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-column-provider.h" #include G_DEFINE_INTERFACE (NemoColumnProvider, nemo_column_provider, G_TYPE_OBJECT) /** * SECTION:nemo-column-provider * @Title: NemoColumnProvider * @Short_description: An interface to provide additional Nemo list view columns. * * This allows additional columns to be shown in the list view. This interface * generally needs to be used in tandem with a #NemoInfoProvider, to feed file * info back to populate the column(s). * **/ static void nemo_column_provider_default_init (NemoColumnProviderInterface *klass) { } /** * nemo_column_provider_get_columns: * @provider: a #NemoColumnProvider * * Returns: (element-type NemoColumn) (transfer full): the provided #NemoColumn objects **/ GList * nemo_column_provider_get_columns (NemoColumnProvider *provider) { g_return_val_if_fail (NEMO_IS_COLUMN_PROVIDER (provider), NULL); g_return_val_if_fail (NEMO_COLUMN_PROVIDER_GET_IFACE (provider)->get_columns != NULL, NULL); return NEMO_COLUMN_PROVIDER_GET_IFACE (provider)->get_columns (provider); } nemo-4.4.2/libnemo-extension/nemo-column-provider.h000066400000000000000000000040451357442400300223550ustar00rootroot00000000000000/* * nemo-column-provider.h - Interface for Nemo extensions that * provide column descriptions. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ /* This interface is implemented by Nemo extensions that want to * add columns to the list view and details to the icon view. * Extensions are asked for a list of columns to display. Each * returned column refers to a string attribute which can be filled in * by NemoInfoProvider */ #ifndef NEMO_COLUMN_PROVIDER_H #define NEMO_COLUMN_PROVIDER_H #include #include "nemo-extension-types.h" #include "nemo-column.h" G_BEGIN_DECLS #define NEMO_TYPE_COLUMN_PROVIDER (nemo_column_provider_get_type ()) G_DECLARE_INTERFACE (NemoColumnProvider, nemo_column_provider, NEMO, COLUMN_PROVIDER, GObject) typedef NemoColumnProviderInterface NemoColumnProviderIface; /** * NemoColumnProviderInterface: * @g_iface: the parent class * @get_columns: Fetch an array of @NemoColumn */ struct _NemoColumnProviderInterface { GTypeInterface g_iface; GList *(*get_columns) (NemoColumnProvider *provider); }; /* Interface Functions */ GList *nemo_column_provider_get_columns (NemoColumnProvider *provider); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-column.c000066400000000000000000000153331357442400300205220ustar00rootroot00000000000000/* * nemo-column.c - Info columns exported by NemoColumnProvider * objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-column.h" #include "nemo-extension-i18n.h" enum { PROP_0, PROP_NAME, PROP_ATTRIBUTE, PROP_ATTRIBUTE_Q, PROP_LABEL, PROP_DESCRIPTION, PROP_XALIGN, LAST_PROP }; typedef struct { char *name; GQuark attribute; char *label; char *description; float xalign; } NemoColumnPrivate; struct _NemoColumn { GObject parent_object; NemoColumnPrivate *details; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoColumn, nemo_column, G_TYPE_OBJECT) /** * SECTION:nemo-column * @Title: NemoColumn * @Short_description: A column used in Nemo's list view. * * A column is linked to a particular file attribute to display in the view. * Many of these are built in to Nemo, but they can also be provided by * a #NemoColumnProvider/#NemoInfoProvider extension. **/ /** * nemo_column_new: * @name: identifier of the column * @attribute: the file attribute to be displayed in the column * @label: the user-visible label for the column * @description: a user-visible description of the column * * Creates a new column * * Returns: a newly created #NemoColumn */ NemoColumn * nemo_column_new (const char *name, const char *attribute, const char *label, const char *description) { NemoColumn *column; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (attribute != NULL, NULL); g_return_val_if_fail (label != NULL, NULL); g_return_val_if_fail (description != NULL, NULL); column = g_object_new (NEMO_TYPE_COLUMN, "name", name, "attribute", attribute, "label", label, "description", description, NULL); return column; } static void nemo_column_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { NemoColumn *column; column = NEMO_COLUMN (object); switch (param_id) { case PROP_NAME : g_value_set_string (value, column->details->name); break; case PROP_ATTRIBUTE : g_value_set_string (value, g_quark_to_string (column->details->attribute)); break; case PROP_ATTRIBUTE_Q : g_value_set_uint (value, column->details->attribute); break; case PROP_LABEL : g_value_set_string (value, column->details->label); break; case PROP_DESCRIPTION : g_value_set_string (value, column->details->description); break; case PROP_XALIGN : g_value_set_float (value, column->details->xalign); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_column_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { NemoColumn *column; column = NEMO_COLUMN (object); switch (param_id) { case PROP_NAME : g_free (column->details->name); column->details->name = g_strdup (g_value_get_string (value)); g_object_notify (object, "name"); break; case PROP_ATTRIBUTE : column->details->attribute = g_quark_from_string (g_value_get_string (value)); g_object_notify (object, "attribute"); g_object_notify (object, "attribute_q"); break; case PROP_LABEL : g_free (column->details->label); column->details->label = g_strdup (g_value_get_string (value)); g_object_notify (object, "label"); break; case PROP_DESCRIPTION : g_free (column->details->description); column->details->description = g_strdup (g_value_get_string (value)); g_object_notify (object, "description"); break; case PROP_XALIGN : column->details->xalign = g_value_get_float (value); g_object_notify (object, "xalign"); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_column_finalize (GObject *object) { NemoColumn *column; column = NEMO_COLUMN (object); g_free (column->details->name); g_free (column->details->label); g_free (column->details->description); g_free (column->details); G_OBJECT_CLASS (nemo_column_parent_class)->finalize (object); } static void nemo_column_init (NemoColumn *column) { column->details = G_TYPE_INSTANCE_GET_PRIVATE (column, NEMO_TYPE_COLUMN, NemoColumnPrivate); column->details->xalign = 0.0; } static void nemo_column_class_init (NemoColumnClass *class) { G_OBJECT_CLASS (class)->finalize = nemo_column_finalize; G_OBJECT_CLASS (class)->get_property = nemo_column_get_property; G_OBJECT_CLASS (class)->set_property = nemo_column_set_property; g_object_class_install_property (G_OBJECT_CLASS (class), PROP_NAME, g_param_spec_string ("name", "Name", "Name of the column", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_ATTRIBUTE, g_param_spec_string ("attribute", "Attribute", "The attribute name to display", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_ATTRIBUTE_Q, g_param_spec_uint ("attribute_q", "Attribute quark", "The attribute name to display, in quark form", 0, G_MAXUINT, 0, G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_LABEL, g_param_spec_string ("label", "Label", "Label to display in the column", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_DESCRIPTION, g_param_spec_string ("description", "Description", "A user-visible description of the column", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_XALIGN, g_param_spec_float ("xalign", "xalign", "The x-alignment of the column", 0.0, 1.0, 0.0, G_PARAM_READWRITE)); } nemo-4.4.2/libnemo-extension/nemo-column.h000066400000000000000000000035401357442400300205240ustar00rootroot00000000000000/* * nemo-column.h - Info columns exported by * NemoColumnProvider objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #ifndef NEMO_COLUMN_H #define NEMO_COLUMN_H #include #include "nemo-extension-types.h" G_BEGIN_DECLS #define NEMO_TYPE_COLUMN nemo_column_get_type() G_DECLARE_FINAL_TYPE (NemoColumn, nemo_column, NEMO, COLUMN, GObject) NemoColumn * nemo_column_new (const char *name, const char *attribute, const char *label, const char *description); /* NemoColumn has the following properties: * name (string) - the identifier for the column * attribute (string) - the file attribute to be displayed in the * column * label (string) - the user-visible label for the column * description (string) - a user-visible description of the column * xalign (float) - x-alignment of the column */ G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-desktop-preferences.c000066400000000000000000000073101357442400300231710ustar00rootroot00000000000000#include #include #include #include #include "nemo-desktop-preferences.h" typedef struct { GtkBuilder *builder; GSettings *desktop_settings; } NemoDesktopPreferencesPrivate; struct _NemoDesktopPreferences { GtkBin parent_object; NemoDesktopPreferencesPrivate *priv; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoDesktopPreferences, nemo_desktop_preferences, GTK_TYPE_BIN) /* copied from nemo-file-management-properties.c */ static void bind_builder_bool (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs) { g_settings_bind (settings, prefs, gtk_builder_get_object (builder, widget_name), "active", G_SETTINGS_BIND_DEFAULT); } static void bind_builder_string_combo (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs) { g_settings_bind (settings, prefs, gtk_builder_get_object (builder, widget_name), "active-id", G_SETTINGS_BIND_DEFAULT); } static void nemo_desktop_preferences_init (NemoDesktopPreferences *preferences) { GtkWidget *widget; NemoDesktopPreferencesPrivate *priv = nemo_desktop_preferences_get_instance_private (preferences); preferences->priv = priv; priv->desktop_settings = g_settings_new ("org.nemo.desktop"); priv->builder = gtk_builder_new (); gtk_builder_set_translation_domain (priv->builder, GETTEXT_PACKAGE); gtk_builder_add_from_resource (priv->builder, "/org/nemo/nemo-desktop-preferences.glade", NULL); widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "prefs_box")); gtk_container_add (GTK_CONTAINER (preferences), widget); bind_builder_string_combo (priv->builder, priv->desktop_settings, "layout_combo", "desktop-layout"); bind_builder_bool (priv->builder, priv->desktop_settings, "computer_switch", "computer-icon-visible"); bind_builder_bool (priv->builder, priv->desktop_settings, "home_switch", "home-icon-visible"); bind_builder_bool (priv->builder, priv->desktop_settings, "trash_switch", "trash-icon-visible"); bind_builder_bool (priv->builder, priv->desktop_settings, "drives_switch", "volumes-visible"); bind_builder_bool (priv->builder, priv->desktop_settings, "network_switch", "network-icon-visible"); bind_builder_bool (priv->builder, priv->desktop_settings, "orphan_switch", "show-orphaned-desktop-icons"); gtk_widget_show_all (GTK_WIDGET (preferences)); } static void nemo_desktop_preferences_dispose (GObject *object) { NemoDesktopPreferences *preferences = NEMO_DESKTOP_PREFERENCES (object); g_clear_object (&preferences->priv->builder); g_clear_object (&preferences->priv->desktop_settings); G_OBJECT_CLASS (nemo_desktop_preferences_parent_class)->dispose (object); } static void nemo_desktop_preferences_class_init (NemoDesktopPreferencesClass *klass) { G_OBJECT_CLASS (klass)->dispose = nemo_desktop_preferences_dispose; } NemoDesktopPreferences * nemo_desktop_preferences_new (void) { return g_object_new (NEMO_TYPE_DESKTOP_PREFERENCES, NULL); } nemo-4.4.2/libnemo-extension/nemo-desktop-preferences.h000066400000000000000000000006671357442400300232060ustar00rootroot00000000000000#ifndef _NEMO_DESKTOP_PREFERENCES_H_ #define _NEMO_DESKTOP_PREFERENCES_H_ #include #include G_BEGIN_DECLS #define NEMO_TYPE_DESKTOP_PREFERENCES (nemo_desktop_preferences_get_type ()) G_DECLARE_FINAL_TYPE (NemoDesktopPreferences, nemo_desktop_preferences, NEMO, DESKTOP_PREFERENCES, GtkBin) NemoDesktopPreferences *nemo_desktop_preferences_new (void); G_END_DECLS #endif /* _NEMO_DESKTOP_PREFERENCES_H_ */nemo-4.4.2/libnemo-extension/nemo-extension-i18n.h000066400000000000000000000011031357442400300220110ustar00rootroot00000000000000#ifndef NEMO_EXTENSION_I18N_H #define NEMO_EXTENSION_I18N_H #include "config.h" #ifdef ENABLE_NLS #include #define _(String) dgettext(GETTEXT_PACKAGE,String) #ifdef gettext_noop #define N_(String) gettext_noop(String) #else #define N_(String) (String) #endif #else /* NLS is disabled */ #define _(String) (String) #define N_(String) (String) #define textdomain(String) (String) #define gettext(String) (String) #define dgettext(Domain,String) (String) #define dcgettext(Domain,String,Type) (String) #define bindtextdomain(Domain,Directory) (Domain) #endif #endif nemo-4.4.2/libnemo-extension/nemo-extension-private.h000066400000000000000000000021771357442400300227200ustar00rootroot00000000000000/* * nemo-extension-private.h - Type definitions for Nemo extensions * * Copyright (C) 2009 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #ifndef NEMO_EXTENSION_PRIVATE_H #define NEMO_EXTENSION_PRIVATE_H #include G_BEGIN_DECLS extern NemoFileInfo *(*nemo_file_info_getter) (GFile *location, gboolean create); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-extension-types.h000066400000000000000000000055031357442400300224060ustar00rootroot00000000000000/* * nemo-info-provider.h - Type definitions for Nemo extensions * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ /* This interface is implemented by Nemo extensions that want to * provide information about files. Extensions are called when Nemo * needs information about a file. They are passed a NemoFileInfo * object which should be filled with relevant information */ #ifndef NEMO_EXTENSION_TYPES_H #define NEMO_EXTENSION_TYPES_H #include G_BEGIN_DECLS /** * SECTION:nemo-extension-types * @Title: Types and Enums * @Short_description: Module initialization functions, enums, handle struct **/ /** * NemoOperationHandle: * * Handle for asynchronous interfaces. These are opaque handles that must * be unique within an extension object. These are returned by operations * that return NEMO_OPERATION_IN_PROGRESS. * * For python extensions, the handle is a dummy struct created by the nemo * python bindings on the extension's behalf. It can be used as a unique * key for a dict, for instance, for keeping track of multiple operations * at once. */ typedef struct _NemoOperationHandle NemoOperationHandle; /** * NemoOperationResult: * @NEMO_OPERATION_COMPLETE: Returned if the call succeeded, and the extension is done * with the request. * @NEMO_OPERATION_FAILED: Returned if the call failed. * @NEMO_OPERATION_IN_PROGRESS: Returned if the extension has begun an async operation. * For C extensions, if this is returned, the extension must set the handle parameter. * For python extensions, handle is already filled, and unique, and can be used for * identifying purposes within the extension. In either case, the extension must call * the callback closure when the operation is complete (complete_invoke.) */ typedef enum { NEMO_OPERATION_COMPLETE, NEMO_OPERATION_FAILED, NEMO_OPERATION_IN_PROGRESS } NemoOperationResult; void nemo_module_initialize (GTypeModule *module); void nemo_module_shutdown (void); void nemo_module_list_types (const GType **types, int *num_types); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-file-info.c000066400000000000000000000244761357442400300211050ustar00rootroot00000000000000/* * nemo-file-info.c - Information about a file * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * */ #include #include "nemo-file-info.h" #include "nemo-extension-private.h" G_DEFINE_INTERFACE (NemoFileInfo, nemo_file_info, G_TYPE_OBJECT) NemoFileInfo *(*nemo_file_info_getter) (GFile *location, gboolean create); /** * SECTION:nemo-file-info * @Title: NemoFileInfo * @Short_description: A wrapper interface for extensions to access NemoFile info. * * This inteface is implemented by NemoFile and provides access to certain information * regarding a given file object. It is also used to add file attributes and notify * a file of changes to those attribues when using a #NemoInfoProvider. **/ static void nemo_file_info_default_init (NemoFileInfoInterface *klass) { } /** * nemo_file_info_list_copy: * @files: (element-type NemoFileInfo): the files to copy * * Returns: (element-type NemoFileInfo) (transfer full): a copy of @files. * Use #nemo_file_info_list_free to free the list and unref its contents. */ GList * nemo_file_info_list_copy (GList *files) { GList *ret; GList *l; ret = g_list_copy (files); for (l = ret; l != NULL; l = l->next) { g_object_ref (G_OBJECT (l->data)); } return ret; } /** * nemo_file_info_list_free: * @files: (element-type NemoFileInfo): a list created with * #nemo_file_info_list_copy * */ void nemo_file_info_list_free (GList *files) { GList *l; for (l = files; l != NULL; l = l->next) { g_object_unref (G_OBJECT (l->data)); } g_list_free (files); } gboolean nemo_file_info_is_gone (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), FALSE); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->is_gone != NULL, FALSE); return NEMO_FILE_INFO_GET_IFACE (file)->is_gone (file); } GFileType nemo_file_info_get_file_type (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), G_FILE_TYPE_UNKNOWN); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_file_type != NULL, G_FILE_TYPE_UNKNOWN); return NEMO_FILE_INFO_GET_IFACE (file)->get_file_type (file); } char * nemo_file_info_get_name (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_name != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_name (file); } /** * nemo_file_info_get_location: * @file: a #NemoFileInfo * * Returns: (transfer full): a #GFile for the location of @file */ GFile * nemo_file_info_get_location (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_location != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_location (file); } char * nemo_file_info_get_uri (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_uri != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_uri (file); } char * nemo_file_info_get_activation_uri (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_activation_uri != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_activation_uri (file); } /** * nemo_file_info_get_parent_location: * @file: a #NemoFileInfo * * Returns: (allow-none) (transfer full): a #GFile for the parent location of @file, * or %NULL if @file has no parent */ GFile * nemo_file_info_get_parent_location (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_parent_location != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_parent_location (file); } char * nemo_file_info_get_parent_uri (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_parent_uri != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_parent_uri (file); } /** * nemo_file_info_get_parent_info: * @file: a #NemoFileInfo * * Returns: (allow-none) (transfer full): a #NemoFileInfo for the parent of @file, * or %NULL if @file has no parent */ NemoFileInfo * nemo_file_info_get_parent_info (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_parent_info != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_parent_info (file); } /** * nemo_file_info_get_mount: * @file: a #NemoFileInfo * * Returns: (allow-none) (transfer full): a #GMount for the mount of @file, * or %NULL if @file has no mount */ GMount * nemo_file_info_get_mount (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_mount != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_mount (file); } char * nemo_file_info_get_uri_scheme (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_uri_scheme != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_uri_scheme (file); } char * nemo_file_info_get_mime_type (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_mime_type != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_mime_type (file); } gboolean nemo_file_info_is_mime_type (NemoFileInfo *file, const char *mime_type) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), FALSE); g_return_val_if_fail (mime_type != NULL, FALSE); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->is_mime_type != NULL, FALSE); return NEMO_FILE_INFO_GET_IFACE (file)->is_mime_type (file, mime_type); } gboolean nemo_file_info_is_directory (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), FALSE); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->is_directory != NULL, FALSE); return NEMO_FILE_INFO_GET_IFACE (file)->is_directory (file); } gboolean nemo_file_info_can_write (NemoFileInfo *file) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), FALSE); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->can_write != NULL, FALSE); return NEMO_FILE_INFO_GET_IFACE (file)->can_write (file); } void nemo_file_info_add_emblem (NemoFileInfo *file, const char *emblem_name) { g_return_if_fail (NEMO_IS_FILE_INFO (file)); g_return_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->add_emblem != NULL); NEMO_FILE_INFO_GET_IFACE (file)->add_emblem (file, emblem_name); } char * nemo_file_info_get_string_attribute (NemoFileInfo *file, const char *attribute_name) { g_return_val_if_fail (NEMO_IS_FILE_INFO (file), NULL); g_return_val_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->get_string_attribute != NULL, NULL); g_return_val_if_fail (attribute_name != NULL, NULL); return NEMO_FILE_INFO_GET_IFACE (file)->get_string_attribute (file, attribute_name); } void nemo_file_info_add_string_attribute (NemoFileInfo *file, const char *attribute_name, const char *value) { g_return_if_fail (NEMO_IS_FILE_INFO (file)); g_return_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->add_string_attribute != NULL); g_return_if_fail (attribute_name != NULL); g_return_if_fail (value != NULL); NEMO_FILE_INFO_GET_IFACE (file)->add_string_attribute (file, attribute_name, value); } /** * nemo_file_info_invalidate_extension_info: * @file: a #NemoFile * * Notifies nemo to re-run info provider extensions on the given file. * * This is useful if you have an extension that listens or responds to some external * interface for changes to local file metadata (such as a cloud drive changing file emblems.) * * When a change such as this occurs, call this on the file in question, and nemo will * schedule a call to extension->update_file_info to update its own internal metadata. * * NOTE: This does *not* need to be called on the tail end of a update_full/update_complete * asynchronous extension. Prior to Nemo 3.6 this was indeed the case, however, due to a * recursion issue in nemo-directory-async.c (see nemo 9e67417f8f09.) */ void nemo_file_info_invalidate_extension_info (NemoFileInfo *file) { g_return_if_fail (NEMO_IS_FILE_INFO (file)); g_return_if_fail (NEMO_FILE_INFO_GET_IFACE (file)->invalidate_extension_info != NULL); NEMO_FILE_INFO_GET_IFACE (file)->invalidate_extension_info (file); } /** * nemo_file_info_lookup: * @location: the location to lookup the file info for * * Returns: (transfer full): a #NemoFileInfo */ NemoFileInfo * nemo_file_info_lookup (GFile *location) { return nemo_file_info_getter (location, FALSE); } /** * nemo_file_info_create: * @location: the location to create the file info for * * Returns: (transfer full): a #NemoFileInfo */ NemoFileInfo * nemo_file_info_create (GFile *location) { return nemo_file_info_getter (location, TRUE); } /** * nemo_file_info_lookup_for_uri: * @uri: the URI to lookup the file info for * * Returns: (transfer full): a #NemoFileInfo */ NemoFileInfo * nemo_file_info_lookup_for_uri (const char *uri) { GFile *location; NemoFile *file; location = g_file_new_for_uri (uri); file = nemo_file_info_lookup (location); g_object_unref (location); return file; } /** * nemo_file_info_create_for_uri: * @uri: the URI to lookup the file info for * * Returns: (transfer full): a #NemoFileInfo */ NemoFileInfo * nemo_file_info_create_for_uri (const char *uri) { GFile *location; NemoFile *file; location = g_file_new_for_uri (uri); file = nemo_file_info_create (location); g_object_unref (location); return file; } nemo-4.4.2/libnemo-extension/nemo-file-info.h000066400000000000000000000132211357442400300210740ustar00rootroot00000000000000/* * nemo-file-info.h - Information about a file * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * */ /* NemoFileInfo is an interface to the NemoFile object. It * provides access to the asynchronous data in the NemoFile. * Extensions are passed objects of this type for operations. */ #ifndef NEMO_FILE_INFO_H #define NEMO_FILE_INFO_H #include #include G_BEGIN_DECLS #define NEMO_TYPE_FILE_INFO (nemo_file_info_get_type ()) #define NEMO_FILE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_FILE_INFO, NemoFileInfo)) #define NEMO_IS_FILE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_FILE_INFO)) #define NEMO_FILE_INFO_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NEMO_TYPE_FILE_INFO, NemoFileInfoInterface)) #ifndef NEMO_FILE_DEFINED #define NEMO_FILE_DEFINED /* Using NemoFile for the vtable to make implementing this in * NemoFile easier */ typedef struct NemoFile NemoFile; #endif typedef NemoFile NemoFileInfo; typedef struct _NemoFileInfoInterface NemoFileInfoInterface; struct _NemoFileInfoInterface { GTypeInterface g_iface; gboolean (*is_gone) (NemoFileInfo *file); char * (*get_name) (NemoFileInfo *file); char * (*get_uri) (NemoFileInfo *file); char * (*get_parent_uri) (NemoFileInfo *file); char * (*get_uri_scheme) (NemoFileInfo *file); char * (*get_mime_type) (NemoFileInfo *file); gboolean (*is_mime_type) (NemoFileInfo *file, const char *mime_Type); gboolean (*is_directory) (NemoFileInfo *file); void (*add_emblem) (NemoFileInfo *file, const char *emblem_name); char * (*get_string_attribute) (NemoFileInfo *file, const char *attribute_name); void (*add_string_attribute) (NemoFileInfo *file, const char *attribute_name, const char *value); void (*invalidate_extension_info) (NemoFileInfo *file); char * (*get_activation_uri) (NemoFileInfo *file); GFileType (*get_file_type) (NemoFileInfo *file); GFile * (*get_location) (NemoFileInfo *file); GFile * (*get_parent_location) (NemoFileInfo *file); NemoFileInfo* (*get_parent_info) (NemoFileInfo *file); GMount * (*get_mount) (NemoFileInfo *file); gboolean (*can_write) (NemoFileInfo *file); }; GList *nemo_file_info_list_copy (GList *files); void nemo_file_info_list_free (GList *files); GType nemo_file_info_get_type (void); /* Return true if the file has been deleted */ gboolean nemo_file_info_is_gone (NemoFileInfo *file); /* Name and Location */ GFileType nemo_file_info_get_file_type (NemoFileInfo *file); GFile * nemo_file_info_get_location (NemoFileInfo *file); char * nemo_file_info_get_name (NemoFileInfo *file); char * nemo_file_info_get_uri (NemoFileInfo *file); char * nemo_file_info_get_activation_uri (NemoFileInfo *file); GFile * nemo_file_info_get_parent_location (NemoFileInfo *file); char * nemo_file_info_get_parent_uri (NemoFileInfo *file); GMount * nemo_file_info_get_mount (NemoFileInfo *file); char * nemo_file_info_get_uri_scheme (NemoFileInfo *file); /* It's not safe to call this recursively multiple times, as it works * only for files already cached by Nemo. */ NemoFileInfo* nemo_file_info_get_parent_info (NemoFileInfo *file); /* File Type */ char * nemo_file_info_get_mime_type (NemoFileInfo *file); gboolean nemo_file_info_is_mime_type (NemoFileInfo *file, const char *mime_type); gboolean nemo_file_info_is_directory (NemoFileInfo *file); gboolean nemo_file_info_can_write (NemoFileInfo *file); /* Modifying the NemoFileInfo */ void nemo_file_info_add_emblem (NemoFileInfo *file, const char *emblem_name); char * nemo_file_info_get_string_attribute (NemoFileInfo *file, const char *attribute_name); void nemo_file_info_add_string_attribute (NemoFileInfo *file, const char *attribute_name, const char *value); /* Invalidating file info */ void nemo_file_info_invalidate_extension_info (NemoFileInfo *file); NemoFileInfo *nemo_file_info_lookup (GFile *location); NemoFileInfo *nemo_file_info_create (GFile *location); NemoFileInfo *nemo_file_info_lookup_for_uri (const char *uri); NemoFileInfo *nemo_file_info_create_for_uri (const char *uri); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-info-provider.c000066400000000000000000000071531357442400300220110ustar00rootroot00000000000000/* * nemo-info-provider.c - Interface for Nemo extensions that * provide info about files. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-info-provider.h" #include G_DEFINE_INTERFACE (NemoInfoProvider, nemo_info_provider, G_TYPE_OBJECT) /** * SECTION:nemo-info-provider * @Title: NemoInfoProvider * @Short_description: An interface to allow collection of additional file info. * * This interface can be used to collect additional file info, generally used * together with a #NemoColumnProvider. It can be used as a synchronous or async * interface. * * Additional, it can act in the background and notify Nemo when information has * changed from some external source. **/ static void nemo_info_provider_default_init (NemoInfoProviderInterface *klass) { } NemoOperationResult nemo_info_provider_update_file_info (NemoInfoProvider *provider, NemoFileInfo *file, GClosure *update_complete, NemoOperationHandle **handle) { g_return_val_if_fail (NEMO_IS_INFO_PROVIDER (provider), NEMO_OPERATION_FAILED); g_return_val_if_fail (NEMO_INFO_PROVIDER_GET_IFACE (provider)->update_file_info != NULL, NEMO_OPERATION_FAILED); g_return_val_if_fail (update_complete != NULL, NEMO_OPERATION_FAILED); g_return_val_if_fail (handle != NULL, NEMO_OPERATION_FAILED); return NEMO_INFO_PROVIDER_GET_IFACE (provider)->update_file_info (provider, file, update_complete, handle); } void nemo_info_provider_cancel_update (NemoInfoProvider *provider, NemoOperationHandle *handle) { g_return_if_fail (NEMO_IS_INFO_PROVIDER (provider)); g_return_if_fail (NEMO_INFO_PROVIDER_GET_IFACE (provider)->cancel_update != NULL); g_return_if_fail (handle != NULL); NEMO_INFO_PROVIDER_GET_IFACE (provider)->cancel_update (provider, handle); } void nemo_info_provider_update_complete_invoke (GClosure *update_complete, NemoInfoProvider *provider, NemoOperationHandle *handle, NemoOperationResult result) { GValue args[3] = { { 0, } }; GValue return_val = { 0, }; g_return_if_fail (update_complete != NULL); g_return_if_fail (NEMO_IS_INFO_PROVIDER (provider)); g_value_init (&args[0], NEMO_TYPE_INFO_PROVIDER); g_value_init (&args[1], G_TYPE_POINTER); g_value_init (&args[2], G_TYPE_INT); g_value_set_object (&args[0], provider); g_value_set_pointer (&args[1], handle); g_value_set_int (&args[2], result); g_closure_invoke (update_complete, &return_val, 3, args, NULL); g_value_unset (&args[0]); g_value_unset (&args[1]); g_value_unset (&args[2]); } nemo-4.4.2/libnemo-extension/nemo-info-provider.h000066400000000000000000000060361357442400300220150ustar00rootroot00000000000000/* * nemo-info-provider.h - Interface for Nemo extensions that * provide info about files. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ /* This interface is implemented by Nemo extensions that want to * provide information about files. Extensions are called when Nemo * needs information about a file. They are passed a NemoFileInfo * object which should be filled with relevant information */ #ifndef NEMO_INFO_PROVIDER_H #define NEMO_INFO_PROVIDER_H #include #include "nemo-extension-types.h" #include "nemo-file-info.h" G_BEGIN_DECLS #define NEMO_TYPE_INFO_PROVIDER (nemo_info_provider_get_type ()) G_DECLARE_INTERFACE (NemoInfoProvider, nemo_info_provider, NEMO, INFO_PROVIDER, GObject) typedef NemoInfoProviderInterface NemoInfoProviderIface; typedef void (*NemoInfoProviderUpdateComplete) (NemoInfoProvider *provider, NemoOperationHandle *handle, NemoOperationResult result, gpointer user_data); struct _NemoInfoProviderInterface { GTypeInterface g_iface; NemoOperationResult (*update_file_info) (NemoInfoProvider *provider, NemoFileInfo *file, GClosure *update_complete, NemoOperationHandle **handle); void (*cancel_update) (NemoInfoProvider *provider, NemoOperationHandle *handle); }; /* pre-G_DECLARE_INTERFACE/G_DEFINE_INTERFACE compatibility */ #define NemoInfoProviderIface NemoInfoProviderInterface /* Interface Functions */ NemoOperationResult nemo_info_provider_update_file_info (NemoInfoProvider *provider, NemoFileInfo *file, GClosure *update_complete, NemoOperationHandle **handle); void nemo_info_provider_cancel_update (NemoInfoProvider *provider, NemoOperationHandle *handle); /* Helper functions for implementations */ void nemo_info_provider_update_complete_invoke (GClosure *update_complete, NemoInfoProvider *provider, NemoOperationHandle *handle, NemoOperationResult result); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-location-widget-provider.c000066400000000000000000000046211357442400300241440ustar00rootroot00000000000000/* * nemo-location-widget-provider.c - Interface for Nemo extensions that provide extra widgets for a location * * Copyright (C) 2005 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #include #include "nemo-location-widget-provider.h" #include G_DEFINE_INTERFACE (NemoLocationWidgetProvider, nemo_location_widget_provider, G_TYPE_OBJECT) /** * SECTION:nemo-location-widget-provider * @Title: NemoLocationWidgetProvider * @Short_description: Allows a custom widget to be added to a Nemo view. * This is an interface to allow the provision of a custom location widget * embedded at the top of the Nemo view. It receives the current location, and * can then determine whether or not the location is appropriate for a widget, and * its contents. * * Be aware that this extension is queried for a new widget any time a view loads a * new location, or reloads the current one. **/ static void nemo_location_widget_provider_default_init (NemoLocationWidgetProviderInterface *klass) { } /** * nemo_location_widget_provider_get_widget: * @provider: a #NemoLocationWidgetProvider * @uri: the URI of the location * @window: parent #GtkWindow * * Returns: (transfer none): the location widget for @provider at @uri */ GtkWidget * nemo_location_widget_provider_get_widget (NemoLocationWidgetProvider *provider, const char *uri, GtkWidget *window) { g_return_val_if_fail (NEMO_IS_LOCATION_WIDGET_PROVIDER (provider), NULL); return NEMO_LOCATION_WIDGET_PROVIDER_GET_IFACE (provider)->get_widget (provider, uri, window); } nemo-4.4.2/libnemo-extension/nemo-location-widget-provider.h000066400000000000000000000043031357442400300241460ustar00rootroot00000000000000/* * nemo-info-provider.h - Interface for Nemo extensions that * provide info about files. * * Copyright (C) 2003 Novell, Inc. * Copyright (C) 2005 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * Alexander Larsson * */ /* This interface is implemented by Nemo extensions that want to * provide extra location widgets for a particular location. * Extensions are called when Nemo displays a location. */ #ifndef NEMO_LOCATION_WIDGET_PROVIDER_H #define NEMO_LOCATION_WIDGET_PROVIDER_H #include #include #include "nemo-extension-types.h" G_BEGIN_DECLS #define NEMO_TYPE_LOCATION_WIDGET_PROVIDER (nemo_location_widget_provider_get_type ()) G_DECLARE_INTERFACE (NemoLocationWidgetProvider, nemo_location_widget_provider, NEMO, LOCATION_WIDGET_PROVIDER, GObject) typedef NemoLocationWidgetProviderInterface NemoLocationWidgetProviderIface; struct _NemoLocationWidgetProviderInterface { GTypeInterface g_iface; GtkWidget * (*get_widget) (NemoLocationWidgetProvider *provider, const char *uri, GtkWidget *window); }; /* Interface Functions */ GtkWidget * nemo_location_widget_provider_get_widget (NemoLocationWidgetProvider *provider, const char *uri, GtkWidget *window); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-menu-item.c000066400000000000000000000306051357442400300211240ustar00rootroot00000000000000/* * nemo-menu-item.c - Menu items exported by NemoMenuProvider * objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-menu.h" #include "nemo-extension-i18n.h" enum { ACTIVATE, LAST_SIGNAL }; enum { PROP_0, PROP_NAME, PROP_LABEL, PROP_TIP, PROP_ICON, PROP_SENSITIVE, PROP_PRIORITY, PROP_MENU, PROP_WIDGET_A, PROP_WIDGET_B, PROP_SEPARATOR, LAST_PROP }; typedef struct { char *name; char *label; char *tip; char *icon; NemoMenu *menu; gboolean sensitive; gboolean priority; GtkWidget *widget_a; GtkWidget *widget_b; gboolean separator; } NemoMenuItemPrivate; struct _NemoMenuItem { GObject parent_class; NemoMenuItemPrivate *details; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoMenuItem, nemo_menu_item, G_TYPE_OBJECT) static guint signals[LAST_SIGNAL] = { 0 }; /** * nemo_menu_item_new: * @name: the identifier for the menu item * @label: the user-visible label of the menu item * @tip: the tooltip of the menu item * @icon: the name of the icon to display in the menu item * * Creates a new menu item that can be added to the toolbar or to a contextual menu. * * Returns: a newly create #NemoMenuItem */ NemoMenuItem * nemo_menu_item_new (const char *name, const char *label, const char *tip, const char *icon) { NemoMenuItem *item; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (label != NULL, NULL); g_return_val_if_fail (tip != NULL, NULL); item = g_object_new (NEMO_TYPE_MENU_ITEM, "name", name, "label", label, "tip", tip, "icon", icon, NULL); return item; } /** * nemo_menu_item_new_widget: * @name: the identifier for the menu item * @widget_a: the custom #GtkWidget to use for widget-a * @widget_b: the custom #GtkWidget to use for widget-b * * Creates a new widget-based menu item that can be added to the toolbar or to a contextual menu. * * Returns: a newly created #NemoMenuItem that will pass widgets to an eventual NemoWidgetAction */ NemoMenuItem * nemo_menu_item_new_widget (const char *name, GtkWidget *widget_a, GtkWidget *widget_b) { NemoMenuItem *item; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (widget_a != NULL, NULL); item = g_object_new (NEMO_TYPE_MENU_ITEM, "name", name, "widget-a", widget_a, "widget-b", widget_b, "label", NULL, "tip", NULL, "icon", NULL, NULL); return item; } /** * nemo_menu_item_new_separator: * @name: the identifier for the menu item * * Creates a new menu item that represents a menu separator. * * Returns: a newly created #NemoMenuItem */ NemoMenuItem * nemo_menu_item_new_separator (const char *name) { NemoMenuItem *item; g_return_val_if_fail (name != NULL, NULL); item = g_object_new (NEMO_TYPE_MENU_ITEM, "name", name, "separator", TRUE, NULL); return item; } /** * nemo_menu_item_activate: * @item: pointer to a #NemoMenuItem * * emits the activate signal. */ void nemo_menu_item_activate (NemoMenuItem *item) { g_signal_emit (item, signals[ACTIVATE], 0); } /** * nemo_menu_item_set_submenu: * @item: pointer to a #NemoMenuItem * @menu: pointer to a #NemoMenu to attach to the button * * Attachs a menu to the given #NemoMenuItem. */ void nemo_menu_item_set_submenu (NemoMenuItem *item, NemoMenu *menu) { g_object_set (item, "menu", menu, NULL); } /** * nemo_menu_item_set_widget_a: * @item: pointer to a #NemoMenuItem * @widget: pointer to a #GtkWidget use in place of text * * Sets the custom widget A for this #NemoMenuItem */ void nemo_menu_item_set_widget_a (NemoMenuItem *item, GtkWidget *widget) { g_object_set (item, "widget-a", widget, NULL); } /** * nemo_menu_item_set_widget_b: * @item: pointer to a #NemoMenuItem * @widget: pointer to a #GtkWidget use in place of text * * Sets the custom widget B for this #NemoMenuItem */ void nemo_menu_item_set_widget_b (NemoMenuItem *item, GtkWidget *widget) { g_object_set (item, "widget-b", widget, NULL); } static void nemo_menu_item_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { NemoMenuItem *item; item = NEMO_MENU_ITEM (object); switch (param_id) { case PROP_NAME : g_value_set_string (value, item->details->name); break; case PROP_LABEL : g_value_set_string (value, item->details->label); break; case PROP_TIP : g_value_set_string (value, item->details->tip); break; case PROP_ICON : g_value_set_string (value, item->details->icon); break; case PROP_SENSITIVE : g_value_set_boolean (value, item->details->sensitive); break; case PROP_PRIORITY : g_value_set_boolean (value, item->details->priority); break; case PROP_MENU : g_value_set_object (value, item->details->menu); break; case PROP_WIDGET_A : g_value_set_object (value, item->details->widget_a); break; case PROP_WIDGET_B : g_value_set_object (value, item->details->widget_b); break; case PROP_SEPARATOR: g_value_set_boolean (value, item->details->separator); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_menu_item_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { NemoMenuItem *item; item = NEMO_MENU_ITEM (object); switch (param_id) { case PROP_NAME : g_free (item->details->name); item->details->name = g_strdup (g_value_get_string (value)); g_object_notify (object, "name"); break; case PROP_LABEL : g_free (item->details->label); item->details->label = g_strdup (g_value_get_string (value)); g_object_notify (object, "label"); break; case PROP_TIP : g_free (item->details->tip); item->details->tip = g_strdup (g_value_get_string (value)); g_object_notify (object, "tip"); break; case PROP_ICON : g_free (item->details->icon); item->details->icon = g_strdup (g_value_get_string (value)); g_object_notify (object, "icon"); break; case PROP_SENSITIVE : item->details->sensitive = g_value_get_boolean (value); g_object_notify (object, "sensitive"); break; case PROP_PRIORITY : item->details->priority = g_value_get_boolean (value); g_object_notify (object, "priority"); break; case PROP_MENU : if (item->details->menu) { g_object_unref (item->details->menu); } item->details->menu = g_object_ref (g_value_get_object (value)); g_object_notify (object, "menu"); break; case PROP_WIDGET_A: if (item->details->widget_a) { g_object_unref (item->details->widget_a); } item->details->widget_a = g_object_ref (g_value_get_object (value)); g_object_notify (object, "widget-a"); break; case PROP_WIDGET_B: if (item->details->widget_b) { g_object_unref (item->details->widget_b); } item->details->widget_b = g_object_ref (g_value_get_object (value)); g_object_notify (object, "widget-b"); break; case PROP_SEPARATOR: item->details->separator = g_value_get_boolean (value); g_object_notify (object, "separator"); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_menu_item_finalize (GObject *object) { NemoMenuItem *item; item = NEMO_MENU_ITEM (object); g_free (item->details->name); g_free (item->details->label); g_free (item->details->tip); g_free (item->details->icon); if (item->details->menu) { g_object_unref (item->details->menu); } if (item->details->widget_a) { g_object_unref (item->details->widget_a); } if (item->details->widget_b) { g_object_unref (item->details->widget_b); } G_OBJECT_CLASS (nemo_menu_item_parent_class)->finalize (object); } static void nemo_menu_item_init (NemoMenuItem *item) { item->details = G_TYPE_INSTANCE_GET_PRIVATE (item, NEMO_TYPE_MENU_ITEM, NemoMenuItemPrivate); item->details->sensitive = TRUE; item->details->menu = NULL; item->details->widget_a = NULL; item->details->widget_b = NULL; item->details->separator = FALSE; } static void nemo_menu_item_class_init (NemoMenuItemClass *class) { G_OBJECT_CLASS (class)->finalize = nemo_menu_item_finalize; G_OBJECT_CLASS (class)->get_property = nemo_menu_item_get_property; G_OBJECT_CLASS (class)->set_property = nemo_menu_item_set_property; signals[ACTIVATE] = g_signal_new ("activate", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_NAME, g_param_spec_string ("name", "Name", "Name of the item", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_LABEL, g_param_spec_string ("label", "Label", "Label to display to the user", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_TIP, g_param_spec_string ("tip", "Tip", "Tooltip for the menu item", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_ICON, g_param_spec_string ("icon", "Icon", "Name of the icon to display in the menu item", NULL, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_SENSITIVE, g_param_spec_boolean ("sensitive", "Sensitive", "Whether the menu item is sensitive", TRUE, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_PRIORITY, g_param_spec_boolean ("priority", "Priority", "Show priority text in toolbars", TRUE, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_MENU, g_param_spec_object ("menu", "Menu", "The menu belonging to this item. May be null.", NEMO_TYPE_MENU, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_WIDGET_A, g_param_spec_object ("widget-a", "Widget A", "The custom widget to use in place of text", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_WIDGET_B, g_param_spec_object ("widget-b", "Widget B", "The custom widget to use in place of text", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_SEPARATOR, g_param_spec_boolean ("separator", "Separator", "Is a separator", FALSE, G_PARAM_READWRITE)); } nemo-4.4.2/libnemo-extension/nemo-menu-item.h000066400000000000000000000017761357442400300211400ustar00rootroot00000000000000/* * nemo-menu-item.h - Menu items exported by NemoMenuProvider * objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #ifndef NEMO_MENU_ITEM_H #define NEMO_MENU_ITEM_H #include "nemo-menu.h" #endif nemo-4.4.2/libnemo-extension/nemo-menu-provider.c000066400000000000000000000072121357442400300220160ustar00rootroot00000000000000/* * nemo-property-page-provider.c - Interface for Nemo extensions * that provide context menu items * for files. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-menu-provider.h" #include G_DEFINE_INTERFACE (NemoMenuProvider, nemo_menu_provider, G_TYPE_OBJECT) /** * SECTION:nemo-menu-provider * @Title: NemoMenuProvider * @Short_description: Allows additional menu items to be added to context menus. * * This interface allows custom menu entries to be inserted in the selection and * background context menus. Submenus and separators can also be generated. * **/ static void nemo_menu_provider_default_init (NemoMenuProviderInterface *klass) { static gboolean initialized = FALSE; if (!initialized) { /* This signal should be emited each time the extension modify the list of menu items */ g_signal_new ("items_updated", NEMO_TYPE_MENU_PROVIDER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); initialized = TRUE; } } /** * nemo_menu_provider_get_file_items: * @provider: a #NemoMenuProvider * @window: the parent #GtkWidget window * @files: (element-type NemoFileInfo): a list of #NemoFileInfo * * Returns: (element-type NemoMenuItem) (transfer full): the provided list of #NemoMenuItem */ GList * nemo_menu_provider_get_file_items (NemoMenuProvider *provider, GtkWidget *window, GList *files) { g_return_val_if_fail (NEMO_IS_MENU_PROVIDER (provider), NULL); if (NEMO_MENU_PROVIDER_GET_IFACE (provider)->get_file_items) { return NEMO_MENU_PROVIDER_GET_IFACE (provider)->get_file_items (provider, window, files); } else { return NULL; } } /** * nemo_menu_provider_get_background_items: * @provider: a #NemoMenuProvider * @window: the parent #GtkWidget window * @current_folder: the folder for which background items are requested * * Returns: (element-type NemoMenuItem) (transfer full): the provided list of #NemoMenuItem */ GList * nemo_menu_provider_get_background_items (NemoMenuProvider *provider, GtkWidget *window, NemoFileInfo *current_folder) { g_return_val_if_fail (NEMO_IS_MENU_PROVIDER (provider), NULL); g_return_val_if_fail (NEMO_IS_FILE_INFO (current_folder), NULL); if (NEMO_MENU_PROVIDER_GET_IFACE (provider)->get_background_items) { return NEMO_MENU_PROVIDER_GET_IFACE (provider)->get_background_items (provider, window, current_folder); } else { return NULL; } } /* This function emit a signal to inform nemo that its item list has changed */ void nemo_menu_provider_emit_items_updated_signal (NemoMenuProvider* provider) { g_return_if_fail (NEMO_IS_MENU_PROVIDER (provider)); g_signal_emit_by_name (provider, "items_updated"); } nemo-4.4.2/libnemo-extension/nemo-menu-provider.h000066400000000000000000000051031357442400300220200ustar00rootroot00000000000000/* * nemo-menu-provider.h - Interface for Nemo extensions that * provide context menu items. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ /* This interface is implemented by Nemo extensions that want to * add context menu entries to files. Extensions are called when * Nemo constructs the context menu for a file. They are passed a * list of NemoFileInfo objects which holds the current selection */ #ifndef NEMO_MENU_PROVIDER_H #define NEMO_MENU_PROVIDER_H #include #include #include "nemo-extension-types.h" #include "nemo-file-info.h" #include "nemo-menu.h" G_BEGIN_DECLS #define NEMO_TYPE_MENU_PROVIDER (nemo_menu_provider_get_type ()) G_DECLARE_INTERFACE (NemoMenuProvider, nemo_menu_provider, NEMO, MENU_PROVIDER, GObject) typedef NemoMenuProviderInterface NemoMenuProviderIface; struct _NemoMenuProviderInterface { GTypeInterface g_iface; GList *(*get_file_items) (NemoMenuProvider *provider, GtkWidget *window, GList *files); GList *(*get_background_items) (NemoMenuProvider *provider, GtkWidget *window, NemoFileInfo *current_folder); }; /* Interface Functions */ GList *nemo_menu_provider_get_file_items (NemoMenuProvider *provider, GtkWidget *window, GList *files); GList *nemo_menu_provider_get_background_items (NemoMenuProvider *provider, GtkWidget *window, NemoFileInfo *current_folder); /* This function emit a signal to inform nemo that its item list has changed. */ void nemo_menu_provider_emit_items_updated_signal (NemoMenuProvider *provider); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-menu.c000066400000000000000000000061471357442400300201740ustar00rootroot00000000000000/* * nemo-menu.h - Menus exported by NemoMenuProvider objects. * * Copyright (C) 2005 Raffaele Sandrini * * 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, Suite 500, MA 02110-1335, USA. * * Author: Raffaele Sandrini * */ #include #include "nemo-menu.h" #include "nemo-extension-i18n.h" #include typedef struct { GList *item_list; } NemoMenuPrivate; struct _NemoMenu { GObject parent_class; NemoMenuPrivate *priv; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoMenu, nemo_menu, G_TYPE_OBJECT) /** * SECTION:nemo-menu * @Title: NemoMenu * @Short_description: A menu added to Nemo's context menus by an extension * * Menu items and submenus can be added to Nemo's selected item and background * context menus by a #NemoMenuProvider. Separators and embedded widgets are also * possible (see #NemoSimpleButton.) **/ void nemo_menu_append_item (NemoMenu *menu, NemoMenuItem *item) { g_return_if_fail (menu != NULL); g_return_if_fail (item != NULL); menu->priv->item_list = g_list_append (menu->priv->item_list, g_object_ref (item)); } /** * nemo_menu_get_items: * @menu: a #NemoMenu * * Returns: (element-type NemoMenuItem) (transfer full): the provided #NemoMenuItem list */ GList * nemo_menu_get_items (NemoMenu *menu) { GList *item_list; g_return_val_if_fail (menu != NULL, NULL); item_list = g_list_copy (menu->priv->item_list); g_list_foreach (item_list, (GFunc)g_object_ref, NULL); return item_list; } /** * nemo_menu_item_list_free: * @item_list: (element-type NemoMenuItem): a list of #NemoMenuItem * */ void nemo_menu_item_list_free (GList *item_list) { g_return_if_fail (item_list != NULL); g_list_foreach (item_list, (GFunc)g_object_unref, NULL); g_list_free (item_list); } /* Type initialization */ static void nemo_menu_finalize (GObject *object) { NemoMenu *menu = NEMO_MENU (object); if (menu->priv->item_list) { g_list_free (menu->priv->item_list); } G_OBJECT_CLASS (nemo_menu_parent_class)->finalize (object); } static void nemo_menu_init (NemoMenu *menu) { menu->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu, NEMO_TYPE_MENU, NemoMenuPrivate); menu->priv->item_list = NULL; } static void nemo_menu_class_init (NemoMenuClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = nemo_menu_finalize; } /* public constructors */ NemoMenu * nemo_menu_new (void) { NemoMenu *obj; obj = NEMO_MENU (g_object_new (NEMO_TYPE_MENU, NULL)); return obj; } nemo-4.4.2/libnemo-extension/nemo-menu.h000066400000000000000000000060531357442400300201750ustar00rootroot00000000000000/* * nemo-menu.h - Menus exported by NemoMenuProvider objects. * * Copyright (C) 2005 Raffaele Sandrini * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * Raffaele Sandrini * */ #ifndef NEMO_MENU_H #define NEMO_MENU_H #include #include #include "nemo-extension-types.h" G_BEGIN_DECLS /* NemoMenu defines */ #define NEMO_TYPE_MENU nemo_menu_get_type () G_DECLARE_FINAL_TYPE (NemoMenu, nemo_menu, NEMO, MENU, GObject) /* NemoMenuItem defines */ #define NEMO_TYPE_MENU_ITEM nemo_menu_item_get_type() G_DECLARE_FINAL_TYPE (NemoMenuItem, nemo_menu_item, NEMO, MENU_ITEM, GObject) /* NemoMenu methods */ NemoMenu * nemo_menu_new (void); void nemo_menu_append_item (NemoMenu *menu, NemoMenuItem *item); GList* nemo_menu_get_items (NemoMenu *menu); void nemo_menu_item_list_free (GList *item_list); /* NemoMenuItem methods */ NemoMenuItem *nemo_menu_item_new (const char *name, const char *label, const char *tip, const char *icon); NemoMenuItem *nemo_menu_item_new_widget (const char *name, GtkWidget *widget_a, GtkWidget *widget_b); NemoMenuItem *nemo_menu_item_new_separator (const char *name); void nemo_menu_item_set_widget_a (NemoMenuItem *item, GtkWidget *widget); void nemo_menu_item_set_widget_b (NemoMenuItem *item, GtkWidget *widget); void nemo_menu_item_activate (NemoMenuItem *item); void nemo_menu_item_set_submenu (NemoMenuItem *item, NemoMenu *menu); /* NemoMenuItem has the following properties: * name (string) - the identifier for the menu item * label (string) - the user-visible label of the menu item * tip (string) - the tooltip of the menu item * icon (string) - the name of the icon to display in the menu item * sensitive (boolean) - whether the menu item is sensitive or not * priority (boolean) - used for toolbar items, whether to show priority * text. * menu (NemoMenu) - The menu belonging to this item. May be null. * widget (GtkWidget) - The optional widget to use in place of a normal menu entr */ G_END_DECLS #endif /* NEMO_MENU_H */ nemo-4.4.2/libnemo-extension/nemo-name-and-desc-provider.c000066400000000000000000000022371357442400300234500ustar00rootroot00000000000000/* * nemo-name-and-desc-provider.c - Interface for Nemo extensions that * returns the extension's proper name and description for the plugin * manager only - it is not necessary for extension functionality. * */ #include #include "nemo-name-and-desc-provider.h" #include static void nemo_name_and_desc_provider_default_init (NemoNameAndDescProviderInterface *klass) { } G_DEFINE_INTERFACE (NemoNameAndDescProvider, nemo_name_and_desc_provider, G_TYPE_OBJECT) /** * nemo_name_and_desc_provider_get_name_and_desc: * @provider: a #NemoNameAndDescProvider * * Returns: (element-type gchar) (transfer full): a list of name:::desc * strings. Optionally, the name of a path executable can be appended as a * third component of the list ('name:::desc:::foo-bar-preferences') */ GList * nemo_name_and_desc_provider_get_name_and_desc (NemoNameAndDescProvider *provider) { g_return_val_if_fail (NEMO_IS_NAME_AND_DESC_PROVIDER (provider), NULL); g_return_val_if_fail (NEMO_NAME_AND_DESC_PROVIDER_GET_IFACE (provider)->get_name_and_desc != NULL, NULL); return NEMO_NAME_AND_DESC_PROVIDER_GET_IFACE (provider)->get_name_and_desc (provider); } nemo-4.4.2/libnemo-extension/nemo-name-and-desc-provider.h000066400000000000000000000017111357442400300234510ustar00rootroot00000000000000/* * nemo-name-and-desc-provider.h - Interface for Nemo extensions that * returns the extension's proper name and description for the plugin * manager only - it is not necessary for extension functionality. * */ #ifndef NEMO_NAME_AND_DESC_PROVIDER_H #define NEMO_NAME_AND_DESC_PROVIDER_H #include #include "nemo-extension-types.h" G_BEGIN_DECLS #define NEMO_TYPE_NAME_AND_DESC_PROVIDER (nemo_name_and_desc_provider_get_type ()) G_DECLARE_INTERFACE (NemoNameAndDescProvider, nemo_name_and_desc_provider, NEMO, NAME_AND_DESC_PROVIDER, GObject) typedef NemoNameAndDescProviderInterface NemoNameAndDescProviderIface; struct _NemoNameAndDescProviderInterface { GTypeInterface g_iface; GList *(*get_name_and_desc) (NemoNameAndDescProvider *provider); }; /* Interface Functions */ GList *nemo_name_and_desc_provider_get_name_and_desc (NemoNameAndDescProvider *provider); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-property-page-provider.c000066400000000000000000000047171357442400300236570ustar00rootroot00000000000000/* * nemo-property-page-provider.c - Interface for Nemo extensions * that provide property pages for * files. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-property-page-provider.h" #include G_DEFINE_INTERFACE (NemoPropertyPageProvider, nemo_property_page_provider, G_TYPE_OBJECT) /** * SECTION:nemo-property-page-provider * @Title: NemoPropertyPageProvider * @Short_description: Allows additional file property pages to be added. * * This interface allows you to provide additional property pages for the right-click * Properties menu item. A new widget is requested each time the property page is opened. **/ static void nemo_property_page_provider_default_init (NemoPropertyPageProviderInterface *klass) { } /** * nemo_property_page_provider_get_pages: * @provider: a #NemoPropertyPageProvider * @files: (element-type NemoFileInfo): a #GList of #NemoFileInfo * * This function is called by Nemo when it wants property page * items from the extension. * * This function is called in the main thread before a property page * is shown, so it should return quickly. * * Returns: (element-type NemoPropertyPage) (transfer full): A #GList of allocated #NemoPropertyPage items. */ GList * nemo_property_page_provider_get_pages (NemoPropertyPageProvider *provider, GList *files) { g_return_val_if_fail (NEMO_IS_PROPERTY_PAGE_PROVIDER (provider), NULL); g_return_val_if_fail (NEMO_PROPERTY_PAGE_PROVIDER_GET_IFACE (provider)->get_pages != NULL, NULL); return NEMO_PROPERTY_PAGE_PROVIDER_GET_IFACE (provider)->get_pages (provider, files); } nemo-4.4.2/libnemo-extension/nemo-property-page-provider.h000066400000000000000000000041741357442400300236610ustar00rootroot00000000000000/* * nemo-property-page-provider.h - Interface for Nemo extensions * that provide property pages. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ /* This interface is implemented by Nemo extensions that want to * add property page to property dialogs. Extensions are called when * Nemo needs property pages for a selection. They are passed a * list of NemoFileInfo objects for which information should * be displayed */ #ifndef NEMO_PROPERTY_PAGE_PROVIDER_H #define NEMO_PROPERTY_PAGE_PROVIDER_H #include #include "nemo-extension-types.h" #include "nemo-file-info.h" #include "nemo-property-page.h" G_BEGIN_DECLS #define NEMO_TYPE_PROPERTY_PAGE_PROVIDER (nemo_property_page_provider_get_type ()) G_DECLARE_INTERFACE (NemoPropertyPageProvider, nemo_property_page_provider, NEMO, PROPERTY_PAGE_PROVIDER, GObject) typedef NemoPropertyPageProviderInterface NemoPropertyPageProviderIface; struct _NemoPropertyPageProviderInterface { GTypeInterface g_iface; GList *(*get_pages) (NemoPropertyPageProvider *provider, GList *files); }; /* Interface Functions */ GList *nemo_property_page_provider_get_pages (NemoPropertyPageProvider *provider, GList *files); G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-property-page.c000066400000000000000000000133231357442400300220200ustar00rootroot00000000000000/* * nemo-property-page.h - Property pages exported by * NemoPropertyProvider objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-property-page.h" #include "nemo-extension-i18n.h" enum { PROP_0, PROP_NAME, PROP_LABEL, PROP_PAGE, LAST_PROP }; typedef struct { char *name; GtkWidget *label; GtkWidget *page; } NemoPropertyPagePrivate; struct _NemoPropertyPage { GObject parent_object; NemoPropertyPagePrivate *details; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoPropertyPage, nemo_property_page, G_TYPE_OBJECT) /** * SECTION:nemo-property-page * @Title: NemoPropertyPage * @Short_description: A widget that can display additional info about a file. * * Additional stack pages for a file's properties window can be provided by a * #NemoPropertyPageProvider. An appropriate parent #GtkWidget is created (usually * a container type,) along with a label for the stack switcher. **/ /** * nemo_property_page_new: * @name: the identifier for the property page * @label: the user-visible label of the property page * @page: the property page to display * * Creates a new #NemoPropertyPage from page_widget. * * Returns: a newly created #NemoPropertyPage */ NemoPropertyPage * nemo_property_page_new (const char *name, GtkWidget *label, GtkWidget *page_widget) { NemoPropertyPage *page; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (label != NULL && GTK_IS_WIDGET (label), NULL); g_return_val_if_fail (page_widget != NULL && GTK_IS_WIDGET (page_widget), NULL); page = g_object_new (NEMO_TYPE_PROPERTY_PAGE, "name", name, "label", label, "page", page_widget, NULL); return page; } static void nemo_property_page_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { NemoPropertyPage *page; page = NEMO_PROPERTY_PAGE (object); switch (param_id) { case PROP_NAME : g_value_set_string (value, page->details->name); break; case PROP_LABEL : g_value_set_object (value, page->details->label); break; case PROP_PAGE : g_value_set_object (value, page->details->page); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_property_page_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { NemoPropertyPage *page; page = NEMO_PROPERTY_PAGE (object); switch (param_id) { case PROP_NAME : g_free (page->details->name); page->details->name = g_strdup (g_value_get_string (value)); g_object_notify (object, "name"); break; case PROP_LABEL : if (page->details->label) { g_object_unref (page->details->label); } page->details->label = g_object_ref (g_value_get_object (value)); g_object_notify (object, "label"); break; case PROP_PAGE : if (page->details->page) { g_object_unref (page->details->page); } page->details->page = g_object_ref (g_value_get_object (value)); g_object_notify (object, "page"); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_property_page_dispose (GObject *object) { NemoPropertyPage *page; page = NEMO_PROPERTY_PAGE (object); if (page->details->label) { g_object_unref (page->details->label); page->details->label = NULL; } if (page->details->page) { g_object_unref (page->details->page); page->details->page = NULL; } } static void nemo_property_page_finalize (GObject *object) { NemoPropertyPage *page; page = NEMO_PROPERTY_PAGE (object); g_free (page->details->name); G_OBJECT_CLASS (nemo_property_page_parent_class)->finalize (object); } static void nemo_property_page_init (NemoPropertyPage *page) { page->details = G_TYPE_INSTANCE_GET_PRIVATE (page, NEMO_TYPE_PROPERTY_PAGE, NemoPropertyPagePrivate); } static void nemo_property_page_class_init (NemoPropertyPageClass *class) { G_OBJECT_CLASS (class)->finalize = nemo_property_page_finalize; G_OBJECT_CLASS (class)->dispose = nemo_property_page_dispose; G_OBJECT_CLASS (class)->get_property = nemo_property_page_get_property; G_OBJECT_CLASS (class)->set_property = nemo_property_page_set_property; g_object_class_install_property (G_OBJECT_CLASS (class), PROP_NAME, g_param_spec_string ("name", "Name", "Name of the page", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_LABEL, g_param_spec_object ("label", "Label", "Label widget to display in the notebook tab", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (class), PROP_PAGE, g_param_spec_object ("page", "Page", "Widget for the property page", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); } nemo-4.4.2/libnemo-extension/nemo-property-page.h000066400000000000000000000033611357442400300220260ustar00rootroot00000000000000/* * nemo-property-page.h - Property pages exported by * NemoPropertyProvider objects. * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #ifndef NEMO_PROPERTY_PAGE_H #define NEMO_PROPERTY_PAGE_H #include #include #include "nemo-extension-types.h" G_BEGIN_DECLS #define NEMO_TYPE_PROPERTY_PAGE nemo_property_page_get_type() G_DECLARE_FINAL_TYPE (NemoPropertyPage, nemo_property_page, NEMO, PROPERTY_PAGE, GObject) NemoPropertyPage *nemo_property_page_new (const char *name, GtkWidget *label, GtkWidget *page); /* NemoPropertyPage has the following properties: * name (string) - the identifier for the property page * label (widget) - the user-visible label of the property page * page (widget) - the property page to display */ G_END_DECLS #endif nemo-4.4.2/libnemo-extension/nemo-simple-button.c000066400000000000000000000052451357442400300220300ustar00rootroot00000000000000/* nemo-simple-button.c */ #include #include "nemo-simple-button.h" #include struct _NemoSimpleButton { GtkButton parent_object; }; G_DEFINE_TYPE (NemoSimpleButton, nemo_simple_button, GTK_TYPE_BUTTON) /** * SECTION:nemo-simple-button * @Title: NemoSimpleButton * @Short_description: A stripped down #GtkButton for embedding in menu items. * * This button class is intended to be used in a #NemoMenuItem to allow some * advanced functionality within a single item row. **/ static gboolean nemo_simple_button_button_release (GtkWidget *widget, GdkEventButton *event) { g_signal_emit_by_name (GTK_BUTTON (widget), "released"); return GDK_EVENT_PROPAGATE; } static void nemo_simple_button_class_init (NemoSimpleButtonClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass*) klass; widget_class->button_release_event = nemo_simple_button_button_release; } static void nemo_simple_button_init (NemoSimpleButton *self) { GtkStyleContext *context; context = gtk_widget_get_style_context (GTK_WIDGET (self)); gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BUTTON); } NemoSimpleButton * nemo_simple_button_new (void) { return g_object_new (NEMO_TYPE_SIMPLE_BUTTON, NULL); } NemoSimpleButton * nemo_simple_button_new_from_icon_name (const gchar *icon_name, int icon_size) { GtkWidget *w, *image; w = g_object_new (NEMO_TYPE_SIMPLE_BUTTON, NULL); image = gtk_image_new_from_icon_name (icon_name, icon_size); gtk_button_set_image (GTK_BUTTON (w), image); return NEMO_SIMPLE_BUTTON (w); } NemoSimpleButton * nemo_simple_button_new_from_stock (const gchar *stock_id, int icon_size) { GtkWidget *w, *image; w = g_object_new (NEMO_TYPE_SIMPLE_BUTTON, NULL); image = gtk_image_new_from_stock (stock_id, icon_size); gtk_button_set_image (GTK_BUTTON (w), image); return NEMO_SIMPLE_BUTTON (w); } NemoSimpleButton * nemo_simple_button_new_from_file (const gchar *path, int icon_size) { GtkWidget *w, *image; GdkPixbuf *pixbuf = NULL; cairo_surface_t *surface = NULL; gint width, height; gint scale = 1; gtk_icon_size_lookup (icon_size, &width, &height); w = g_object_new (NEMO_TYPE_SIMPLE_BUTTON, NULL); scale = gtk_widget_get_scale_factor (w); pixbuf = gdk_pixbuf_new_from_file_at_size (path, width * scale, height * scale, NULL); if (pixbuf) { surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL); g_object_unref (pixbuf); } if (surface) { image = gtk_image_new (); g_object_set (image, "surface", surface, NULL); gtk_button_set_image (GTK_BUTTON (w), image); } return NEMO_SIMPLE_BUTTON (w); }nemo-4.4.2/libnemo-extension/nemo-simple-button.h000066400000000000000000000013241357442400300220270ustar00rootroot00000000000000/* nemo-simple-button.h */ #ifndef __NEMO_SIMPLE_BUTTON_H__ #define __NEMO_SIMPLE_BUTTON_H__ #include #include #include "nemo-extension-types.h" G_BEGIN_DECLS #define NEMO_TYPE_SIMPLE_BUTTON nemo_simple_button_get_type() G_DECLARE_FINAL_TYPE (NemoSimpleButton, nemo_simple_button, NEMO, SIMPLE_BUTTON, GtkButton) NemoSimpleButton *nemo_simple_button_new (void); NemoSimpleButton *nemo_simple_button_new_from_icon_name (const gchar *icon_name, int icon_size); NemoSimpleButton *nemo_simple_button_new_from_stock (const gchar *stock_id, int icon_size); NemoSimpleButton *nemo_simple_button_new_from_file (const gchar *path, int icon_size); G_END_DECLS #endif /* __NEMO_SIMPLE_BUTTON_H__ */ nemo-4.4.2/libnemo-private/000077500000000000000000000000001357442400300155565ustar00rootroot00000000000000nemo-4.4.2/libnemo-private/README000066400000000000000000000006771357442400300164500ustar00rootroot00000000000000README for nemo/libnemo-private This library, libnemo-private, is totally private to nemo. If you are writing a nemo component, you should not use this library or link with it. The code in here is internal to nemo and not available for public consumption. If you think that there is something interesting in this library that you would like to use in a third party component, please send mail to the nemo mailing list at: nemo-list@gnome.org nemo-4.4.2/libnemo-private/meson.build000066400000000000000000000054551357442400300177310ustar00rootroot00000000000000 dbusBuiltSources = gnome.gdbus_codegen('nemo-generated', join_paths(meson.source_root(), 'data', 'dbus-interfaces.xml'), interface_prefix: 'org.Nemo.', namespace: 'NemoDBus', object_manager: true ) nemo_private_sources = [ dbusBuiltSources, 'nemo-action-manager.c', 'nemo-action.c', 'nemo-bookmark.c', 'nemo-cell-renderer-disk.c', 'nemo-centered-placement-grid.c', 'nemo-clipboard-monitor.c', 'nemo-clipboard.c', 'nemo-column-chooser.c', 'nemo-column-utilities.c', 'nemo-dbus-manager.c', 'nemo-debug.c', 'nemo-default-file-icon.c', 'nemo-desktop-directory-file.c', 'nemo-desktop-directory.c', 'nemo-desktop-icon-file.c', 'nemo-desktop-link-monitor.c', 'nemo-desktop-link.c', 'nemo-desktop-metadata.c', 'nemo-desktop-utils.c', 'nemo-directory-async.c', 'nemo-directory.c', 'nemo-dnd.c', 'nemo-entry.c', 'nemo-file-changes-queue.c', 'nemo-file-conflict-dialog.c', 'nemo-file-dnd.c', 'nemo-file-operations.c', 'nemo-file-queue.c', 'nemo-file-undo-manager.c', 'nemo-file-undo-operations.c', 'nemo-file-utilities.c', 'nemo-file.c', 'nemo-global-preferences.c', 'nemo-icon-canvas-item.c', 'nemo-icon-container.c', 'nemo-icon-dnd.c', 'nemo-icon-info.c', 'nemo-job-queue.c', 'nemo-lib-self-check-functions.c', 'nemo-link.c', 'nemo-merged-directory.c', 'nemo-metadata.c', 'nemo-mime-application-chooser.c', 'nemo-module.c', 'nemo-monitor.c', 'nemo-placement-grid.c', 'nemo-places-tree-view.c', 'nemo-program-choosing.c', 'nemo-progress-info-manager.c', 'nemo-progress-info.c', 'nemo-query.c', 'nemo-recent.c', 'nemo-saved-search-file.c', 'nemo-search-directory-file.c', 'nemo-search-directory.c', 'nemo-search-engine-simple.c', 'nemo-search-engine.c', 'nemo-selection-canvas-item.c', 'nemo-separator-action.c', 'nemo-signaller.c', 'nemo-statx.c', 'nemo-thumbnails.c', 'nemo-trash-monitor.c', 'nemo-tree-view-drag-dest.c', 'nemo-ui-utilities.c', 'nemo-undo-manager.c', 'nemo-undo-signal-handlers.c', 'nemo-undo-transaction.c', 'nemo-undo.c', 'nemo-vfs-directory.c', 'nemo-vfs-file.c', 'nemo-widget-action.c', 'nemo-widget-menu-item.c', ] nemo_private_deps = [ cinnamon, eel, gail, glib, gmodule, gtk, libxml, math, nemo_extension, x11, ] if libexif_enabled nemo_private_deps += libexif endif if libselinux_enabled nemo_private_deps += libselinux endif nemo_private_lib = static_library('nemo-private', nemo_private_sources, dependencies: nemo_private_deps, include_directories: [ rootInclude, ], c_args: nemo_definitions, ) nemo_private = declare_dependency( include_directories: include_directories('.'), link_with: [ nemo_private_lib ], dependencies: nemo_private_deps, ) install_data('org.nemo.gschema.xml', install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas') ) nemo-4.4.2/libnemo-private/nemo-action-manager.c000066400000000000000000000264251357442400300215540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-action-manager.h" #include "nemo-directory.h" #include "nemo-action.h" #include #define DEBUG_FLAG NEMO_DEBUG_ACTIONS #include #include "nemo-file-utilities.h" G_DEFINE_TYPE (NemoActionManager, nemo_action_manager, G_TYPE_OBJECT); static void set_up_actions (NemoActionManager *action_manager); static void nemo_action_manager_constructed (GObject *object); static void nemo_action_manager_dispose (GObject *gobject); static void nemo_action_manager_finalize (GObject *gobject); static gpointer parent_class; enum { PROP_0, PROP_CONDITIONS }; enum { CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void actions_added_or_changed (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoActionManager *action_manager; action_manager = NEMO_ACTION_MANAGER (callback_data); action_manager->action_list_dirty = TRUE; set_up_actions (action_manager); } static void plugin_prefs_changed (GSettings *settings, gchar *key, gpointer user_data) { actions_added_or_changed (NULL, NULL, user_data); } static void add_directory_to_directory_list (NemoActionManager *action_manager, NemoDirectory *directory, GList **directory_list, GCallback changed_callback) { NemoFileAttributes attributes; if (g_list_find (*directory_list, directory) == NULL) { nemo_directory_ref (directory); attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT; nemo_directory_file_monitor_add (directory, directory_list, FALSE, attributes, (NemoDirectoryCallback)changed_callback, action_manager); g_signal_connect_object (directory, "files_added", G_CALLBACK (changed_callback), action_manager, 0); g_signal_connect_object (directory, "files_changed", G_CALLBACK (changed_callback), action_manager, 0); *directory_list = g_list_append (*directory_list, directory); } } static void remove_directory_from_directory_list (NemoActionManager *action_manager, NemoDirectory *directory, GList **directory_list, GCallback changed_callback) { *directory_list = g_list_remove (*directory_list, directory); g_signal_handlers_disconnect_by_func (directory, G_CALLBACK (changed_callback), action_manager); nemo_directory_file_monitor_remove (directory, directory_list); nemo_directory_unref (directory); } static void add_directory_to_actions_directory_list (NemoActionManager *action_manager, NemoDirectory *directory) { add_directory_to_directory_list (action_manager, directory, &action_manager->actions_directory_list, G_CALLBACK (actions_added_or_changed)); } static void remove_directory_from_actions_directory_list (NemoActionManager *action_manager, NemoDirectory *directory) { remove_directory_from_directory_list (action_manager, directory, &action_manager->actions_directory_list, G_CALLBACK (actions_added_or_changed)); } static void set_up_actions_directories (NemoActionManager *action_manager) { NemoDirectory *dir; gchar *path, *uri; gchar **data_dirs; guint i; data_dirs = (gchar **) g_get_system_data_dirs (); for (i = 0; i < g_strv_length (data_dirs); i++) { path = g_build_filename (data_dirs[i], "nemo", "actions", NULL); uri = g_filename_to_uri (path, NULL, NULL); dir = nemo_directory_get_by_uri (uri); add_directory_to_actions_directory_list (action_manager, dir); nemo_directory_unref (dir); g_clear_pointer (&path, g_free); g_clear_pointer (&uri, g_free); } path = nemo_action_manager_get_user_directory_path (); uri = g_filename_to_uri (path, NULL, NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) { g_mkdir_with_parents (path, DEFAULT_NEMO_DIRECTORY_MODE); } dir = nemo_directory_get_by_uri (uri); add_directory_to_actions_directory_list (action_manager, dir); nemo_directory_unref (dir); g_clear_pointer (&path, g_free); g_clear_pointer (&uri, g_free); } static char * escape_action_name (const char *action_name, const char *prefix) { GString *s; if (action_name == NULL) { return NULL; } s = g_string_new (prefix); while (*action_name != 0) { switch (*action_name) { case '\\': g_string_append (s, "\\\\"); break; case '/': g_string_append (s, "\\s"); break; case '&': g_string_append (s, "\\a"); break; case '"': g_string_append (s, "\\q"); break; default: g_string_append_c (s, *action_name); } action_name ++; } return g_string_free (s, FALSE); } static void on_action_condition_changed (NemoActionManager *action_manager) { DEBUG ("Action manager (%p) received action condition changed. Sending our own changed.", action_manager); g_signal_emit (action_manager, signals[CHANGED], 0); } static void add_action_to_action_list (NemoActionManager *action_manager, NemoFile *file) { gchar *uri; gchar *action_name; NemoAction *action; uri = nemo_file_get_uri (file); action_name = escape_action_name (uri, "action_"); gchar *path = g_filename_from_uri (uri, NULL, NULL); action = nemo_action_new (action_name, path); g_free (path); g_free (uri); g_free (action_name); if (action == NULL) { return; } g_signal_connect_swapped (action, "condition-changed", G_CALLBACK (on_action_condition_changed), action_manager); action_manager->actions = g_list_append (action_manager->actions, action); } static void void_action_list (NemoActionManager *action_manager) { GList *tmp = action_manager->actions; action_manager->actions = NULL; g_list_free_full (tmp, g_object_unref); } static void set_up_actions (NemoActionManager *action_manager) { GList *dir, *file_list, *node; NemoFile *file; NemoDirectory *directory; if (g_list_length (action_manager->actions) > 0) void_action_list (action_manager); for (dir = action_manager->actions_directory_list; dir != NULL; dir = dir->next) { directory = dir->data; file_list = nemo_directory_get_file_list (directory); for (node = file_list; node != NULL; node = node->next) { file = node->data; if (!g_str_has_suffix (nemo_file_peek_name (file), ".nemo_action") || !nemo_global_preferences_should_load_plugin (nemo_file_peek_name (file), NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS)) continue; add_action_to_action_list (action_manager, file); } nemo_file_list_free (file_list); } action_manager->action_list_dirty = FALSE; g_signal_emit (action_manager, signals[CHANGED], 0); } static void nemo_action_manager_init (NemoActionManager *action_manager) { action_manager->actions = NULL; action_manager->actions_directory_list = NULL; action_manager->action_list_dirty = TRUE; } static void nemo_action_manager_class_init (NemoActionManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = nemo_action_manager_finalize; object_class->dispose = nemo_action_manager_dispose; object_class->constructed = nemo_action_manager_constructed; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoActionManagerClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } void nemo_action_manager_constructed (GObject *object) { G_OBJECT_CLASS (parent_class)->constructed (object); NemoActionManager *action_manager = NEMO_ACTION_MANAGER (object); set_up_actions_directories (action_manager); set_up_actions (action_manager); g_signal_connect (nemo_plugin_preferences, "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS, G_CALLBACK (plugin_prefs_changed), action_manager); } NemoActionManager * nemo_action_manager_new (void) { return g_object_new (NEMO_TYPE_ACTION_MANAGER, NULL); } static void nemo_action_manager_dispose (GObject *object) { NemoActionManager *action_manager = NEMO_ACTION_MANAGER (object); if (action_manager->actions_directory_list != NULL) { GList *node, *copy; copy = nemo_directory_list_copy (action_manager->actions_directory_list); for (node = copy; node != NULL; node = node->next) { remove_directory_from_actions_directory_list (action_manager, node->data); } g_list_free (action_manager->actions_directory_list); action_manager->actions_directory_list = NULL; nemo_directory_list_free (copy); } g_signal_handlers_disconnect_by_func (nemo_plugin_preferences, G_CALLBACK (plugin_prefs_changed), action_manager); G_OBJECT_CLASS (parent_class)->dispose (object); } static void nemo_action_manager_finalize (GObject *object) { NemoActionManager *action_manager = NEMO_ACTION_MANAGER (object); g_list_free_full (action_manager->actions, g_object_unref); G_OBJECT_CLASS (parent_class)->finalize (object); } GList * nemo_action_manager_list_actions (NemoActionManager *action_manager) { return action_manager->action_list_dirty ? NULL : action_manager->actions; } gchar * nemo_action_manager_get_user_directory_path (void) { return g_build_filename (g_get_user_data_dir (), "nemo", "actions", NULL); } nemo-4.4.2/libnemo-private/nemo-action-manager.h000066400000000000000000000043221357442400300215510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_ACTION_MANAGER_H #define NEMO_ACTION_MANAGER_H #include #include "nemo-file.h" #define NEMO_TYPE_ACTION_MANAGER nemo_action_manager_get_type() #define NEMO_ACTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ACTION_MANAGER, NemoActionManager)) #define NEMO_ACTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ACTION_MANAGER, NemoActionManagerClass)) #define NEMO_IS_ACTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ACTION_MANAGER)) #define NEMO_IS_ACTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ACTION_MANAGER)) #define NEMO_ACTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ACTION_MANAGER, NemoActionManagerClass)) typedef struct _NemoActionManager NemoActionManager; typedef struct _NemoActionManagerClass NemoActionManagerClass; struct _NemoActionManager { GObject parent; GList *actions; GList *actions_directory_list; gboolean action_list_dirty; }; struct _NemoActionManagerClass { GObjectClass parent_class; void (* changed) (NemoActionManager *action_manager); }; GType nemo_action_manager_get_type (void); NemoActionManager *nemo_action_manager_new (void); GList * nemo_action_manager_list_actions (NemoActionManager *action_manager); gchar * nemo_action_manager_get_user_directory_path (void); #endif /* NEMO_ACTION_MANAGER_H */ nemo-4.4.2/libnemo-private/nemo-action.c000066400000000000000000001717041357442400300201450ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-action.h" #include #include #include #include "nemo-file-utilities.h" #include "nemo-program-choosing.h" #define DEBUG_FLAG NEMO_DEBUG_ACTIONS #include #if (!GLIB_CHECK_VERSION(2,50,0)) #define g_drive_is_removable g_drive_is_media_removable #endif G_DEFINE_TYPE (NemoAction, nemo_action, GTK_TYPE_ACTION); static void nemo_action_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void nemo_action_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void nemo_action_constructed (GObject *object); static void nemo_action_finalize (GObject *gobject); static SelectionType nemo_action_get_selection_type (NemoAction *action); static void nemo_action_set_extensions (NemoAction *action, gchar **extensions); static gchar **nemo_action_get_extension_list (NemoAction *action); static void nemo_action_set_mimetypes (NemoAction *action, gchar **mimetypes); static gchar **nemo_action_get_mimetypes_list (NemoAction *action); static void nemo_action_set_key_file_path (NemoAction *action, const gchar *path); static void nemo_action_set_exec (NemoAction *action, const gchar *exec); static void nemo_action_set_parent_dir (NemoAction *action, const gchar *parent_dir); static void nemo_action_set_separator (NemoAction *action, const gchar *separator); static void nemo_action_set_conditions (NemoAction *action, gchar **conditions); static gchar **nemo_action_get_conditions (NemoAction *action); static void nemo_action_set_orig_label (NemoAction *action, const gchar *orig_label); static void nemo_action_set_orig_tt (NemoAction *action, const gchar *orig_tt); static gchar *find_token_type (const gchar *str, TokenType *token_type); static gpointer parent_class; enum { PROP_0, PROP_KEY_FILE_PATH, PROP_SELECTION_TYPE, PROP_EXTENSIONS, PROP_MIMES, PROP_EXEC, PROP_PARENT_DIR, PROP_USE_PARENT_DIR, PROP_ORIG_LABEL, PROP_ORIG_TT, PROP_SEPARATOR, PROP_QUOTE_TYPE, PROP_ESCAPE_SPACE, PROP_RUN_IN_TERMINAL, PROP_CONDITIONS }; enum { CONDITION_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { NemoAction *action; gchar *name; guint watch_id; gboolean exists; } DBusCondition; typedef struct { NemoAction *action; GSettings *settings; gchar *condition_string; gchar *key; guint handler_id; } GSettingsCondition; static void dbus_condition_free (gpointer data) { DBusCondition *cond = (DBusCondition *) data; g_free (cond->name); g_bus_unwatch_name (cond->watch_id); g_free (cond); } static void gsettings_condition_free (gpointer data) { GSettingsCondition *cond = (GSettingsCondition *) data; g_signal_handler_disconnect (cond->settings, cond->handler_id); g_object_unref (cond->settings); g_free (cond->key); g_free (cond->condition_string); g_free (cond); } static void nemo_action_init (NemoAction *action) { action->key_file_path = NULL; action->selection_type = SELECTION_SINGLE; action->extensions = NULL; action->mimetypes = NULL; action->exec = NULL; action->parent_dir = NULL; action->use_parent_dir = FALSE; action->orig_label = NULL; action->orig_tt = NULL; action->quote_type = QUOTE_TYPE_NONE; action->separator = NULL; action->conditions = NULL; action->dbus = NULL; action->dbus_satisfied = TRUE; action->dbus_recalc_timeout_id = 0; action->gsettings = NULL; action->gsettings_satisfied = TRUE; action->gsettings_recalc_timeout_id = 0; action->escape_underscores = FALSE; action->escape_space = FALSE; action->show_in_blank_desktop = FALSE; action->run_in_terminal = FALSE; action->constructing = TRUE; } static void nemo_action_class_init (NemoActionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = nemo_action_finalize; object_class->set_property = nemo_action_set_property; object_class->get_property = nemo_action_get_property; object_class->constructed = nemo_action_constructed; g_object_class_install_property (object_class, PROP_KEY_FILE_PATH, g_param_spec_string ("key-file-path", "Key File Path", "The key file path associated with this action", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY) ); g_object_class_install_property (object_class, PROP_SELECTION_TYPE, g_param_spec_int ("selection-type", "Selection Type", "The action selection type", 0, SELECTION_NONE, SELECTION_SINGLE, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_EXTENSIONS, g_param_spec_pointer ("extensions", "Extensions", "String array of file extensions", G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_MIMES, g_param_spec_pointer ("mimetypes", "Mimetypes", "String array of file mimetypes", G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_EXEC, g_param_spec_string ("exec", "Executable String", "The command line to run", NULL, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_PARENT_DIR, g_param_spec_string ("parent-dir", "Parent directory", "The directory the action file resides in", NULL, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_USE_PARENT_DIR, g_param_spec_boolean ("use-parent-dir", "Use Parent Directory", "Execute using the full action path", FALSE, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_ORIG_LABEL, g_param_spec_string ("orig-label", "Original label string", "The starting label - with token", NULL, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_ORIG_TT, g_param_spec_string ("orig-tooltip", "Original tooltip string", "The starting tooltip - with token", NULL, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_SEPARATOR, g_param_spec_string ("separator", "Separator to insert between files in the exec line", "Separator to use between files, like comma, space, etc", NULL, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_QUOTE_TYPE, g_param_spec_int ("quote-type", "Type of quotes to use to enclose individual file names", "Type of quotes to use to enclose individual file names - none, single or double", QUOTE_TYPE_SINGLE, QUOTE_TYPE_NONE, QUOTE_TYPE_SINGLE, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_CONDITIONS, g_param_spec_pointer ("conditions", "Special show conditions", "Special conditions, like a bool gsettings key, or 'desktop'", G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_ESCAPE_SPACE, g_param_spec_boolean ("escape-space", "Escape spaces in file paths", "Escape spaces in file paths", FALSE, G_PARAM_READWRITE) ); g_object_class_install_property (object_class, PROP_RUN_IN_TERMINAL, g_param_spec_boolean ("run-in-terminal", "Run command in a terminal", "Run command in a terminal", FALSE, G_PARAM_READWRITE) ); signals[CONDITION_CHANGED] = g_signal_new ("condition-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static gboolean recalc_dbus_conditions (NemoAction *action) { GList *l; DBusCondition *c; gboolean pass, old_satisfied; DEBUG ("Recalculating dbus conditions for %s", action->key_file_path); pass = TRUE; for (l = action->dbus; l != NULL; l = l->next) { c = (DBusCondition *) l->data; DEBUG ("Checking dbus name for an owner: '%s' - evaluated to %s", c->name, c->exists ? "TRUE" : "FALSE"); if (!c->exists) { pass = FALSE; break; } } old_satisfied = action->dbus_satisfied; action->dbus_satisfied = pass; DEBUG ("DBus satisfied: %s", pass ? "TRUE" : "FALSE"); if (pass != old_satisfied) { g_signal_emit (action, signals[CONDITION_CHANGED], 0); } action->dbus_recalc_timeout_id = 0; return FALSE; } static void queue_recalc_dbus_conditions (NemoAction *action) { if (action->constructing) { return; } if (action->dbus_recalc_timeout_id != 0) { g_source_remove (action->dbus_recalc_timeout_id); action->dbus_recalc_timeout_id = 0; } action->dbus_recalc_timeout_id = g_idle_add ((GSourceFunc) recalc_dbus_conditions, action); } static void on_dbus_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { DBusCondition *cond = user_data; cond->exists = TRUE; queue_recalc_dbus_conditions (cond->action); } static void on_dbus_disappeared (GDBusConnection *connection, const gchar *name, gpointer user_data) { DBusCondition *cond = user_data; cond->exists = FALSE; queue_recalc_dbus_conditions (cond->action); } static void setup_dbus_condition (NemoAction *action, const gchar *condition) { gchar **split = g_strsplit (condition, " ", 2); if (g_strv_length (split) != 2) { g_strfreev (split); return; } if (g_strcmp0 (split[0], "dbus") != 0) { g_strfreev (split); return; } DBusCondition *cond = g_new0 (DBusCondition, 1); cond->name = g_strdup (split[1]); cond->exists = FALSE; cond->action = action; action->dbus = g_list_append (action->dbus, cond); cond->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, cond->name, 0, on_dbus_appeared, on_dbus_disappeared, cond, NULL); g_strfreev (split); } #define EQUALS "eq" #define NOT_EQUALS "ne" #define LESS_THAN "lt" #define GREATER_THAN "gt" enum { GSETTINGS_SCHEMA_INDEX = 1, GSETTINGS_KEY_INDEX = 2, GSETTINGS_TYPE_INDEX = 3, GSETTINGS_OP_INDEX = 4, GSETTINGS_VAL_INDEX = 5, }; static gboolean operator_is_valid (const gchar *op_string) { return (g_strcmp0 (op_string, EQUALS) == 0 || g_strcmp0 (op_string, NOT_EQUALS) == 0 || g_strcmp0 (op_string, LESS_THAN) == 0 || g_strcmp0 (op_string, GREATER_THAN) == 0); } static gboolean try_vector (const gchar *op, gint vector) { if (g_strcmp0 (op, EQUALS) == 0) { return (vector == 0); } else if (g_strcmp0 (op, NOT_EQUALS) == 0) { return (vector != 0); } else if (g_strcmp0 (op, LESS_THAN) == 0) { return (vector < 0); } else if (g_strcmp0 (op, GREATER_THAN) == 0) { return (vector > 0); } return FALSE; } static gboolean recalc_gsettings_conditions (NemoAction *action) { GList *l; gboolean pass, old_satisfied; DEBUG ("Recalculating gsettings conditions for %s", action->key_file_path); pass = TRUE; for (l = action->gsettings; l != NULL; l = l->next) { GSettingsCondition *cond; const GVariantType *target_type, *setting_type; gchar **split; gint len; gboolean iter_pass = FALSE; cond = (GSettingsCondition *) l->data; split = g_strsplit (cond->condition_string, " ", 6); len = g_strv_length (split); if (len == 3) { GVariant *setting_var; target_type = G_VARIANT_TYPE_BOOLEAN; setting_var = g_settings_get_value (cond->settings, cond->key); setting_type = g_variant_get_type (setting_var); if (g_variant_type_equal (setting_type, target_type)) { iter_pass = g_variant_get_boolean (setting_var); } g_variant_unref (setting_var); } else { GVariant *setting_var; target_type = G_VARIANT_TYPE (split[GSETTINGS_TYPE_INDEX]); setting_var = g_settings_get_value (cond->settings, cond->key); setting_type = g_variant_get_type (setting_var); if (g_variant_type_equal (setting_type, target_type)) { GVariant *target_var; target_var = g_variant_parse (target_type, split[GSETTINGS_VAL_INDEX], NULL, NULL, NULL); if (target_var != NULL) { gint vector = g_variant_compare (setting_var, target_var); iter_pass = try_vector (split[GSETTINGS_OP_INDEX], vector); g_variant_unref (target_var); } else { g_warning ("Nemo Action: gsettings value could not be parsed into a valid GVariant"); } } g_variant_unref (setting_var); } g_strfreev (split); DEBUG ("Checking gsettings condition: '%s' - evaluated to %s", cond->condition_string, iter_pass ? "TRUE" : "FALSE"); /* This should just break here, except the catch with GSettings changed signal handler, * where the value must be retrieved once with a handler connected before the changed signal * will begin being emitted. So, we should go thru all conditions so during setup none * of the signals are skipped. */ if (!iter_pass) { pass = FALSE; } } DEBUG ("GSettings satisfied: %s", pass ? "TRUE" : "FALSE"); old_satisfied = action->gsettings_satisfied; action->gsettings_satisfied = pass; if (pass != old_satisfied) { g_signal_emit (action, signals[CONDITION_CHANGED], 0); } action->gsettings_recalc_timeout_id = 0; return FALSE; } static void queue_recalc_gsettings_conditions (NemoAction *action) { if (action->constructing) { return; } if (action->gsettings_recalc_timeout_id != 0) { g_source_remove (action->gsettings_recalc_timeout_id); action->gsettings_recalc_timeout_id = 0; } action->gsettings_recalc_timeout_id = g_idle_add ((GSourceFunc) recalc_gsettings_conditions, action); } static void setup_gsettings_condition (NemoAction *action, const gchar *condition) { GSettingsSchemaSource *schema_source; GSettingsSchema *schema; gchar **split; gint len; split = g_strsplit (condition, " ", 6); len = g_strv_length (split); if (len != 6 && len != 3) { g_strfreev (split); return; } if (g_strcmp0 (split[0], "gsettings") != 0) { g_strfreev (split); return; } if (len == 6 && (!g_variant_type_string_is_valid (split[GSETTINGS_TYPE_INDEX]) || !operator_is_valid (split[GSETTINGS_OP_INDEX]))) { g_warning ("Nemo Action: Either gsettings variant type (%s) or operator (%s) is invalid.", split[GSETTINGS_TYPE_INDEX], split[GSETTINGS_OP_INDEX]); g_strfreev (split); return; } schema_source = g_settings_schema_source_get_default(); schema = g_settings_schema_source_lookup (schema_source, split[GSETTINGS_SCHEMA_INDEX], TRUE); if (schema) { GSettings *settings; gchar **keys; gint i; settings = g_settings_new (split[GSETTINGS_SCHEMA_INDEX]); keys = g_settings_list_keys (settings); for (i = 0; i < g_strv_length (keys); i++) { if (g_strcmp0 (keys[i], split[GSETTINGS_KEY_INDEX]) == 0) { GSettingsCondition *cond; gchar *signal_string; cond = g_new0 (GSettingsCondition, 1); cond->action = action; cond->condition_string = g_strdup (condition); cond->settings = g_object_ref (settings); cond->key = g_strdup (keys[i]); signal_string = g_strdup_printf ("changed::%s", cond->key); cond->handler_id = g_signal_connect_swapped (settings, signal_string, G_CALLBACK (queue_recalc_gsettings_conditions), action); action->gsettings = g_list_prepend (action->gsettings, cond); g_free (signal_string); break; } } g_object_unref (settings); g_strfreev (keys); g_settings_schema_unref (schema); } g_strfreev (split); } static void strip_custom_modifier (const gchar *raw, gboolean *custom, gchar **out) { if (g_str_has_prefix (raw, "<") && g_str_has_suffix (raw, ">")) { gchar **split = g_strsplit_set (raw, "<>", 3); *out = g_strdup (split[1]); *custom = TRUE; g_strfreev (split); } else { *out = g_strdup (raw); *custom = FALSE; } } void nemo_action_constructed (GObject *object) { G_OBJECT_CLASS (parent_class)->constructed (object); NemoAction *action = NEMO_ACTION (object); GKeyFile *key_file = g_key_file_new(); g_key_file_load_from_file (key_file, action->key_file_path, G_KEY_FILE_NONE, NULL); gchar *orig_label = g_key_file_get_locale_string (key_file, ACTION_FILE_GROUP, KEY_NAME, NULL, NULL); gchar *orig_tt = g_key_file_get_locale_string (key_file, ACTION_FILE_GROUP, KEY_COMMENT, NULL, NULL); gchar *icon_name = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_ICON_NAME, NULL); gchar *stock_id = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_STOCK_ID, NULL); gchar *exec_raw = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_EXEC, NULL); gchar *selection_string_raw = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_SELECTION, NULL); gchar *selection_string = g_ascii_strdown (selection_string_raw, -1); g_free (selection_string_raw); gchar *separator = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_SEPARATOR, NULL); gchar *quote_type_string = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_QUOTE_TYPE, NULL); QuoteType quote_type = QUOTE_TYPE_NONE; if (quote_type_string != NULL) { if (g_strcmp0 (quote_type_string, "single") == 0) quote_type = QUOTE_TYPE_SINGLE; else if (g_strcmp0 (quote_type_string, "double") == 0) quote_type = QUOTE_TYPE_DOUBLE; else if (g_strcmp0 (quote_type_string, "backtick") == 0) quote_type = QUOTE_TYPE_BACKTICK; } SelectionType type; if (g_strcmp0 (selection_string, SELECTION_SINGLE_KEY) == 0) type = SELECTION_SINGLE; else if (g_strcmp0 (selection_string, SELECTION_MULTIPLE_KEY) == 0) type = SELECTION_MULTIPLE; else if (g_strcmp0 (selection_string, SELECTION_ANY_KEY) == 0) type = SELECTION_ANY; else if (g_strcmp0 (selection_string, SELECTION_NONE_KEY) == 0) type = SELECTION_NONE; else if (g_strcmp0 (selection_string, SELECTION_NOT_NONE_KEY) == 0) type = SELECTION_NOT_NONE; else { gint val = (int) g_ascii_strtoll (selection_string, NULL, 10); type = val > 0 ? val : SELECTION_SINGLE; } g_free (selection_string); gsize count; gchar **ext = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_EXTENSIONS, &count, NULL); gsize mime_count; gchar **mimes = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_MIME_TYPES, &mime_count, NULL); gsize condition_count; gchar **conditions = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_CONDITIONS, &condition_count, NULL); gboolean escape_space; escape_space = g_key_file_get_boolean (key_file, ACTION_FILE_GROUP, KEY_WHITESPACE, NULL); gboolean run_in_terminal; run_in_terminal = g_key_file_get_boolean (key_file, ACTION_FILE_GROUP, KEY_TERMINAL, NULL); gboolean is_desktop = FALSE; if (conditions && condition_count > 0) { guint j; gchar *condition; for (j = 0; j < condition_count; j++) { condition = conditions[j]; if (g_str_has_prefix (condition, "dbus")) { setup_dbus_condition (action, condition); } else if (g_str_has_prefix (condition, "gsettings")) { setup_gsettings_condition (action, condition); } else if (g_str_has_prefix (condition, "exec")) { /* handled in nemo_action_get_visibility */ } else if (g_strcmp0 (condition, "desktop") == 0) { is_desktop = TRUE; } else if (g_strcmp0 (condition, "removable") == 0) { /* this is handled in nemo_action_get_visibility() */ } else { g_warning ("Ignoring invalid condition: %s." " See sample action at /usr/share/nemo/actions/sample.nemo_action", condition); } } } gchar *exec = NULL; gboolean use_parent_dir = FALSE; strip_custom_modifier (exec_raw, &use_parent_dir, &exec); g_free (exec_raw); TokenType token_type; action->show_in_blank_desktop = is_desktop && type == SELECTION_NONE && find_token_type (exec, &token_type) == NULL; GFile *file = g_file_new_for_path (action->key_file_path); GFile *parent = g_file_get_parent (file); gchar *parent_dir = g_file_get_path (parent); g_object_unref (file); g_object_unref (parent); g_object_set (action, "label", orig_label, "tooltip", orig_tt, "icon-name", icon_name, "stock-id", stock_id, "exec", exec, "selection-type", type, "extensions", ext, "mimetypes", mimes, "parent-dir", parent_dir, "use-parent-dir", use_parent_dir, "orig-label", orig_label, "orig-tooltip", orig_tt, "quote-type", quote_type, "separator", separator, "conditions", conditions, "escape-space", escape_space, "run-in-terminal", run_in_terminal, NULL); action->constructing = FALSE; DEBUG ("Initial action gsettings and dbus update (%s)", action->key_file_path); queue_recalc_dbus_conditions (action); queue_recalc_gsettings_conditions (action); DEBUG ("Initial action gsettings and dbus complete (%s)", action->key_file_path); g_free (orig_label); g_free (orig_tt); g_free (icon_name); g_free (stock_id); g_free (exec); g_free (parent_dir); g_free (quote_type_string); g_free (separator); g_strfreev (ext); g_strfreev (mimes); g_strfreev (conditions); g_key_file_free (key_file); } NemoAction * nemo_action_new (const gchar *name, const gchar *path) { GKeyFile *key_file = g_key_file_new(); g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, NULL); if (!g_key_file_has_group (key_file, ACTION_FILE_GROUP)) { g_key_file_free (key_file); return NULL; } if (g_key_file_has_key (key_file, ACTION_FILE_GROUP, KEY_ACTIVE, NULL)) { if (!g_key_file_get_boolean (key_file, ACTION_FILE_GROUP, KEY_ACTIVE, NULL)) { g_key_file_free (key_file); return NULL; } } gchar *orig_label = g_key_file_get_locale_string (key_file, ACTION_FILE_GROUP, KEY_NAME, NULL, NULL); gchar *exec_raw = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_EXEC, NULL); gchar **ext = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_EXTENSIONS, NULL, NULL); gchar **mimes = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_MIME_TYPES, NULL, NULL); gchar **deps = g_key_file_get_string_list (key_file, ACTION_FILE_GROUP, KEY_DEPENDENCIES, NULL, NULL); gchar *selection_string = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_SELECTION, NULL); gboolean finish = TRUE; if (deps != NULL) { guint i = 0; for (i = 0; i < g_strv_length (deps); i++) { if (g_path_is_absolute (deps[i])) { if (!g_file_test (deps[i], G_FILE_TEST_EXISTS)) { finish = FALSE; DEBUG ("Missing action dependency: %s", deps[i]); } } else { gchar *p = g_find_program_in_path (deps[i]); if (p == NULL) { finish = FALSE; DEBUG ("Missing action dependency: %s", deps[i]); g_free (p); break; } g_free (p); } } } if (orig_label == NULL || exec_raw == NULL || (ext == NULL && mimes == NULL) || selection_string == NULL) { g_warning ("An action definition requires, at minimum, " "a Label field, an Exec field, a Selection field, and an either an Extensions or Mimetypes field.\n" "Check the %s file for missing fields.", path); finish = FALSE; } g_free (orig_label); g_free (exec_raw); g_free (selection_string); g_strfreev (ext); g_strfreev (mimes); g_strfreev (deps); g_key_file_free (key_file); return finish ? g_object_new (NEMO_TYPE_ACTION, "name", name, "key-file-path", path, NULL): NULL; } static void nemo_action_finalize (GObject *object) { NemoAction *action = NEMO_ACTION (object); g_free (action->key_file_path); g_strfreev (action->extensions); g_strfreev (action->mimetypes); g_strfreev (action->conditions); g_free (action->exec); g_free (action->parent_dir); g_free (action->orig_label); g_free (action->orig_tt); g_free (action->separator); if (action->dbus) { g_list_free_full (action->dbus, (GDestroyNotify) dbus_condition_free); action->dbus = NULL; } if (action->gsettings) { g_list_free_full (action->gsettings, (GDestroyNotify) gsettings_condition_free); action->gsettings = NULL; } if (action->dbus_recalc_timeout_id != 0) { g_source_remove (action->dbus_recalc_timeout_id); action->dbus_recalc_timeout_id = 0; } if (action->gsettings_recalc_timeout_id != 0) { g_source_remove (action->gsettings_recalc_timeout_id); action->gsettings_recalc_timeout_id = 0; } G_OBJECT_CLASS (parent_class)->finalize (object); } static void nemo_action_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoAction *action; action = NEMO_ACTION (object); switch (prop_id) { case PROP_KEY_FILE_PATH: nemo_action_set_key_file_path (action, g_value_get_string (value)); break; case PROP_SELECTION_TYPE: action->selection_type = g_value_get_int (value); break; case PROP_EXTENSIONS: nemo_action_set_extensions (action, g_value_get_pointer (value)); break; case PROP_MIMES: nemo_action_set_mimetypes (action, g_value_get_pointer (value)); break; case PROP_EXEC: nemo_action_set_exec (action, g_value_get_string (value)); break; case PROP_PARENT_DIR: nemo_action_set_parent_dir (action, g_value_get_string (value)); break; case PROP_USE_PARENT_DIR: action->use_parent_dir = g_value_get_boolean (value); break; case PROP_ORIG_LABEL: nemo_action_set_orig_label (action, g_value_get_string (value)); break; case PROP_ORIG_TT: nemo_action_set_orig_tt (action, g_value_get_string (value)); break; case PROP_QUOTE_TYPE: action->quote_type = g_value_get_int (value); break; case PROP_SEPARATOR: nemo_action_set_separator (action, g_value_get_string (value)); break; case PROP_CONDITIONS: nemo_action_set_conditions (action, g_value_get_pointer (value)); break; case PROP_ESCAPE_SPACE: action->escape_space = g_value_get_boolean (value); break; case PROP_RUN_IN_TERMINAL: action->run_in_terminal = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_action_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NemoAction *action; action = NEMO_ACTION (object); switch (prop_id) { case PROP_KEY_FILE_PATH: g_value_set_string (value, action->key_file_path); break; case PROP_SELECTION_TYPE: g_value_set_int (value, action->selection_type); break; case PROP_EXTENSIONS: g_value_set_pointer (value, action->extensions); break; case PROP_MIMES: g_value_set_pointer (value, action->mimetypes); break; case PROP_EXEC: g_value_set_string (value, action->exec); break; case PROP_PARENT_DIR: g_value_set_string (value, action->parent_dir); break; case PROP_USE_PARENT_DIR: g_value_set_boolean (value, action->use_parent_dir); break; case PROP_ORIG_LABEL: g_value_set_string (value, action->orig_label); break; case PROP_ORIG_TT: g_value_set_string (value, action->orig_tt); break; case PROP_QUOTE_TYPE: g_value_set_int (value, action->quote_type); break; case PROP_SEPARATOR: g_value_set_string (value, action->separator); break; case PROP_CONDITIONS: g_value_set_pointer (value, action->conditions); break; case PROP_ESCAPE_SPACE: g_value_set_boolean (value, action->escape_space); break; case PROP_RUN_IN_TERMINAL: g_value_set_boolean (value, action->run_in_terminal); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gchar * find_token_type (const gchar *str, TokenType *token_type) { gchar *ptr = NULL; *token_type = TOKEN_NONE; ptr = g_strstr_len (str, -1, "%"); if (ptr != NULL) { if (g_str_has_prefix (ptr, TOKEN_EXEC_FILE_LIST)) { *token_type = TOKEN_PATH_LIST; return ptr; } if (g_str_has_prefix (ptr, TOKEN_EXEC_URI_LIST)) { *token_type = TOKEN_URI_LIST; return ptr; } if (g_str_has_prefix (ptr, TOKEN_EXEC_PARENT)) { *token_type = TOKEN_PARENT_PATH; return ptr; } if (g_str_has_prefix (ptr, TOKEN_EXEC_FILE_NAME)) { *token_type = TOKEN_FILE_DISPLAY_NAME; return ptr; } if (g_str_has_prefix (ptr, TOKEN_EXEC_PARENT_NAME)) { *token_type = TOKEN_PARENT_DISPLAY_NAME; return ptr; } if (g_str_has_prefix (ptr, TOKEN_LABEL_FILE_NAME)) { *token_type = TOKEN_FILE_DISPLAY_NAME; return ptr; } if (g_str_has_prefix (ptr, TOKEN_EXEC_DEVICE)) { *token_type = TOKEN_DEVICE; return ptr; } } return NULL; } static gchar * get_path (NemoAction *action, NemoFile *file) { gchar *ret, *quote_escaped, *orig; orig = nemo_file_get_path (file); quote_escaped = eel_str_escape_quotes (orig); if (action->escape_space) { ret = eel_str_escape_spaces (quote_escaped); } else { ret = g_strdup (quote_escaped); } g_free (orig); g_free (quote_escaped); return ret; } static GString * score_append (NemoAction *action, GString *str, const gchar *c) { if (action->escape_underscores) { gchar *escaped = eel_str_double_underscores (c); str = g_string_append (str, escaped); g_free (escaped); return str; } else { return g_string_append (str, c); } } static GString * insert_separator (NemoAction *action, GString *str) { if (action->separator == NULL) str = g_string_append (str, " "); else str = score_append (action, str, action->separator); return str; } static GString * insert_quote (NemoAction *action, GString *str) { switch (action->quote_type) { case QUOTE_TYPE_SINGLE: str = g_string_append (str, "'"); break; case QUOTE_TYPE_DOUBLE: str = g_string_append (str, "\""); break; case QUOTE_TYPE_BACKTICK: str = g_string_append (str, "`"); break; case QUOTE_TYPE_NONE: break; default: break; } return str; } static gchar * get_device_path (NemoAction *action, NemoFile *file) { GMount *mount = nemo_file_get_mount (file); GVolume *volume = g_mount_get_volume (mount); gchar *ret = NULL; if (action->escape_space) { gchar *id = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); ret = eel_str_escape_spaces (id); g_free (id); } else { ret = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); } g_object_unref (mount); g_object_unref (volume); return ret; } static gchar * get_insertion_string (NemoAction *action, TokenType token_type, GList *selection, NemoFile *parent) { GList *l; GString *str = g_string_new(""); gboolean first = TRUE; switch (token_type) { case TOKEN_PATH_LIST: if (g_list_length (selection) > 0) { for (l = selection; l != NULL; l = l->next) { if (!first) str = insert_separator (action, str); str = insert_quote (action, str); gchar *path = get_path (action, NEMO_FILE (l->data)); if (path) str = score_append (action, str, path); g_free (path); str = insert_quote (action, str); first = FALSE; } } else { goto default_parent_path; } break; case TOKEN_URI_LIST: if (g_list_length (selection) > 0) { for (l = selection; l != NULL; l = l->next) { if (!first) str = insert_separator (action, str); str = insert_quote (action, str); gchar *uri = nemo_file_get_uri (NEMO_FILE (l->data)); str = score_append (action, str, uri); g_free (uri); str = insert_quote (action, str); first = FALSE; } } else { goto default_parent_path; } break; case TOKEN_PARENT_PATH: ; default_parent_path: ; gchar *path = get_path (action, parent); if (path == NULL) { gchar *name = nemo_file_get_display_name (parent); if (g_strcmp0 (name, "x-nemo-desktop") == 0) path = nemo_get_desktop_directory (); else path = g_strdup (""); g_free (name); } str = insert_quote (action, str); str = score_append (action, str, path); str = insert_quote (action, str); g_free (path); break; case TOKEN_FILE_DISPLAY_NAME: if (g_list_length (selection) > 0) { gchar *file_display_name = nemo_file_get_display_name (NEMO_FILE (selection->data)); str = score_append (action, str, file_display_name); g_free (file_display_name); } else { goto default_parent_display_name; } break; case TOKEN_PARENT_DISPLAY_NAME: ; default_parent_display_name: ; gchar *parent_display_name; gchar *real_display_name = nemo_file_get_display_name (parent); if (g_strcmp0 (real_display_name, "x-nemo-desktop") == 0) parent_display_name = g_strdup_printf (_("Desktop")); else parent_display_name = nemo_file_get_display_name (parent); g_free (real_display_name); str = insert_quote (action, str); str = score_append (action, str, parent_display_name); str = insert_quote (action, str); g_free (parent_display_name); break; case TOKEN_DEVICE: if (g_list_length (selection) > 0) { for (l = selection; l != NULL; l = l->next) { if (!first) str = insert_separator (action, str); str = insert_quote (action, str); gchar *dev = get_device_path (action, NEMO_FILE (l->data)); if (dev) str = score_append (action, str, dev); g_free (dev); str = insert_quote (action, str); first = FALSE; } } else { goto default_parent_path; } break; case TOKEN_NONE: default: break; } gchar *ret = str->str; g_string_free (str, FALSE); return ret; } static GString * expand_action_string (NemoAction *action, GList *selection, NemoFile *parent, GString *str) { gchar *ptr; TokenType token_type; ptr = find_token_type (str->str, &token_type); while (ptr != NULL) { gint shift = ptr - str->str; gchar *insertion = get_insertion_string (action, token_type, selection, parent); str = g_string_erase (str, shift, 2); str = g_string_insert (str, shift, insertion); token_type = TOKEN_NONE; /* The string may have expanded, and since we modify-in-place using GString, make sure * our continuation begins just beyond what we inserted, not the original match position. * Otherwise we may get confused by uri escape codes that happen to match *our* replacement * tokens (%U, %F, etc...). * * See: https://github.com/linuxmint/nemo/issues/1956 */ ptr = find_token_type (str->str + shift + strlen(insertion), &token_type); g_free (insertion); } return str; } void nemo_action_activate (NemoAction *action, GList *selection, NemoFile *parent) { GError *error; GString *exec = g_string_new (action->exec); error = NULL; action->escape_underscores = FALSE; exec = expand_action_string (action, selection, parent, exec); if (action->use_parent_dir) { exec = g_string_prepend (exec, G_DIR_SEPARATOR_S); exec = g_string_prepend (exec, action->parent_dir); } DEBUG ("Action Spawning: %s", exec->str); if (action->run_in_terminal) { gint argcp; gchar **argvp; if (g_shell_parse_argv (exec->str, &argcp, &argvp, &error)) { nemo_launch_application_from_command_array (gdk_screen_get_default (), argvp[0], TRUE, (const char * const *)(argvp + sizeof (gchar))); g_strfreev (argvp); } else { DEBUG ("Could not parse arguments terminal launch. Possibly turn off Quotes and remove any from your Exec line: %s\n", error->message); g_error_free (error); } } else { if (!g_spawn_command_line_async (exec->str, &error)) { DEBUG ("Error spawning action: %s\n", error->message); g_error_free (error); } } g_string_free (exec, TRUE); } static SelectionType nemo_action_get_selection_type (NemoAction *action) { return action->selection_type; } static void nemo_action_set_extensions (NemoAction *action, gchar **extensions) { gchar **tmp; tmp = action->extensions; action->extensions = g_strdupv (extensions); g_strfreev (tmp); } static gchar ** nemo_action_get_extension_list (NemoAction *action) { return action->extensions; } static void nemo_action_set_mimetypes (NemoAction *action, gchar **mimetypes) { gchar **tmp; tmp = action->mimetypes; action->mimetypes = g_strdupv (mimetypes); g_strfreev (tmp); } static gchar ** nemo_action_get_mimetypes_list (NemoAction *action) { return action->mimetypes; } static void nemo_action_set_key_file_path (NemoAction *action, const gchar *path) { gchar *tmp; tmp = action->key_file_path; action->key_file_path = g_strdup (path); g_free (tmp); } static void nemo_action_set_exec (NemoAction *action, const gchar *exec) { gchar *tmp; tmp = action->exec; action->exec = g_strdup (exec); g_free (tmp); } static void nemo_action_set_parent_dir (NemoAction *action, const gchar *parent_dir) { gchar *tmp; tmp = action->parent_dir; action->parent_dir = g_strdup (parent_dir); g_free (tmp); } static void nemo_action_set_separator (NemoAction *action, const gchar *separator) { gchar *tmp; tmp = action->separator; action->separator = g_strdup (separator); g_free (tmp); } static void nemo_action_set_conditions (NemoAction *action, gchar **conditions) { gchar **tmp; tmp = action->conditions; action->conditions = g_strdupv (conditions); g_strfreev (tmp); } static gchar ** nemo_action_get_conditions (NemoAction *action) { return action->conditions; } static void nemo_action_set_orig_label (NemoAction *action, const gchar *orig_label) { gchar *tmp; tmp = action->orig_label; action->orig_label = g_strdup (orig_label); g_free (tmp); } static void nemo_action_set_orig_tt (NemoAction *action, const gchar *orig_tt) { gchar *tmp; tmp = action->orig_tt; action->orig_tt = g_strdup (orig_tt); g_free (tmp); } const gchar * nemo_action_get_orig_label (NemoAction *action) { return action->orig_label; } const gchar * nemo_action_get_orig_tt (NemoAction *action) { return action->orig_tt; } gchar * nemo_action_get_label (NemoAction *action, GList *selection, NemoFile *parent) { const gchar *orig_label = nemo_action_get_orig_label (action); if (orig_label == NULL) return NULL; action->escape_underscores = TRUE; GString *str = g_string_new (orig_label); str = expand_action_string (action, selection, parent, str); DEBUG ("Action Label: %s", str->str); gchar *ret = str->str; g_string_free (str, FALSE); return ret; } gchar * nemo_action_get_tt (NemoAction *action, GList *selection, NemoFile *parent) { const gchar *orig_tt = nemo_action_get_orig_tt (action); if (orig_tt == NULL) return NULL; action->escape_underscores = FALSE; GString *str = g_string_new (orig_tt); str = expand_action_string (action, selection, parent, str); DEBUG ("Action Tooltip: %s", str->str); gchar *ret = str->str; g_string_free (str, FALSE); return ret; } static gboolean get_dbus_satisfied (NemoAction *action) { return action->dbus_satisfied; } static gboolean get_gsettings_satisfied (NemoAction *action) { return action->gsettings_satisfied; } static gboolean check_exec_condition (NemoAction *action, const gchar *condition, GList *selection, NemoFile *parent) { GString *exec; GError *error; gint return_code; gchar *exec_str; gchar **split; gboolean use_parent_dir; split = g_strsplit (condition, " ", 2); if (g_strv_length (split) != 2) { g_strfreev (split); return FALSE; } if (g_strcmp0 (split[0], "exec") != 0) { g_strfreev (split); return FALSE; } strip_custom_modifier (split[1], &use_parent_dir, &exec_str); g_strfreev (split); exec = g_string_new (exec_str); g_free (exec_str); error = NULL; action->escape_underscores = FALSE; exec = expand_action_string (action, selection, parent, exec); if (use_parent_dir) { exec = g_string_prepend (exec, G_DIR_SEPARATOR_S); exec = g_string_prepend (exec, action->parent_dir); } DEBUG ("Checking exec condition: %s", exec->str); if (!g_spawn_command_line_sync (exec->str, NULL, NULL, &return_code, &error)) { DEBUG ("Error spawning exec condition: %s\n", error->message); g_error_free (error); } DEBUG ("Action checking exec condition '%s' returned: %d", exec->str, return_code); g_string_free (exec, TRUE); return (return_code == 0); } static gboolean get_is_dir (NemoFile *file) { gboolean ret = FALSE; GFile *f = nemo_file_get_location (file); if (g_file_is_native (f)) { gchar *path; path = g_file_get_path (f); ret = g_file_test (path, G_FILE_TEST_IS_DIR); g_free (path); } else { ret = nemo_file_is_directory (file); } g_object_unref (f); return ret; } gboolean nemo_action_get_visibility (NemoAction *action, GList *selection, NemoFile *parent, gboolean for_places) { // Check DBUS if (!get_dbus_satisfied (action)) return FALSE; if (!get_gsettings_satisfied (action)) return FALSE; // Check selection gboolean selection_type_show = FALSE; SelectionType selection_type = nemo_action_get_selection_type (action); guint selected_count = g_list_length (selection); switch (selection_type) { case SELECTION_SINGLE: selection_type_show = selected_count == 1; break; case SELECTION_MULTIPLE: selection_type_show = selected_count > 1; break; case SELECTION_NOT_NONE: selection_type_show = selected_count > 0; break; case SELECTION_NONE: selection_type_show = selected_count == 0; break; case SELECTION_ANY: selection_type_show = TRUE; break; default: selection_type_show = selected_count == selection_type; break; } if (!selection_type_show) return FALSE; // Check extensions and mimetypes gboolean extension_type_show = TRUE; gchar **extensions = nemo_action_get_extension_list (action); gchar **mimetypes = nemo_action_get_mimetypes_list (action); guint ext_count = extensions != NULL ? g_strv_length (extensions) : 0; guint mime_count = mimetypes != NULL ? g_strv_length (mimetypes) : 0; if (ext_count == 1 && g_strcmp0 (extensions[0], "any") == 0) { extension_type_show = TRUE; } else { gboolean found_match = TRUE; GList *iter; for (iter = selection; iter != NULL && found_match; iter = iter->next) { found_match = FALSE; gboolean is_dir; gchar *raw_fn = nemo_file_get_name (NEMO_FILE (iter->data)); gchar *filename = g_ascii_strdown (raw_fn, -1); g_free (raw_fn); guint i; is_dir = get_is_dir (iter->data); if (ext_count > 0) { for (i = 0; i < ext_count; i++) { if (g_strcmp0 (extensions[i], "dir") == 0) { if (is_dir) { found_match = TRUE; break; } } else if (g_strcmp0 (extensions[i], "none") == 0) { if (g_strrstr (filename, ".") == NULL) { found_match = TRUE; break; } } else if (g_strcmp0 (extensions[i], "nodirs") == 0) { if (!is_dir) { found_match = TRUE; break; } } else { gchar *str = g_ascii_strdown (extensions[i], -1); if (g_str_has_suffix (filename, str)) { found_match = TRUE; } g_free (str); if (found_match) { break; } } } } g_free (filename); if (mime_count > 0) { for (i = 0; i < mime_count; i++) { if (nemo_file_is_mime_type (NEMO_FILE (iter->data), mimetypes[i])) { found_match = TRUE; break; } } } if (nemo_file_is_mime_type (NEMO_FILE (iter->data), "application/x-nemo-link")) { found_match = FALSE; } } extension_type_show = found_match; } if (!extension_type_show) return FALSE; // Check conditions gboolean condition_type_show = TRUE; gchar **conditions = nemo_action_get_conditions (action); guint condition_count = conditions != NULL ? g_strv_length (conditions) : 0; if (condition_count > 0) { guint j; gchar *condition; for (j = 0; j < condition_count; j++) { condition = conditions[j]; if (g_strcmp0 (condition, "desktop") == 0) { gchar *name = nemo_file_get_display_name (parent); if (g_strcmp0 (name, "x-nemo-desktop") != 0) condition_type_show = FALSE; g_free (name); } else if (g_strcmp0 (condition, "removable") == 0) { gboolean is_removable = FALSE; if (g_list_length (selection) > 0) { NemoFile *file; GMount *mount = NULL; file = NEMO_FILE (selection->data); mount = nemo_file_get_mount (file); /* find_enclosing_mount can block, so only bother when activated * from the places sidebar (which is strictly done on-demand), * so we don't drag down any view loads. */ if (!mount && for_places) { GFile *f; f = nemo_file_get_location (file); if (g_file_is_native (f)) { mount = g_file_find_enclosing_mount (f, NULL, NULL); nemo_file_set_mount (file, mount); } g_object_unref (f); } if (mount) { GDrive *drive; drive = g_mount_get_drive (mount); if (drive) { if (g_drive_is_removable (drive)) { is_removable = TRUE; } g_object_unref (drive); } } } condition_type_show = is_removable; } else if (g_str_has_prefix (condition, "exec")) { condition_type_show = check_exec_condition (action, condition, selection, parent); } if (!condition_type_show) break; } } if (!condition_type_show) return FALSE; return TRUE; } nemo-4.4.2/libnemo-private/nemo-action.h000066400000000000000000000107031357442400300201410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_ACTION_H #define NEMO_ACTION_H #include #include #include "nemo-file.h" #define NEMO_TYPE_ACTION nemo_action_get_type() #define NEMO_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ACTION, NemoAction)) #define NEMO_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ACTION, NemoActionClass)) #define NEMO_IS_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ACTION)) #define NEMO_IS_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ACTION)) #define NEMO_ACTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ACTION, NemoActionClass)) #define SELECTION_SINGLE_KEY "s" #define SELECTION_MULTIPLE_KEY "m" #define SELECTION_ANY_KEY "any" #define SELECTION_NONE_KEY "none" #define SELECTION_NOT_NONE_KEY "notnone" #define TOKEN_EXEC_URI_LIST "%U" #define TOKEN_EXEC_FILE_LIST "%F" #define TOKEN_EXEC_PARENT "%P" #define TOKEN_EXEC_FILE_NAME "%f" #define TOKEN_EXEC_PARENT_NAME "%p" #define TOKEN_EXEC_DEVICE "%D" #define TOKEN_LABEL_FILE_NAME "%N" // Leave in for compatibility, same as TOKEN_EXEC_FILE_NAME #define ACTION_FILE_GROUP "Nemo Action" #define KEY_ACTIVE "Active" #define KEY_NAME "Name" #define KEY_COMMENT "Comment" #define KEY_EXEC "Exec" #define KEY_ICON_NAME "Icon-Name" #define KEY_STOCK_ID "Stock-Id" #define KEY_SELECTION "Selection" #define KEY_EXTENSIONS "Extensions" #define KEY_MIME_TYPES "Mimetypes" #define KEY_SEPARATOR "Separator" #define KEY_QUOTE_TYPE "Quote" #define KEY_DEPENDENCIES "Dependencies" #define KEY_CONDITIONS "Conditions" #define KEY_WHITESPACE "EscapeSpaces" #define KEY_DOUBLE_ESCAPE_QUOTES "DoubleEscapeQuotes" #define KEY_TERMINAL "Terminal" typedef struct _NemoAction NemoAction; typedef struct _NemoActionClass NemoActionClass; typedef enum { SELECTION_SINGLE = G_MAXINT - 10, SELECTION_MULTIPLE, SELECTION_NOT_NONE, SELECTION_ANY, SELECTION_NONE } SelectionType; typedef enum { QUOTE_TYPE_SINGLE = 0, QUOTE_TYPE_DOUBLE, QUOTE_TYPE_BACKTICK, QUOTE_TYPE_NONE } QuoteType; typedef enum { TOKEN_NONE = 0, TOKEN_PATH_LIST, TOKEN_URI_LIST, TOKEN_FILE_DISPLAY_NAME, TOKEN_PARENT_DISPLAY_NAME, TOKEN_PARENT_PATH, TOKEN_DEVICE } TokenType; struct _NemoAction { GtkAction parent; gchar *key_file_path; SelectionType selection_type; gchar **extensions; gchar **mimetypes; gchar *exec; gchar *parent_dir; gchar **conditions; gchar *separator; QuoteType quote_type; gchar *orig_label; gchar *orig_tt; gboolean use_parent_dir; GList *dbus; guint dbus_recalc_timeout_id; GList *gsettings; guint gsettings_recalc_timeout_id; gboolean dbus_satisfied; gboolean gsettings_satisfied; gboolean escape_underscores; gboolean escape_space; gboolean show_in_blank_desktop; gboolean run_in_terminal; gboolean constructing; }; struct _NemoActionClass { GtkActionClass parent_class; }; GType nemo_action_get_type (void); NemoAction *nemo_action_new (const gchar *name, const gchar *path); void nemo_action_activate (NemoAction *action, GList *selection, NemoFile *parent); const gchar *nemo_action_get_orig_label (NemoAction *action); const gchar *nemo_action_get_orig_tt (NemoAction *action); gchar *nemo_action_get_label (NemoAction *action, GList *selection, NemoFile *parent); gchar *nemo_action_get_tt (NemoAction *action, GList *selection, NemoFile *parent); gboolean nemo_action_get_visibility (NemoAction *action, GList *selection, NemoFile *parent, gboolean for_places); #endif /* NEMO_ACTION_H */ nemo-4.4.2/libnemo-private/nemo-bookmark.c000066400000000000000000000564331357442400300204760ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-bookmark.c - implementation of individual bookmarks. * * Copyright (C) 1999, 2000 Eazel, Inc. * Copyright (C) 2011, Red Hat, Inc. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: John Sullivan * Cosimo Cecchi */ #include #include "nemo-bookmark.h" #include "nemo-metadata.h" #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_BOOKMARKS #include enum { CONTENTS_CHANGED, LOCATION_MOUNTED, LOOKUP_METADATA, LAST_SIGNAL }; enum { PROP_NAME = 1, PROP_CUSTOM_NAME, PROP_LOCATION, PROP_ICON_NAME, PROP_METADATA, NUM_PROPERTIES }; #define ELLIPSISED_MENU_ITEM_MIN_CHARS 32 static GParamSpec* properties[NUM_PROPERTIES] = { NULL }; static guint signals[LAST_SIGNAL] = { 0 }; struct NemoBookmarkDetails { char *name; gboolean has_custom_name; GFile *location; gchar *icon_name; NemoFile *file; char *scroll_file; NemoBookmarkMetadata *metadata; }; static void nemo_bookmark_disconnect_file (NemoBookmark *file); G_DEFINE_TYPE (NemoBookmark, nemo_bookmark, G_TYPE_OBJECT); static void nemo_bookmark_set_name_internal (NemoBookmark *bookmark, const char *new_name) { if (g_strcmp0 (bookmark->details->name, new_name) != 0) { g_free (bookmark->details->name); bookmark->details->name = g_strdup (new_name); g_object_notify_by_pspec (G_OBJECT (bookmark), properties[PROP_NAME]); } } static void nemo_bookmark_update_icon (NemoBookmark *bookmark) { gchar *new_icon_name; if (bookmark->details->file == NULL) { return; } if (!nemo_file_is_not_yet_confirmed (bookmark->details->file) && nemo_file_check_if_ready (bookmark->details->file, NEMO_FILE_ATTRIBUTES_FOR_ICON)) { DEBUG ("%s: set new icon", nemo_bookmark_get_name (bookmark)); new_icon_name = nemo_file_get_control_icon_name (bookmark->details->file); g_object_set (bookmark, "icon-name", new_icon_name, NULL); g_free (new_icon_name); } } static void bookmark_set_name_from_ready_file (NemoBookmark *self, NemoFile *file) { gchar *display_name; if (self->details->has_custom_name) { return; } display_name = nemo_file_get_display_name (self->details->file); if (nemo_file_is_home (self->details->file)) { nemo_bookmark_set_custom_name (self, _("Home")); } else if (g_strcmp0 (self->details->name, display_name) != 0) { nemo_bookmark_set_custom_name (self, display_name); DEBUG ("%s: name changed to %s", nemo_bookmark_get_name (self), display_name); } g_free (display_name); } static gchar * get_default_folder_icon_name (NemoBookmark *bookmark) { gchar *ret = NULL; if (g_file_is_native (bookmark->details->location)) { ret = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER); } else { gchar *uri = g_file_get_uri (bookmark->details->location); if (g_str_has_prefix (uri, EEL_SEARCH_URI)) { ret = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_SAVED_SEARCH); } else { ret = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_REMOTE); } g_free (uri); } return ret; } static gchar * construct_default_icon_from_metadata (NemoBookmark *bookmark) { return get_default_folder_icon_name (bookmark); /* TODO: Remove emblem stuff from bookmarks */ // if (ret != NULL && md->emblems != NULL) { // guint i = 0; // GIcon *emb_icon; // GEmblem *emblem; // emb_icon = g_themed_icon_new (md->emblems[i]); // emblem = g_emblem_new (emb_icon); // ret = g_emblemed_icon_new (ret, emblem); // i++; // while (i < g_strv_length (md->emblems)) { // emb_icon = g_themed_icon_new (md->emblems[i]); // emblem = g_emblem_new (emb_icon); // g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (ret), emblem); // i++; // } // } // return ret; } static void nemo_bookmark_set_icon_to_default (NemoBookmark *bookmark) { gchar *icon_name; icon_name = construct_default_icon_from_metadata (bookmark); if (!nemo_bookmark_uri_get_exists (bookmark)) { DEBUG ("%s: file does not exist, use special icon", nemo_bookmark_get_name (bookmark)); g_clear_pointer (&icon_name, g_free); icon_name = g_strdup (NEMO_ICON_SYMBOLIC_MISSING_BOOKMARK); } DEBUG ("%s: setting icon to default", nemo_bookmark_get_name (bookmark)); g_object_set (bookmark, "icon-name", icon_name, NULL); g_free (icon_name); } static gboolean metadata_changed (NemoBookmark *bookmark) { gboolean ret = FALSE; NemoBookmarkMetadata *data = nemo_bookmark_get_updated_metadata (bookmark); gboolean has_custom = data && data->emblems; gboolean had_custom = bookmark->details->metadata != NULL; if ((has_custom && !had_custom) || (had_custom && !has_custom)) { ret = TRUE; } else if (has_custom && had_custom) { NemoBookmarkMetadata *md = bookmark->details->metadata; ret = nemo_bookmark_metadata_compare (data, md); } nemo_bookmark_metadata_free (data); return ret; } static void bookmark_file_changed_callback (NemoFile *file, NemoBookmark *bookmark) { GFile *location; g_assert (file == bookmark->details->file); DEBUG ("%s: file changed", nemo_bookmark_get_name (bookmark)); location = nemo_file_get_location (file); if (!g_file_equal (bookmark->details->location, location) && !nemo_file_is_in_trash (file)) { DEBUG ("%s: file got moved", nemo_bookmark_get_name (bookmark)); g_object_unref (bookmark->details->location); bookmark->details->location = g_object_ref (location); g_object_notify_by_pspec (G_OBJECT (bookmark), properties[PROP_LOCATION]); g_signal_emit (bookmark, signals[CONTENTS_CHANGED], 0); } g_object_unref (location); if (nemo_file_is_gone (file) || nemo_file_is_in_trash (file)) { /* The file we were monitoring has been trashed, deleted, * or moved in a way that we didn't notice. We should make * a spanking new NemoFile object for this * location so if a new file appears in this place * we will notice. However, we can't immediately do so * because creating a new NemoFile directly as a result * of noticing a file goes away may trigger i/o on that file * again, noticeing it is gone, leading to a loop. * So, the new NemoFile is created when the bookmark * is used again. However, this is not really a problem, as * we don't want to change the icon or anything about the * bookmark just because its not there anymore. */ DEBUG ("%s: trashed", nemo_bookmark_get_name (bookmark)); nemo_bookmark_disconnect_file (bookmark); nemo_bookmark_set_icon_to_default (bookmark); } else { nemo_bookmark_update_icon (bookmark); bookmark_set_name_from_ready_file (bookmark, file); if (metadata_changed (bookmark)) { g_signal_emit (bookmark, signals[CONTENTS_CHANGED], 0); } } } static void nemo_bookmark_disconnect_file (NemoBookmark *bookmark) { if (bookmark->details->file != NULL) { DEBUG ("%s: disconnecting file", nemo_bookmark_get_name (bookmark)); g_signal_handlers_disconnect_by_func (bookmark->details->file, G_CALLBACK (bookmark_file_changed_callback), bookmark); g_clear_object (&bookmark->details->file); } } static void nemo_bookmark_connect_file (NemoBookmark *bookmark) { if (bookmark->details->file != NULL) { DEBUG ("%s: file already connected, returning", nemo_bookmark_get_name (bookmark)); return; } if (nemo_bookmark_uri_get_exists (bookmark)) { DEBUG ("%s: creating file", nemo_bookmark_get_name (bookmark)); bookmark->details->file = nemo_file_get (bookmark->details->location); g_assert (!nemo_file_is_gone (bookmark->details->file)); g_signal_connect_object (bookmark->details->file, "changed", G_CALLBACK (bookmark_file_changed_callback), bookmark, 0); } /* Set icon based on available information. */ nemo_bookmark_update_icon (bookmark); if (bookmark->details->icon_name == NULL) { nemo_bookmark_set_icon_to_default (bookmark); } if (bookmark->details->file != NULL && nemo_file_check_if_ready (bookmark->details->file, NEMO_FILE_ATTRIBUTE_INFO)) { bookmark_set_name_from_ready_file (bookmark, bookmark->details->file); } if (bookmark->details->name == NULL) { bookmark->details->name = nemo_compute_title_for_location (bookmark->details->location); } } /* GObject methods */ static void nemo_bookmark_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoBookmark *self = NEMO_BOOKMARK (object); switch (property_id) { case PROP_ICON_NAME: ; const gchar *new_icon_name; new_icon_name = g_value_get_string (value); if (new_icon_name != NULL && g_strcmp0 (self->details->icon_name, new_icon_name) != 0) { g_clear_pointer (&self->details->icon_name, g_free); self->details->icon_name = g_strdup (new_icon_name); } break; case PROP_LOCATION: self->details->location = g_value_dup_object (value); break; case PROP_CUSTOM_NAME: self->details->has_custom_name = g_value_get_boolean (value); break; case PROP_NAME: nemo_bookmark_set_name_internal (self, g_value_get_string (value)); break; case PROP_METADATA: if (self->details->metadata) g_clear_pointer (&self->details->metadata, nemo_bookmark_metadata_free); self->details->metadata = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_bookmark_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoBookmark *self = NEMO_BOOKMARK (object); switch (property_id) { case PROP_NAME: g_value_set_string (value, self->details->name); break; case PROP_ICON_NAME: g_value_set_string (value, self->details->icon_name); break; case PROP_LOCATION: g_value_set_object (value, self->details->location); break; case PROP_CUSTOM_NAME: g_value_set_boolean (value, self->details->has_custom_name); break; case PROP_METADATA: g_value_set_pointer (value, self->details->metadata); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_bookmark_finalize (GObject *object) { NemoBookmark *bookmark; g_assert (NEMO_IS_BOOKMARK (object)); bookmark = NEMO_BOOKMARK (object); nemo_bookmark_disconnect_file (bookmark); g_object_unref (bookmark->details->location); g_clear_pointer (&bookmark->details->icon_name, g_free); g_clear_pointer (&bookmark->details->metadata, nemo_bookmark_metadata_free); g_free (bookmark->details->name); g_free (bookmark->details->scroll_file); G_OBJECT_CLASS (nemo_bookmark_parent_class)->finalize (object); } static void nemo_bookmark_class_init (NemoBookmarkClass *class) { GObjectClass *oclass = G_OBJECT_CLASS (class); oclass->finalize = nemo_bookmark_finalize; oclass->get_property = nemo_bookmark_get_property; oclass->set_property = nemo_bookmark_set_property; signals[CONTENTS_CHANGED] = g_signal_new ("contents-changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoBookmarkClass, contents_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[LOCATION_MOUNTED] = g_signal_new ("location-mounted", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoBookmarkClass, location_mounted), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, G_TYPE_FILE); properties[PROP_NAME] = g_param_spec_string ("name", "Bookmark's name", "The name of this bookmark", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); properties[PROP_CUSTOM_NAME] = g_param_spec_boolean ("custom-name", "Whether the bookmark has a custom name", "Whether the bookmark has a custom name", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); properties[PROP_LOCATION] = g_param_spec_object ("location", "Bookmark's location", "The location of this bookmark", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); properties[PROP_ICON_NAME] = g_param_spec_string ("icon-name", "Bookmark's icon name", "The icon name for this bookmark", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_METADATA] = g_param_spec_pointer ("metadata", "Bookmark's non-gvfs metadata", "Metadata for defining the bookmark's icon", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); g_type_class_add_private (class, sizeof (NemoBookmarkDetails)); } static void nemo_bookmark_init (NemoBookmark *bookmark) { bookmark->details = G_TYPE_INSTANCE_GET_PRIVATE (bookmark, NEMO_TYPE_BOOKMARK, NemoBookmarkDetails); } const gchar * nemo_bookmark_get_name (NemoBookmark *bookmark) { g_return_val_if_fail (NEMO_IS_BOOKMARK (bookmark), NULL); return bookmark->details->name; } gboolean nemo_bookmark_get_has_custom_name (NemoBookmark *bookmark) { g_return_val_if_fail(NEMO_IS_BOOKMARK (bookmark), FALSE); return (bookmark->details->has_custom_name); } /** * nemo_bookmark_set_custom_name: * * Change the user-displayed name of a bookmark. * @new_name: The new user-displayed name for this bookmark, mustn't be NULL. * **/ void nemo_bookmark_set_custom_name (NemoBookmark *bookmark, const char *new_name) { g_return_if_fail (new_name != NULL); g_return_if_fail (NEMO_IS_BOOKMARK (bookmark)); g_object_set (bookmark, "custom-name", TRUE, "name", new_name, NULL); g_signal_emit (bookmark, signals[CONTENTS_CHANGED], 0); } /** * nemo_bookmark_compare_with: * * Check whether two bookmarks are considered identical. * @a: first NemoBookmark*. * @b: second NemoBookmark*. * * Return value: 0 if @a and @b have same name and uri, 1 otherwise * (GCompareFunc style) **/ int nemo_bookmark_compare_with (gconstpointer a, gconstpointer b) { NemoBookmark *bookmark_a; NemoBookmark *bookmark_b; g_return_val_if_fail (NEMO_IS_BOOKMARK (a), 1); g_return_val_if_fail (NEMO_IS_BOOKMARK (b), 1); bookmark_a = NEMO_BOOKMARK (a); bookmark_b = NEMO_BOOKMARK (b); if (!g_file_equal (bookmark_a->details->location, bookmark_b->details->location)) { return 1; } if (g_strcmp0 (bookmark_a->details->name, bookmark_b->details->name) != 0) { return 1; } return 0; } /** * nemo_bookmark_compare_uris: * * Check whether the uris of two bookmarks are for the same location. * @a: first NemoBookmark*. * @b: second NemoBookmark*. * * Return value: 0 if @a and @b have matching uri, 1 otherwise * (GCompareFunc style) **/ int nemo_bookmark_compare_uris (gconstpointer a, gconstpointer b) { NemoBookmark *bookmark_a; NemoBookmark *bookmark_b; g_return_val_if_fail (NEMO_IS_BOOKMARK (a), 1); g_return_val_if_fail (NEMO_IS_BOOKMARK (b), 1); bookmark_a = NEMO_BOOKMARK (a); bookmark_b = NEMO_BOOKMARK (b); return !g_file_equal (bookmark_a->details->location, bookmark_b->details->location); } NemoBookmark * nemo_bookmark_copy (NemoBookmark *bookmark) { g_return_val_if_fail (NEMO_IS_BOOKMARK (bookmark), NULL); return nemo_bookmark_new (bookmark->details->location, bookmark->details->has_custom_name ? bookmark->details->name : NULL, bookmark->details->icon_name, bookmark->details->metadata ? nemo_bookmark_metadata_copy (bookmark->details->metadata) : NULL); } gchar * nemo_bookmark_get_icon_name (NemoBookmark *bookmark) { g_return_val_if_fail (NEMO_IS_BOOKMARK (bookmark), NULL); /* Try to connect a file in case file exists now but didn't earlier. */ nemo_bookmark_connect_file (bookmark); if (bookmark->details->icon_name) { return g_strdup (bookmark->details->icon_name); } return NULL; } GFile * nemo_bookmark_get_location (NemoBookmark *bookmark) { g_return_val_if_fail(NEMO_IS_BOOKMARK (bookmark), NULL); /* Try to connect a file in case file exists now but didn't earlier. * This allows a bookmark to update its image properly in the case * where a new file appears with the same URI as a previously-deleted * file. Calling connect_file here means that attempts to activate the * bookmark will update its image if possible. */ nemo_bookmark_connect_file (bookmark); return g_object_ref (bookmark->details->location); } char * nemo_bookmark_get_uri (NemoBookmark *bookmark) { GFile *file; char *uri; file = nemo_bookmark_get_location (bookmark); uri = g_file_get_uri (file); g_object_unref (file); return uri; } NemoBookmark * nemo_bookmark_new (GFile *location, const gchar *custom_name, const gchar *icon_name, NemoBookmarkMetadata *md) { NemoBookmark *new_bookmark; gchar *name; if (custom_name == NULL) name = g_file_get_basename (location); else name = g_strdup (custom_name); new_bookmark = NEMO_BOOKMARK (g_object_new (NEMO_TYPE_BOOKMARK, "location", location, "icon-name", icon_name, "name", name, "custom-name", custom_name != NULL, "metadata", md, NULL)); g_free (name); return new_bookmark; } static GtkWidget * create_image_widget_for_bookmark (NemoBookmark *bookmark) { GtkWidget *widget; gchar *icon_name; icon_name = nemo_bookmark_get_icon_name (bookmark); widget = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); g_free (icon_name); return widget; } /** * nemo_bookmark_menu_item_new: * * Return a menu item representing a bookmark. * @bookmark: The bookmark the menu item represents. * Return value: A newly-created bookmark, not yet shown. **/ GtkWidget * nemo_bookmark_menu_item_new (NemoBookmark *bookmark) { GtkWidget *menu_item; GtkWidget *image_widget; GtkLabel *label; const char *name; name = nemo_bookmark_get_name (bookmark); menu_item = gtk_image_menu_item_new_with_label (name); label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (menu_item))); gtk_label_set_use_underline (label, FALSE); gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); gtk_label_set_max_width_chars (label, ELLIPSISED_MENU_ITEM_MIN_CHARS); image_widget = create_image_widget_for_bookmark (bookmark); if (image_widget != NULL) { gtk_widget_show (image_widget); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image_widget); } return menu_item; } gboolean nemo_bookmark_uri_get_exists (NemoBookmark *bookmark) { char *path_name; gboolean exists = FALSE; path_name = g_file_get_path (bookmark->details->location); if (g_file_is_native (bookmark->details->location) && g_file_test (path_name, G_FILE_TEST_EXISTS)) { exists = TRUE; } else { g_signal_emit_by_name (bookmark, "location-mounted", bookmark->details->location, &exists); } g_free (path_name); return exists; } void nemo_bookmark_set_scroll_pos (NemoBookmark *bookmark, const char *uri) { g_free (bookmark->details->scroll_file); bookmark->details->scroll_file = g_strdup (uri); } char * nemo_bookmark_get_scroll_pos (NemoBookmark *bookmark) { return g_strdup (bookmark->details->scroll_file); } void nemo_bookmark_connect (NemoBookmark *bookmark) { nemo_bookmark_connect_file (bookmark); } static gchar ** char_list_to_strv (GList *list) { GList *iter; GPtrArray *array = g_ptr_array_new (); for (iter = list; iter != NULL; iter = iter->next) { g_ptr_array_add (array, g_strdup (iter->data)); } g_ptr_array_add (array, NULL); return (char **) g_ptr_array_free (array, FALSE); } NemoBookmarkMetadata * nemo_bookmark_get_updated_metadata (NemoBookmark *bookmark) { NemoBookmarkMetadata *ret = NULL; if (!bookmark->details->file) return NULL; if (bookmark->details->file && !nemo_file_is_gone (bookmark->details->file)) { GList *custom_emblems = NULL; custom_emblems = nemo_file_get_metadata_list (bookmark->details->file, NEMO_METADATA_KEY_EMBLEMS); if (custom_emblems) { ret = nemo_bookmark_metadata_new (); ret->emblems = char_list_to_strv (custom_emblems); g_list_free_full (custom_emblems, g_free); } } else if (bookmark->details->metadata) { ret = nemo_bookmark_metadata_copy (bookmark->details->metadata); } return ret; } NemoBookmarkMetadata * nemo_bookmark_get_current_metadata (NemoBookmark *bookmark) { if (bookmark->details->metadata) return bookmark->details->metadata; return NULL; } NemoBookmarkMetadata * nemo_bookmark_metadata_new (void) { NemoBookmarkMetadata *meta = g_slice_new0 (NemoBookmarkMetadata); return meta; } NemoBookmarkMetadata * nemo_bookmark_metadata_copy (NemoBookmarkMetadata *meta) { NemoBookmarkMetadata *copy = nemo_bookmark_metadata_new (); copy->bookmark_name = g_strdup (meta->bookmark_name); copy->emblems = g_strdupv (meta->emblems); return copy; } gboolean nemo_bookmark_metadata_compare (NemoBookmarkMetadata *d1, NemoBookmarkMetadata *d2) { if (g_strcmp0 (d1->bookmark_name, d2->bookmark_name) != 0 || (g_strv_length (d1->emblems) != g_strv_length (d2->emblems))) return FALSE; guint i; for (i = 0; i < g_strv_length (d1->emblems); i++) { if (g_strcmp0 (d1->emblems[i], d2->emblems[i]) != 0) return FALSE; } return TRUE; } void nemo_bookmark_metadata_free (NemoBookmarkMetadata *metadata) { if (metadata == NULL) { return; } g_free (metadata->bookmark_name); g_strfreev (metadata->emblems); g_slice_free (NemoBookmarkMetadata, metadata); } nemo-4.4.2/libnemo-private/nemo-bookmark.h000066400000000000000000000115171357442400300204750ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-bookmark.h - implementation of individual bookmarks. * * Copyright (C) 1999, 2000 Eazel, Inc. * Copyright (C) 2011, Red Hat, Inc. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: John Sullivan * Cosimo Cecchi */ #ifndef NEMO_BOOKMARK_H #define NEMO_BOOKMARK_H #include #include typedef struct NemoBookmark NemoBookmark; #define NEMO_TYPE_BOOKMARK nemo_bookmark_get_type() #define NEMO_BOOKMARK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_BOOKMARK, NemoBookmark)) #define NEMO_BOOKMARK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_BOOKMARK, NemoBookmarkClass)) #define NEMO_IS_BOOKMARK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_BOOKMARK)) #define NEMO_IS_BOOKMARK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_BOOKMARK)) #define NEMO_BOOKMARK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_BOOKMARK, NemoBookmarkClass)) typedef struct NemoBookmarkDetails NemoBookmarkDetails; struct NemoBookmark { GObject object; NemoBookmarkDetails *details; }; typedef struct { gchar *bookmark_name; gchar **emblems; } NemoBookmarkMetadata; struct NemoBookmarkClass { GObjectClass parent_class; /* Signals that clients can connect to. */ /* The contents-changed signal is emitted when the bookmark's contents * (custom name or URI) changed. */ void (* contents_changed) (NemoBookmark *bookmark); gboolean (* location_mounted) (GFile *location); }; typedef struct NemoBookmarkClass NemoBookmarkClass; GType nemo_bookmark_get_type (void); NemoBookmark * nemo_bookmark_new (GFile *location, const char *custom_name, const char *icon_name, NemoBookmarkMetadata *md); NemoBookmark * nemo_bookmark_copy (NemoBookmark *bookmark); const char * nemo_bookmark_get_name (NemoBookmark *bookmark); GFile * nemo_bookmark_get_location (NemoBookmark *bookmark); char * nemo_bookmark_get_uri (NemoBookmark *bookmark); gchar * nemo_bookmark_get_icon_name (NemoBookmark *bookmark); gboolean nemo_bookmark_get_has_custom_name (NemoBookmark *bookmark); void nemo_bookmark_set_custom_name (NemoBookmark *bookmark, const char *new_name); gboolean nemo_bookmark_uri_get_exists (NemoBookmark *bookmark); int nemo_bookmark_compare_with (gconstpointer a, gconstpointer b); int nemo_bookmark_compare_uris (gconstpointer a, gconstpointer b); void nemo_bookmark_set_scroll_pos (NemoBookmark *bookmark, const char *uri); char * nemo_bookmark_get_scroll_pos (NemoBookmark *bookmark); /* Helper functions for displaying bookmarks */ GtkWidget * nemo_bookmark_menu_item_new (NemoBookmark *bookmark); void nemo_bookmark_connect (NemoBookmark *bookmark); /* Bookmark metadata struct functions */ NemoBookmarkMetadata *nemo_bookmark_get_updated_metadata (NemoBookmark *bookmark); NemoBookmarkMetadata *nemo_bookmark_get_current_metadata (NemoBookmark *bookmark); gboolean nemo_bookmark_metadata_compare (NemoBookmarkMetadata *d1, NemoBookmarkMetadata *d2); NemoBookmarkMetadata *nemo_bookmark_metadata_new (void); NemoBookmarkMetadata *nemo_bookmark_metadata_copy (NemoBookmarkMetadata *meta); void nemo_bookmark_metadata_free (NemoBookmarkMetadata *metadata); #endif /* NEMO_BOOKMARK_H */ nemo-4.4.2/libnemo-private/nemo-cell-renderer-disk.c000066400000000000000000000234621357442400300223400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-cell-renderer-disk.h" #include G_DEFINE_TYPE (NemoCellRendererDisk, nemo_cell_renderer_disk, GTK_TYPE_CELL_RENDERER_TEXT); static void nemo_cell_renderer_disk_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void nemo_cell_renderer_disk_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void nemo_cell_renderer_disk_finalize (GObject *gobject); static void nemo_cell_renderer_disk_render (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags); enum { PROP_DISK_FULL_PERCENTAGE = 1, PROP_SHOW_DISK_FULL_PERCENTAGE = 2, }; static gpointer parent_class; static void nemo_cell_renderer_disk_init (NemoCellRendererDisk *cell) { g_object_set (cell, "disk-full-percent", 0, "show-disk-full-percent", FALSE, NULL); } static void nemo_cell_renderer_disk_class_init (NemoCellRendererDiskClass *klass) { GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = nemo_cell_renderer_disk_finalize; object_class->get_property = nemo_cell_renderer_disk_get_property; object_class->set_property = nemo_cell_renderer_disk_set_property; cell_class->render = nemo_cell_renderer_disk_render; g_object_class_install_property (object_class, PROP_DISK_FULL_PERCENTAGE, g_param_spec_int ("disk-full-percent", "Percentage", "The fractional bar to display", -1, 100, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SHOW_DISK_FULL_PERCENTAGE, g_param_spec_boolean ("show-disk-full-percent", "Show Percentage Graph", "Whether to show the bar", FALSE, G_PARAM_READWRITE)); } GtkCellRenderer * nemo_cell_renderer_disk_new (void) { return g_object_new (NEMO_TYPE_CELL_RENDERER_DISK, NULL); } static void nemo_cell_renderer_disk_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } static void nemo_cell_renderer_disk_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *psec) { NemoCellRendererDisk *celldisk = NEMO_CELL_RENDERER_DISK (object); switch (param_id) { case PROP_DISK_FULL_PERCENTAGE: g_value_set_int(value, celldisk->disk_full_percent); break; case PROP_SHOW_DISK_FULL_PERCENTAGE: g_value_set_boolean(value, celldisk->show_disk_full_percent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec); break; } } static void nemo_cell_renderer_disk_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { NemoCellRendererDisk *celldisk = NEMO_CELL_RENDERER_DISK (object); switch (param_id) { case PROP_DISK_FULL_PERCENTAGE: celldisk->disk_full_percent = g_value_get_int (value); break; case PROP_SHOW_DISK_FULL_PERCENTAGE: celldisk->show_disk_full_percent = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } } static void convert_color (GdkColor *style_color, GdkRGBA *color) { color->red = style_color->red / 65535.0; color->green = style_color->green / 65535.0; color->blue = style_color->blue / 65535.0; color->alpha = 1; } static void use_default_color (GdkRGBA *color) { color->red = .5; color->green = .5; color->blue = .5; color->alpha = 1; } #define _270_DEG 270.0 * (M_PI/180.0) #define _180_DEG 180.0 * (M_PI/180.0) #define _90_DEG 90.0 * (M_PI/180.0) #define _0_DEG 0.0 static void cairo_rectangle_with_radius_corners (cairo_t *cr, gint x, gint y, gint w, gint h, gint rad) { cairo_move_to (cr, x+rad, y); cairo_line_to (cr, x+w-rad, y); cairo_arc (cr, x+w-rad, y+rad, rad, _270_DEG, _0_DEG); cairo_line_to (cr, x+w, y+h-rad); cairo_arc (cr, x+w-rad, y+h-rad, rad, _0_DEG, _90_DEG); cairo_line_to (cr, x+rad, y+h); cairo_arc (cr, x+rad, y+h-rad, rad, _90_DEG, _180_DEG); cairo_line_to (cr, x, y-rad); cairo_arc (cr, x+rad, y+rad, rad, _180_DEG, _270_DEG); } static void nemo_cell_renderer_disk_render (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) { NemoCellRendererDisk *cellprogress = NEMO_CELL_RENDERER_DISK (cell); gint x, y, w; gint xpad, ypad; gint full; gboolean show = cellprogress->show_disk_full_percent; GtkStyleContext *context; if (show) { context = gtk_widget_get_style_context (widget); GdkColor *gdk_bg_color, *gdk_fg_color; GdkRGBA bg_color, fg_color; gint bar_width, bar_radius, bottom_padding, max_length; gtk_style_context_get_style (context, "disk-full-bg-color", &gdk_bg_color, "disk-full-fg-color", &gdk_fg_color, "disk-full-bar-width", &bar_width, "disk-full-bar-radius", &bar_radius, "disk-full-bottom-padding", &bottom_padding, "disk-full-max-length", &max_length, NULL); if (gdk_bg_color) { convert_color (gdk_bg_color, &bg_color); gdk_color_free (gdk_bg_color); } else { use_default_color (&bg_color); } if (gdk_fg_color) { convert_color (gdk_fg_color, &fg_color); gdk_color_free (gdk_fg_color); } else { use_default_color (&fg_color); } gtk_cell_renderer_get_padding (cell, &xpad, &ypad); x = cell_area->x + xpad; y = cell_area->y + cell_area->height - bar_width - bottom_padding; w = cell_area->width - xpad * 2; w = w < max_length ? w : max_length; full = (int) (((float) cellprogress->disk_full_percent / 100.0) * (float) w); gtk_style_context_save (context); cairo_save (cr); gdk_cairo_set_source_rgba (cr, &bg_color); cairo_rectangle_with_radius_corners (cr, x, y, w, bar_width, bar_radius); cairo_fill (cr); cairo_restore (cr); cairo_save (cr); gdk_cairo_set_source_rgba (cr, &fg_color); cairo_rectangle_with_radius_corners (cr, x, y, full, bar_width, bar_radius); cairo_fill (cr); cairo_restore (cr); gtk_style_context_restore (context); } GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, cr, widget, background_area, cell_area, flags); } nemo-4.4.2/libnemo-private/nemo-cell-renderer-disk.h000066400000000000000000000042111357442400300223340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 2007 Martin Wehner 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Martin Wehner */ #ifndef NEMO_CELL_RENDERER_DISK_H #define NEMO_CELL_RENDERER_DISK_H #include #define NEMO_TYPE_CELL_RENDERER_DISK nemo_cell_renderer_disk_get_type() #define NEMO_CELL_RENDERER_DISK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_CELL_RENDERER_DISK, NemoCellRendererDisk)) #define NEMO_CELL_RENDERER_DISK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_CELL_RENDERER_DISK, NemoCellRendererDiskClass)) #define NEMO_IS_CELL_RENDERER_DISK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_CELL_RENDERER_DISK)) #define NEMO_IS_CELL_RENDERER_DISK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_CELL_RENDERER_DISK)) #define NEMO_CELL_RENDERER_DISK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_CELL_RENDERER_DISK, NemoCellRendererDiskClass)) typedef struct _NemoCellRendererDisk NemoCellRendererDisk; typedef struct _NemoCellRendererDiskClass NemoCellRendererDiskClass; struct _NemoCellRendererDisk { GtkCellRendererText parent; gint disk_full_percent; gboolean show_disk_full_percent; }; struct _NemoCellRendererDiskClass { GtkCellRendererTextClass parent_class; }; GType nemo_cell_renderer_disk_get_type (void); GtkCellRenderer *nemo_cell_renderer_disk_new (void); #endif /* NEMO_CELL_RENDERER_DISK_H */ nemo-4.4.2/libnemo-private/nemo-centered-placement-grid.c000066400000000000000000000533661357442400300233550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #include "math.h" #include #include "nemo-icon-private.h" #include "nemo-file.h" NemoCenteredPlacementGrid * nemo_centered_placement_grid_new (NemoIconContainer *container, gboolean horizontal) { NemoCenteredPlacementGrid *grid; gint width, height; gint num_columns; gint num_rows; gint i; gint snap_x, snap_y; gint icon_size; GtkAllocation allocation; /* Get container dimensions */ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); icon_size = nemo_get_desktop_icon_size_for_zoom_level (container->details->zoom_level); width = nemo_icon_container_get_canvas_width (container, allocation); height = nemo_icon_container_get_canvas_height (container, allocation); snap_x = GET_VIEW_CONSTANT (container, snap_size_x); snap_y = GET_VIEW_CONSTANT (container, snap_size_y); num_columns = width / snap_x; num_rows = height / snap_y; if (num_columns == 0 || num_rows == 0) { return NULL; } grid = g_new0 (NemoCenteredPlacementGrid, 1); grid->container = container; grid->horizontal = horizontal; grid->icon_size = icon_size; grid->real_snap_x = snap_x; grid->real_snap_y = snap_y; grid->num_columns = num_columns; grid->num_rows = num_rows; grid->borders = gtk_border_new (); grid->grid_memory = g_new0 (int, (num_rows * num_columns)); grid->icon_grid = g_new0 (int *, num_columns); for (i = 0; i < num_columns; i++) { grid->icon_grid[i] = grid->grid_memory + (i * num_rows); } grid->borders->left = (width - (num_columns * snap_x)) / 2; grid->borders->right = (width - (num_columns * snap_x)) / 2; grid->borders->top = (height - (num_rows * snap_y)) / 2; grid->borders->bottom = (height - (num_rows * snap_y)) / 2; return grid; } void nemo_centered_placement_grid_free (NemoCenteredPlacementGrid *grid) { if (grid == NULL) { return; } g_free (grid->icon_grid); g_free (grid->grid_memory); gtk_border_free (grid->borders); g_free (grid); } static gboolean nemo_centered_placement_grid_position_is_free (NemoCenteredPlacementGrid *grid, gint grid_x, gint grid_y) { g_assert (grid_x >= 0 && grid_x < grid->num_columns); g_assert (grid_y >= 0 && grid_y < grid->num_rows); return grid->icon_grid[grid_x][grid_y] == 0; } static void nemo_centered_placement_grid_mark (NemoCenteredPlacementGrid *grid, gint grid_x, gint grid_y) { g_assert (grid_x >= 0 && grid_x < grid->num_columns); g_assert (grid_y >= 0 && grid_y < grid->num_rows); grid->icon_grid[grid_x][grid_y] = 1; } static void nemo_centered_placement_grid_unmark (NemoCenteredPlacementGrid *grid, gint grid_x, gint grid_y) { g_assert (grid_x >= 0 && grid_x < grid->num_columns); g_assert (grid_y >= 0 && grid_y < grid->num_rows); grid->icon_grid[grid_x][grid_y] = 0; } static void nemo_centered_placement_grid_get_next_grid_position (NemoCenteredPlacementGrid *grid, gint x_in, gint y_in, gint *x_out, gint *y_out) { gint x, y; gboolean first_line; first_line = TRUE; x = y = 0; if (grid->horizontal) { for (y = y_in; y < grid->num_rows; y++) { for (x = first_line ? x_in : 0; x < grid->num_columns; x++) { first_line = FALSE; if (x != x_in || y != y_in) { goto out; } } } } else { for (x = x_in; x < grid->num_columns; x++) { for (y = first_line ? y_in : 0; y < grid->num_rows; y++) { first_line = FALSE; if (x != x_in || y != y_in) { goto out; } } } } out: *x_out = x; *y_out = y; } void nemo_centered_placement_grid_nominal_to_icon_position (NemoCenteredPlacementGrid *grid, NemoIcon *icon, gint x_nominal, gint y_nominal, gint *x_adjusted, gint *y_adjusted) { gint icon_width; if (icon != NULL) { EelDRect icon_bounds; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); icon_width = icon_bounds.x1 - icon_bounds.x0; } else { icon_width = grid->icon_size; } *x_adjusted = x_nominal + (grid->real_snap_x / 2) - (icon_width / 2); *y_adjusted = y_nominal + (grid->real_snap_y / 2) - GET_VIEW_CONSTANT (grid->container, icon_vertical_adjust); } void nemo_centered_placement_grid_icon_position_to_nominal (NemoCenteredPlacementGrid *grid, NemoIcon *icon, gint x_adjusted, gint y_adjusted, gint *x_nominal, gint *y_nominal) { gint icon_width; if (icon != NULL) { EelDRect icon_bounds; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); icon_width = icon_bounds.x1 - icon_bounds.x0; } else { icon_width = grid->icon_size; } *x_nominal = x_adjusted + (icon_width / 2) - (grid->real_snap_x / 2); *y_nominal = y_adjusted - (grid->real_snap_y / 2) + GET_VIEW_CONSTANT (grid->container, icon_vertical_adjust); } void nemo_centered_placement_grid_mark_icon (NemoCenteredPlacementGrid *grid, NemoIcon *icon) { gint grid_x, grid_y; GdkRectangle rect; if (icon->x <= 0.0 && icon->y <= 0.0) { return; } nemo_centered_placement_grid_get_current_position_rect (grid, icon->x, icon->y, &rect, NULL); grid_x = rect.x / grid->real_snap_x; grid_y = rect.y / grid->real_snap_y; if ((grid_x >= 0 && grid_x < grid->num_columns) && (grid_y >= 0 && grid_y < grid->num_rows)) { nemo_centered_placement_grid_mark (grid, grid_x, grid_y); } } void nemo_centered_placement_grid_unmark_icon (NemoCenteredPlacementGrid *grid, NemoIcon *icon) { gint grid_x, grid_y; GdkRectangle rect; if (icon->x <= 0.0 && icon->y <= 0.0) { return; } nemo_centered_placement_grid_get_current_position_rect (grid, icon->x, icon->y, &rect, NULL); grid_x = rect.x / grid->real_snap_x; grid_y = rect.y / grid->real_snap_y; if ((grid_x >= 0 && grid_x < grid->num_columns) && (grid_y >= 0 && grid_y < grid->num_rows)) { nemo_centered_placement_grid_unmark (grid, grid_x, grid_y); } } void nemo_centered_placement_grid_mark_position (NemoCenteredPlacementGrid *grid, gint x, gint y) { GdkRectangle rect; gint grid_x, grid_y; if (x < 0 && y < 0) { return; } nemo_centered_placement_grid_get_current_position_rect (grid, x, y, &rect, NULL); grid_x = rect.x / grid->real_snap_x; grid_y = rect.y / grid->real_snap_y; if ((grid_x >= 0 && grid_x < grid->num_columns) && (grid_y >= 0 && grid_y < grid->num_rows)) { nemo_centered_placement_grid_mark (grid, grid_x, grid_y); } } void nemo_centered_placement_grid_unmark_position (NemoCenteredPlacementGrid *grid, gint x, gint y) { GdkRectangle rect; gint grid_x, grid_y; if (x < 0 && y < 0) { return; } nemo_centered_placement_grid_get_current_position_rect (grid, x, y, &rect, NULL); grid_x = rect.x / grid->real_snap_x; grid_y = rect.y / grid->real_snap_y; if ((grid_x >= 0 && grid_x < grid->num_columns) && (grid_y >= 0 && grid_y < grid->num_rows)) { nemo_centered_placement_grid_unmark (grid, grid_x, grid_y); } } void nemo_centered_placement_grid_pre_populate (NemoCenteredPlacementGrid *grid, GList *icons, gboolean ignore_lazy) { GList *p; NemoIcon *icon; for (p = icons; p != NULL; p = p->next) { gboolean should_mark; icon = p->data; if (ignore_lazy) { should_mark = nemo_icon_container_icon_is_positioned (icon) && !icon->has_lazy_position; } else { should_mark = nemo_icon_container_icon_is_positioned (icon); } if (should_mark) { nemo_centered_placement_grid_mark_icon (grid, icon); } } } void nemo_centered_placement_grid_get_next_position_rect (NemoCenteredPlacementGrid *grid, GdkRectangle *in_rect, GdkRectangle *out_rect, gboolean *is_free) { gint index_x, index_y, next_index_x, next_index_y; gint x, y; x = in_rect->x - grid->borders->left; y = in_rect->y - grid->borders->top; index_x = x / grid->real_snap_x; index_y = y / grid->real_snap_y; index_x = CLAMP (index_x, 0, grid->num_columns - 1); index_y = CLAMP (index_y, 0, grid->num_rows - 1); nemo_centered_placement_grid_get_next_grid_position (grid, index_x, index_y, &next_index_x, &next_index_y); next_index_x = CLAMP (next_index_x, 0, grid->num_columns - 1); next_index_y = CLAMP (next_index_y, 0, grid->num_rows - 1); out_rect->x = next_index_x * grid->real_snap_x; out_rect->y = next_index_y * grid->real_snap_y; out_rect->width = grid->real_snap_x; out_rect->height = grid->real_snap_y; out_rect->x += grid->borders->left; out_rect->y += grid->borders->top; if (is_free) { if ((next_index_x == grid->num_columns - 1) && (next_index_y == grid->num_rows - 1)) { /* Last position of the grid is our escape valve when our number if icons * exceeds possible positions in the grid - we'll allow icons to overlap * here (what else can we do? Shrink the grid till everything fits? That * could also be broken - sooner or later we need this) */ *is_free = TRUE; } else { *is_free = nemo_centered_placement_grid_position_is_free (grid, next_index_x, next_index_y); } } } void nemo_centered_placement_grid_get_current_position_rect (NemoCenteredPlacementGrid *grid, gint x, gint y, GdkRectangle *rect, gboolean *is_free) { gint index_x, index_y; x -= grid->borders->left; y -= grid->borders->top; index_x = x / grid->real_snap_x; index_y = y / grid->real_snap_y; index_x = CLAMP (index_x, 0, grid->num_columns - 1); index_y = CLAMP (index_y, 0, grid->num_rows - 1); rect->x = index_x * grid->real_snap_x; rect->y = index_y * grid->real_snap_y; rect->width = grid->real_snap_x; rect->height = grid->real_snap_y; rect->x += grid->borders->left; rect->y += grid->borders->top; if (is_free) { if ((index_x == grid->num_columns - 1) && (index_y == grid->num_rows - 1)) { /* Last position of the grid is our escape valve when our number if icons * exceeds possible positions in the grid - we'll allow icons to overlap * here (what else can we do? Shrink the grid till everything fits? That * could also be broken - sooner or later we need this) */ *is_free = TRUE; } else { *is_free = nemo_centered_placement_grid_position_is_free (grid, index_x, index_y); } } } static NemoIcon * get_icon_at_grid_position (NemoCenteredPlacementGrid *grid, gint grid_x, gint grid_y) { NemoIcon *icon; GList *l; for (l = grid->container->details->icons; l != NULL; l = l->next) { GdkRectangle rect; gint icon_grid_x, icon_grid_y; icon = l->data; nemo_centered_placement_grid_get_current_position_rect (grid, icon->x, icon->y, &rect, NULL); icon_grid_x = rect.x / grid->real_snap_x; icon_grid_y = rect.y / grid->real_snap_y; if (grid_x == icon_grid_x && grid_y == icon_grid_y) { return icon; } } return NULL; } GList * nemo_centered_placement_grid_clear_grid_for_selection (NemoCenteredPlacementGrid *grid, gint start_x, gint start_y, GList *drag_sel_list) { NemoDragSelectionItem *item; NemoIcon *icon; GList *ret_list, *icon_list, *p; GdkRectangle grid_rect; gboolean is_free; gboolean insert_before, first_line; gint grid_x, grid_y, new_grid_x, new_grid_y, iter_x, iter_y, icon_new_x, icon_new_y; gint space_needed; start_x -= grid->borders->left; start_y -= grid->borders->top; /* We need to have space_needed number of contiguous positions in the grid */ space_needed = g_list_length (drag_sel_list); /* Find where we're starting from, whether inserting before or after the current * item */ nemo_centered_placement_grid_get_current_position_rect (grid, start_x, start_y, &grid_rect, &is_free); grid_x = grid_rect.x / grid->real_snap_x; grid_y = grid_rect.y / grid->real_snap_y; insert_before = TRUE; if (!is_free) { if (grid->horizontal) { insert_before = (start_x >= grid_rect.x) && (start_x < grid_rect.x + (grid_rect.width / 2)); } else { insert_before = (start_y >= grid_rect.y) && (start_y < grid_rect.y + (grid_rect.height / 2)); } } if (!insert_before) { nemo_centered_placement_grid_get_next_grid_position (grid, grid_x, grid_y, &new_grid_x, &new_grid_y); } else { new_grid_x = grid_x; new_grid_y = grid_y; } /* Iterate thru the grid, starting at our insertion position, pick up existing icons that are in * the way until we have enough free space to lay down the original selection plus these icons. */ first_line = TRUE; icon_list = NULL; if (grid->horizontal) { for (iter_y = new_grid_y; iter_y < grid->num_rows; iter_y++) { for (iter_x = first_line ? new_grid_x : 0; iter_x < grid->num_columns; iter_x++) { first_line = FALSE; if (nemo_centered_placement_grid_position_is_free (grid, iter_x, iter_y)) { space_needed--; } else { icon = get_icon_at_grid_position (grid, iter_x, iter_y); icon_list = g_list_prepend (icon_list, icon); nemo_centered_placement_grid_unmark (grid, iter_x, iter_y); } if (space_needed == 0) { goto done_collecting; } } } } else { for (iter_x = new_grid_x; iter_x < grid->num_columns; iter_x++) { for (iter_y = first_line ? new_grid_y : 0; iter_y < grid->num_rows; iter_y++) { first_line = FALSE; if (nemo_centered_placement_grid_position_is_free (grid, iter_x, iter_y)) { space_needed--; } else { icon = get_icon_at_grid_position (grid, iter_x, iter_y); icon_list = g_list_prepend (icon_list, icon); nemo_centered_placement_grid_unmark (grid, iter_x, iter_y); } if (space_needed == 0) { goto done_collecting; } } } } done_collecting: /* Now go thru the original selection list, and modify their target positions to our grid positions */ icon_list = g_list_reverse (icon_list); iter_x = new_grid_x; iter_y = new_grid_y; for (p = drag_sel_list; p != NULL; p = p->next) { item = p->data; icon = nemo_icon_container_get_icon_by_uri (grid->container, item->uri); nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, /* May be NULL if not a desktop item */ iter_x * grid->real_snap_x, iter_y * grid->real_snap_y, &icon_new_x, &icon_new_y); item->got_icon_position = TRUE; item->icon_x = icon_new_x - start_x; item->icon_y = icon_new_y - start_y; nemo_centered_placement_grid_get_next_grid_position (grid, iter_x, iter_y, &iter_x, &iter_y); } /* Build a NemoDragSelectionItem list from the NemoIcon list we picked up, setting the appropriate positions * following the original selection */ ret_list = NULL; for (p = icon_list; p != NULL; p = p->next) { icon = p->data; nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, iter_x * grid->real_snap_x, iter_y * grid->real_snap_y, &icon_new_x, &icon_new_y); item = nemo_drag_selection_item_new (); item->uri = nemo_file_get_uri (NEMO_FILE (icon->data)); item->got_icon_position = TRUE; item->icon_x = icon_new_x - start_x; item->icon_y = icon_new_y - start_y; item->icon_width = grid->icon_size; item->icon_height = grid->icon_size; ret_list = g_list_prepend (ret_list, item); nemo_centered_placement_grid_get_next_grid_position (grid, iter_x, iter_y, &iter_x, &iter_y); } ret_list = g_list_reverse (ret_list); /* Return the 'push list' - extra icons to be moved, but behind the scenes, that won't be * selected once the drop is complete */ return ret_list; } nemo-4.4.2/libnemo-private/nemo-clipboard-monitor.c000066400000000000000000000204001357442400300222760ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-clipboard-monitor.c: catch clipboard changes. Copyright (C) 2004 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-clipboard-monitor.h" #include "nemo-file.h" #include #include /* X11 has a weakness when it comes to clipboard handling, * there is no way to get told when the owner of the clipboard * changes. This is often needed, for instance to set the * sensitivity of the paste menu item. We work around this * internally in an app by telling the clipboard monitor when * we changed the clipboard. Unfortunately this doesn't give * us perfect results, we still don't catch changes made by * other clients * * This is fixed with the XFIXES extensions, which recent versions * of Gtk+ supports as the owner_change signal on GtkClipboard. We * use this now, but keep the old code since not all X servers support * XFIXES. */ enum { CLIPBOARD_CHANGED, CLIPBOARD_INFO, LAST_SIGNAL }; struct NemoClipboardMonitorDetails { NemoClipboardInfo *info; }; static guint signals[LAST_SIGNAL] = { 0 }; static GdkAtom copied_files_atom; G_DEFINE_TYPE (NemoClipboardMonitor, nemo_clipboard_monitor, G_TYPE_OBJECT); static NemoClipboardMonitor *clipboard_monitor = NULL; static void destroy_clipboard_monitor (void) { if (clipboard_monitor != NULL) { g_object_unref (clipboard_monitor); } } NemoClipboardMonitor * nemo_clipboard_monitor_get (void) { GtkClipboard *clipboard; if (clipboard_monitor == NULL) { clipboard_monitor = NEMO_CLIPBOARD_MONITOR (g_object_new (NEMO_TYPE_CLIPBOARD_MONITOR, NULL)); eel_debug_call_at_shutdown (destroy_clipboard_monitor); clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); g_signal_connect (clipboard, "owner_change", G_CALLBACK (nemo_clipboard_monitor_emit_changed), NULL); } return clipboard_monitor; } void nemo_clipboard_monitor_emit_changed (void) { NemoClipboardMonitor *monitor; monitor = nemo_clipboard_monitor_get (); g_signal_emit (monitor, signals[CLIPBOARD_CHANGED], 0); } static NemoClipboardInfo * nemo_clipboard_info_new (GList *files, gboolean cut) { NemoClipboardInfo *info; info = g_slice_new0 (NemoClipboardInfo); info->files = nemo_file_list_copy (files); info->cut = cut; return info; } static NemoClipboardInfo * nemo_clipboard_info_copy (NemoClipboardInfo *info) { NemoClipboardInfo *new_info; new_info = NULL; if (info != NULL) { new_info = nemo_clipboard_info_new (info->files, info->cut); } return new_info; } static void nemo_clipboard_info_free (NemoClipboardInfo *info) { nemo_file_list_free (info->files); g_slice_free (NemoClipboardInfo, info); } static void nemo_clipboard_monitor_init (NemoClipboardMonitor *monitor) { monitor->details = G_TYPE_INSTANCE_GET_PRIVATE (monitor, NEMO_TYPE_CLIPBOARD_MONITOR, NemoClipboardMonitorDetails); } static void clipboard_monitor_finalize (GObject *object) { NemoClipboardMonitor *monitor; monitor = NEMO_CLIPBOARD_MONITOR (object); if (monitor->details->info != NULL) { nemo_clipboard_info_free (monitor->details->info); monitor->details->info = NULL; } G_OBJECT_CLASS (nemo_clipboard_monitor_parent_class)->finalize (object); } static void nemo_clipboard_monitor_class_init (NemoClipboardMonitorClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = clipboard_monitor_finalize; copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); signals[CLIPBOARD_CHANGED] = g_signal_new ("clipboard_changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoClipboardMonitorClass, clipboard_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[CLIPBOARD_INFO] = g_signal_new ("clipboard_info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoClipboardMonitorClass, clipboard_info), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); g_type_class_add_private (klass, sizeof (NemoClipboardMonitorDetails)); } void nemo_clipboard_monitor_set_clipboard_info (NemoClipboardMonitor *monitor, NemoClipboardInfo *info) { if (monitor->details->info != NULL) { nemo_clipboard_info_free (monitor->details->info); monitor->details->info = NULL; } monitor->details->info = nemo_clipboard_info_copy (info); g_signal_emit (monitor, signals[CLIPBOARD_INFO], 0, monitor->details->info); nemo_clipboard_monitor_emit_changed (); } NemoClipboardInfo * nemo_clipboard_monitor_get_clipboard_info (NemoClipboardMonitor *monitor) { return monitor->details->info; } void nemo_clear_clipboard_callback (GtkClipboard *clipboard, gpointer user_data) { nemo_clipboard_monitor_set_clipboard_info (nemo_clipboard_monitor_get (), NULL); } static char * convert_file_list_to_string (NemoClipboardInfo *info, gboolean format_for_text, gsize *len) { GString *uris; char *uri, *tmp; GFile *f; guint i; GList *l; if (format_for_text) { uris = g_string_new (NULL); } else { uris = g_string_new (info->cut ? "cut" : "copy"); } for (i = 0, l = info->files; l != NULL; l = l->next, i++) { uri = nemo_file_get_uri (l->data); if (format_for_text) { f = g_file_new_for_uri (uri); tmp = g_file_get_parse_name (f); g_object_unref (f); if (tmp != NULL) { g_string_append (uris, tmp); g_free (tmp); } else { g_string_append (uris, uri); } /* skip newline for last element */ if (i + 1 < g_list_length (info->files)) { g_string_append_c (uris, '\n'); } } else { g_string_append_c (uris, '\n'); g_string_append (uris, uri); } g_free (uri); } *len = uris->len; return g_string_free (uris, FALSE); } void nemo_get_clipboard_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data) { char **uris; GList *l; int i; NemoClipboardInfo *clipboard_info; GdkAtom target; clipboard_info = nemo_clipboard_monitor_get_clipboard_info (nemo_clipboard_monitor_get ()); target = gtk_selection_data_get_target (selection_data); if (gtk_targets_include_uri (&target, 1)) { uris = g_malloc ((g_list_length (clipboard_info->files) + 1) * sizeof (char *)); i = 0; for (l = clipboard_info->files; l != NULL; l = l->next) { uris[i] = nemo_file_get_uri (l->data); i++; } uris[i] = NULL; gtk_selection_data_set_uris (selection_data, uris); g_strfreev (uris); } else if (gtk_targets_include_text (&target, 1)) { char *str; gsize len; str = convert_file_list_to_string (clipboard_info, TRUE, &len); gtk_selection_data_set_text (selection_data, str, len); g_free (str); } else if (target == copied_files_atom) { char *str; gsize len; str = convert_file_list_to_string (clipboard_info, FALSE, &len); gtk_selection_data_set (selection_data, copied_files_atom, 8, (guchar *) str, len); g_free (str); } } nemo-4.4.2/libnemo-private/nemo-clipboard-monitor.h000066400000000000000000000061061357442400300223120ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-clipboard-monitor.h: lets you notice clipboard changes. Copyright (C) 2004 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_CLIPBOARD_MONITOR_H #define NEMO_CLIPBOARD_MONITOR_H #include #define NEMO_TYPE_CLIPBOARD_MONITOR nemo_clipboard_monitor_get_type() #define NEMO_CLIPBOARD_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_CLIPBOARD_MONITOR, NemoClipboardMonitor)) #define NEMO_CLIPBOARD_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_CLIPBOARD_MONITOR, NemoClipboardMonitorClass)) #define NEMO_IS_CLIPBOARD_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_CLIPBOARD_MONITOR)) #define NEMO_IS_CLIPBOARD_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_CLIPBOARD_MONITOR)) #define NEMO_CLIPBOARD_MONITOR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_CLIPBOARD_MONITOR, NemoClipboardMonitorClass)) typedef struct NemoClipboardMonitorDetails NemoClipboardMonitorDetails; typedef struct NemoClipboardInfo NemoClipboardInfo; typedef struct { GObject parent_slot; NemoClipboardMonitorDetails *details; } NemoClipboardMonitor; typedef struct { GObjectClass parent_slot; void (* clipboard_changed) (NemoClipboardMonitor *monitor); void (* clipboard_info) (NemoClipboardMonitor *monitor, NemoClipboardInfo *info); } NemoClipboardMonitorClass; struct NemoClipboardInfo { GList *files; gboolean cut; }; GType nemo_clipboard_monitor_get_type (void); NemoClipboardMonitor * nemo_clipboard_monitor_get (void); void nemo_clipboard_monitor_set_clipboard_info (NemoClipboardMonitor *monitor, NemoClipboardInfo *info); NemoClipboardInfo * nemo_clipboard_monitor_get_clipboard_info (NemoClipboardMonitor *monitor); void nemo_clipboard_monitor_emit_changed (void); void nemo_clear_clipboard_callback (GtkClipboard *clipboard, gpointer user_data); void nemo_get_clipboard_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data); #endif /* NEMO_CLIPBOARD_MONITOR_H */ nemo-4.4.2/libnemo-private/nemo-clipboard.c000066400000000000000000000426371357442400300206310ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-clipboard.c * * Nemo Clipboard support. For now, routines to support component cut * and paste. * * Copyright (C) 1999, 2000 Free Software Foundaton * Copyright (C) 2000, 2001 Eazel, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Rebecca Schulman , * Darin Adler */ #include #include "nemo-clipboard.h" #include "nemo-file-utilities.h" #include #include #include typedef struct _TargetCallbackData TargetCallbackData; typedef void (* SelectAllCallback) (gpointer target); typedef void (* ConnectCallbacksFunc) (GObject *object, TargetCallbackData *target_data); static void selection_changed_callback (GtkWidget *widget, gpointer callback_data); static void owner_change_callback (GtkClipboard *clipboard, GdkEventOwnerChange *event, gpointer callback_data); struct _TargetCallbackData { GtkUIManager *ui_manager; GtkActionGroup *action_group; gboolean shares_selection_changes; SelectAllCallback select_all_callback; ConnectCallbacksFunc connect_callbacks; ConnectCallbacksFunc disconnect_callbacks; }; static void cut_callback (gpointer target) { g_assert (target != NULL); g_signal_emit_by_name (target, "cut-clipboard"); } static void copy_callback (gpointer target) { g_assert (target != NULL); g_signal_emit_by_name (target, "copy-clipboard"); } static void paste_callback (gpointer target) { g_assert (target != NULL); g_signal_emit_by_name (target, "paste-clipboard"); } static void editable_select_all_callback (gpointer target) { GtkEditable *editable; editable = GTK_EDITABLE (target); g_assert (editable != NULL); gtk_editable_set_position (editable, -1); gtk_editable_select_region (editable, 0, -1); } static void text_view_select_all_callback (gpointer target) { g_assert (GTK_IS_TEXT_VIEW (target)); g_signal_emit_by_name (target, "select-all", TRUE); } static void action_cut_callback (GtkAction *action, gpointer callback_data) { cut_callback (callback_data); } static void action_copy_callback (GtkAction *action, gpointer callback_data) { copy_callback (callback_data); } static void action_paste_callback (GtkAction *action, gpointer callback_data) { paste_callback (callback_data); } static void action_select_all_callback (GtkAction *action, gpointer callback_data) { TargetCallbackData *target_data; g_assert (callback_data != NULL); target_data = g_object_get_data (callback_data, "Nemo:clipboard_target_data"); g_assert (target_data != NULL); target_data->select_all_callback (callback_data); } static void received_clipboard_contents (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) { GtkActionGroup *action_group; GtkAction *action; action_group = data; action = gtk_action_group_get_action (action_group, "Paste"); if (action != NULL) { gtk_action_set_sensitive (action, gtk_selection_data_targets_include_text (selection_data)); } g_object_unref (action_group); } static void set_paste_sensitive_if_clipboard_contains_data (GtkActionGroup *action_group) { GtkAction *action; if (gdk_display_supports_selection_notification (gdk_display_get_default ())) { gtk_clipboard_request_contents (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), gdk_atom_intern ("TARGETS", FALSE), received_clipboard_contents, g_object_ref (action_group)); } else { /* If selection notification isn't supported, always activate Paste */ action = gtk_action_group_get_action (action_group, "Paste"); gtk_action_set_sensitive (action, TRUE); } } static void set_clipboard_menu_items_sensitive (GtkActionGroup *action_group) { GtkAction *action; action = gtk_action_group_get_action (action_group, "Cut"); gtk_action_set_sensitive (action, TRUE); action = gtk_action_group_get_action (action_group, "Copy"); gtk_action_set_sensitive (action, TRUE); } static void set_clipboard_menu_items_insensitive (GtkActionGroup *action_group) { GtkAction *action; action = gtk_action_group_get_action (action_group, "Cut"); gtk_action_set_sensitive (action, FALSE); action = gtk_action_group_get_action (action_group, "Copy"); gtk_action_set_sensitive (action, FALSE); } static gboolean clipboard_items_are_merged_in (GtkWidget *widget) { return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "Nemo:clipboard_menu_items_merged")); } static void set_clipboard_items_are_merged_in (GObject *widget_as_object, gboolean merged_in) { g_object_set_data (widget_as_object, "Nemo:clipboard_menu_items_merged", GINT_TO_POINTER (merged_in)); } static void editable_connect_callbacks (GObject *object, TargetCallbackData *target_data) { g_signal_connect_after (object, "selection_changed", G_CALLBACK (selection_changed_callback), target_data); selection_changed_callback (GTK_WIDGET (object), target_data); } static void editable_disconnect_callbacks (GObject *object, TargetCallbackData *target_data) { g_signal_handlers_disconnect_matched (object, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, G_CALLBACK (selection_changed_callback), target_data); } static void text_buffer_update_sensitivity (GtkTextBuffer *buffer, TargetCallbackData *target_data) { g_assert (GTK_IS_TEXT_BUFFER (buffer)); g_assert (target_data != NULL); if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { set_clipboard_menu_items_sensitive (target_data->action_group); } else { set_clipboard_menu_items_insensitive (target_data->action_group); } } static void text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *iter1, GtkTextIter *iter2, TargetCallbackData *target_data) { text_buffer_update_sensitivity (buffer, target_data); } static void text_buffer_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark, TargetCallbackData *target_data) { /* anonymous marks with NULL names refer to cursor moves */ if (gtk_text_mark_get_name (mark) != NULL) { text_buffer_update_sensitivity (buffer, target_data); } } static void text_view_connect_callbacks (GObject *object, TargetCallbackData *target_data) { GtkTextBuffer *buffer; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object)); g_assert (buffer); g_signal_connect_after (buffer, "mark-set", G_CALLBACK (text_buffer_mark_set), target_data); g_signal_connect_after (buffer, "delete-range", G_CALLBACK (text_buffer_delete_range), target_data); text_buffer_update_sensitivity (buffer, target_data); } static void text_view_disconnect_callbacks (GObject *object, TargetCallbackData *target_data) { GtkTextBuffer *buffer; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object)); g_assert (buffer); g_signal_handlers_disconnect_matched (buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, target_data); } static void merge_in_clipboard_menu_items (GObject *widget_as_object, TargetCallbackData *target_data) { gboolean add_selection_callback; g_assert (target_data != NULL); add_selection_callback = target_data->shares_selection_changes; gtk_ui_manager_insert_action_group (target_data->ui_manager, target_data->action_group, 0); set_paste_sensitive_if_clipboard_contains_data (target_data->action_group); g_signal_connect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), "owner_change", G_CALLBACK (owner_change_callback), target_data); if (add_selection_callback) { target_data->connect_callbacks (widget_as_object, target_data); } else { /* If we don't use sensitivity, everything should be on */ set_clipboard_menu_items_sensitive (target_data->action_group); } set_clipboard_items_are_merged_in (widget_as_object, TRUE); } static void merge_out_clipboard_menu_items (GObject *widget_as_object, TargetCallbackData *target_data) { gboolean selection_callback_was_added; g_assert (target_data != NULL); gtk_ui_manager_remove_action_group (target_data->ui_manager, target_data->action_group); g_signal_handlers_disconnect_matched (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, G_CALLBACK (owner_change_callback), target_data); selection_callback_was_added = target_data->shares_selection_changes; if (selection_callback_was_added) { target_data->disconnect_callbacks (widget_as_object, target_data); } set_clipboard_items_are_merged_in (widget_as_object, FALSE); } static gboolean focus_changed_callback (GtkWidget *widget, GdkEventAny *event, gpointer callback_data) { /* Connect the component to the container if the widget has focus. */ if (gtk_widget_has_focus (widget)) { if (!clipboard_items_are_merged_in (widget)) { merge_in_clipboard_menu_items (G_OBJECT (widget), callback_data); } } else { if (clipboard_items_are_merged_in (widget)) { merge_out_clipboard_menu_items (G_OBJECT (widget), callback_data); } } return FALSE; } static void selection_changed_callback (GtkWidget *widget, gpointer callback_data) { TargetCallbackData *target_data; GtkEditable *editable; int start, end; target_data = (TargetCallbackData *) callback_data; g_assert (target_data != NULL); editable = GTK_EDITABLE (widget); g_assert (editable != NULL); if (gtk_editable_get_selection_bounds (editable, &start, &end) && start != end) { set_clipboard_menu_items_sensitive (target_data->action_group); } else { set_clipboard_menu_items_insensitive (target_data->action_group); } } static void owner_change_callback (GtkClipboard *clipboard, GdkEventOwnerChange *event, gpointer callback_data) { TargetCallbackData *target_data; g_assert (callback_data != NULL); target_data = callback_data; set_paste_sensitive_if_clipboard_contains_data (target_data->action_group); } static void target_destroy_callback (GtkWidget *object, gpointer callback_data) { g_assert (callback_data != NULL); if (clipboard_items_are_merged_in (object)) { merge_out_clipboard_menu_items (G_OBJECT (object), callback_data); } } static void target_data_free (TargetCallbackData *target_data) { g_object_unref (target_data->action_group); g_free (target_data); } static const GtkActionEntry clipboard_entries[] = { /* name, stock id */ { "Cut", GTK_STOCK_CUT, /* label, accelerator */ NULL, NULL, /* tooltip */ N_("Cut the selected text to the clipboard"), G_CALLBACK (action_cut_callback) }, /* name, stock id */ { "Copy", GTK_STOCK_COPY, /* label, accelerator */ NULL, NULL, /* tooltip */ N_("Copy the selected text to the clipboard"), G_CALLBACK (action_copy_callback) }, /* name, stock id */ { "Paste", GTK_STOCK_PASTE, /* label, accelerator */ NULL, NULL, /* tooltip */ N_("Paste the text stored on the clipboard"), G_CALLBACK (action_paste_callback) }, /* name, stock id */ { "Select All", NULL, /* label, accelerator */ N_("Select _All"), "A", /* tooltip */ N_("Select all the text in a text field"), G_CALLBACK (action_select_all_callback) }, }; static TargetCallbackData * initialize_clipboard_component_with_callback_data (GtkEditable *target, GtkUIManager *ui_manager, gboolean shares_selection_changes, SelectAllCallback select_all_callback, ConnectCallbacksFunc connect_callbacks, ConnectCallbacksFunc disconnect_callbacks) { GtkActionGroup *action_group; TargetCallbackData *target_data; action_group = gtk_action_group_new ("ClipboardActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions (action_group, clipboard_entries, G_N_ELEMENTS (clipboard_entries), target); /* Do the actual connection of the UI to the container at * focus time, and disconnect at both focus and destroy * time. */ target_data = g_new (TargetCallbackData, 1); target_data->ui_manager = ui_manager; target_data->action_group = action_group; target_data->shares_selection_changes = shares_selection_changes; target_data->select_all_callback = select_all_callback; target_data->connect_callbacks = connect_callbacks; target_data->disconnect_callbacks = disconnect_callbacks; return target_data; } static void nemo_clipboard_real_set_up (gpointer target, GtkUIManager *ui_manager, gboolean shares_selection_changes, SelectAllCallback select_all_callback, ConnectCallbacksFunc connect_callbacks, ConnectCallbacksFunc disconnect_callbacks) { TargetCallbackData *target_data; if (g_object_get_data (G_OBJECT (target), "Nemo:clipboard_target_data") != NULL) { return; } target_data = initialize_clipboard_component_with_callback_data (target, ui_manager, shares_selection_changes, select_all_callback, connect_callbacks, disconnect_callbacks); g_signal_connect (target, "focus_in_event", G_CALLBACK (focus_changed_callback), target_data); g_signal_connect (target, "focus_out_event", G_CALLBACK (focus_changed_callback), target_data); g_signal_connect (target, "destroy", G_CALLBACK (target_destroy_callback), target_data); g_object_set_data_full (G_OBJECT (target), "Nemo:clipboard_target_data", target_data, (GDestroyNotify) target_data_free); /* Call the focus changed callback once to merge if the window is * already in focus. */ focus_changed_callback (GTK_WIDGET (target), NULL, target_data); } void nemo_clipboard_set_up_editable (GtkEditable *target, GtkUIManager *ui_manager, gboolean shares_selection_changes) { g_return_if_fail (GTK_IS_EDITABLE (target)); g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); nemo_clipboard_real_set_up (target, ui_manager, shares_selection_changes, editable_select_all_callback, editable_connect_callbacks, editable_disconnect_callbacks); } void nemo_clipboard_set_up_text_view (GtkTextView *target, GtkUIManager *ui_manager) { g_return_if_fail (GTK_IS_TEXT_VIEW (target)); g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); nemo_clipboard_real_set_up (target, ui_manager, TRUE, text_view_select_all_callback, text_view_connect_callbacks, text_view_disconnect_callbacks); } static GList * convert_lines_to_str_list (char **lines, gboolean *cut) { int i; GList *result; if (cut) { *cut = FALSE; } if (lines[0] == NULL) { return NULL; } if (strcmp (lines[0], "cut") == 0) { if (cut) { *cut = TRUE; } } else if (strcmp (lines[0], "copy") != 0) { return NULL; } result = NULL; for (i = 1; lines[i] != NULL; i++) { result = g_list_prepend (result, g_strdup (lines[i])); } return g_list_reverse (result); } GList* nemo_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection_data, gboolean *cut, GdkAtom copied_files_atom) { GList *items; char **lines; if (gtk_selection_data_get_data_type (selection_data) != copied_files_atom || gtk_selection_data_get_length (selection_data) <= 0) { items = NULL; } else { gchar *data; /* Not sure why it's legal to assume there's an extra byte * past the end of the selection data that it's safe to write * to. But gtk_editable_selection_received does this, so I * think it is OK. */ data = (gchar *) gtk_selection_data_get_data (selection_data); data[gtk_selection_data_get_length (selection_data)] = '\0'; lines = g_strsplit (data, "\n", 0); items = convert_lines_to_str_list (lines, cut); g_strfreev (lines); } return items; } GtkClipboard * nemo_clipboard_get (GtkWidget *widget) { return gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (widget)), GDK_SELECTION_CLIPBOARD); } void nemo_clipboard_clear_if_colliding_uris (GtkWidget *widget, const GList *item_uris, GdkAtom copied_files_atom) { GtkSelectionData *data; GList *clipboard_item_uris, *l; gboolean collision; collision = FALSE; data = gtk_clipboard_wait_for_contents (nemo_clipboard_get (widget), copied_files_atom); if (data == NULL) { return; } clipboard_item_uris = nemo_clipboard_get_uri_list_from_selection_data (data, NULL, copied_files_atom); for (l = (GList *) item_uris; l; l = l->next) { if (g_list_find_custom ((GList *) item_uris, l->data, (GCompareFunc) g_strcmp0)) { collision = TRUE; break; } } if (collision) { gtk_clipboard_clear (nemo_clipboard_get (widget)); } if (clipboard_item_uris) { g_list_free_full (clipboard_item_uris, g_free); } } nemo-4.4.2/libnemo-private/nemo-clipboard.h000066400000000000000000000044051357442400300206250ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-directory-view.h * * Copyright (C) 1999, 2000 Free Software Foundaton * Copyright (C) 2000 Eazel, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Rebecca Schulman */ #ifndef NEMO_CLIPBOARD_H #define NEMO_CLIPBOARD_H #include /* This makes this editable or text view put clipboard commands into * the passed UI manager when the editable/text view is in focus. * Callers in Nemo normally get the UI manager from * nemo_window_get_ui_manager. */ /* The shares selection changes argument should be set to true if the * widget uses the signal "selection_changed" to tell others about * text selection changes. The NemoEntry widget * is currently the only editable in nemo that shares selection * changes. */ void nemo_clipboard_set_up_editable (GtkEditable *target, GtkUIManager *ui_manager, gboolean shares_selection_changes); void nemo_clipboard_set_up_text_view (GtkTextView *target, GtkUIManager *ui_manager); void nemo_clipboard_clear_if_colliding_uris (GtkWidget *widget, const GList *item_uris, GdkAtom copied_files_atom); GtkClipboard* nemo_clipboard_get (GtkWidget *widget); GList* nemo_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection_data, gboolean *cut, GdkAtom copied_files_atom); #endif /* NEMO_CLIPBOARD_H */ nemo-4.4.2/libnemo-private/nemo-column-chooser.c000066400000000000000000000411451357442400300216200ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-column-chooser.h - A column chooser widget Copyright (C) 2004 Novell, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the column COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Dave Camp */ #include #include "nemo-column-chooser.h" #include #include #include #include "nemo-column-utilities.h" struct _NemoColumnChooserDetails { GtkTreeView *view; GtkListStore *store; GtkWidget *move_up_button; GtkWidget *move_down_button; GtkWidget *use_default_button; NemoFile *file; }; enum { COLUMN_VISIBLE, COLUMN_LABEL, COLUMN_NAME, COLUMN_TOGGLE_SENSITIVE, NUM_COLUMNS }; enum { PROP_FILE = 1, NUM_PROPERTIES }; enum { CHANGED, USE_DEFAULT, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE(NemoColumnChooser, nemo_column_chooser, GTK_TYPE_BOX); static void nemo_column_chooser_constructed (GObject *object); static void nemo_column_chooser_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { NemoColumnChooser *chooser; chooser = NEMO_COLUMN_CHOOSER (object); switch (param_id) { case PROP_FILE: chooser->details->file = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_column_chooser_class_init (NemoColumnChooserClass *chooser_class) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (chooser_class); oclass->set_property = nemo_column_chooser_set_property; oclass->constructed = nemo_column_chooser_constructed; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (chooser_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoColumnChooserClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[USE_DEFAULT] = g_signal_new ("use_default", G_TYPE_FROM_CLASS (chooser_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoColumnChooserClass, use_default), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_object_class_install_property (oclass, PROP_FILE, g_param_spec_object ("file", "File", "The file this column chooser is for", NEMO_TYPE_FILE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); g_type_class_add_private (chooser_class, sizeof (NemoColumnChooserDetails)); } static void update_buttons (NemoColumnChooser *chooser) { GtkTreeSelection *selection; GtkTreeIter iter; selection = gtk_tree_view_get_selection (chooser->details->view); if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { gboolean visible; gboolean top; gboolean bottom; GtkTreePath *first; GtkTreePath *path; gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), &iter, COLUMN_VISIBLE, &visible, -1); path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store), &iter); first = gtk_tree_path_new_first (); top = (gtk_tree_path_compare (path, first) == 0); gtk_tree_path_free (path); gtk_tree_path_free (first); bottom = !gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter); gtk_widget_set_sensitive (chooser->details->move_up_button, !top); gtk_widget_set_sensitive (chooser->details->move_down_button, !bottom); } else { gtk_widget_set_sensitive (chooser->details->move_up_button, FALSE); gtk_widget_set_sensitive (chooser->details->move_down_button, FALSE); } } static void list_changed (NemoColumnChooser *chooser) { update_buttons (chooser); g_signal_emit (chooser, signals[CHANGED], 0); } static void visible_toggled_callback (GtkCellRendererToggle *cell, char *path_string, gpointer user_data) { NemoColumnChooser *chooser; GtkTreePath *path; GtkTreeIter iter; gboolean visible; chooser = NEMO_COLUMN_CHOOSER (user_data); path = gtk_tree_path_new_from_string (path_string); gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), &iter, COLUMN_VISIBLE, &visible, -1); gtk_list_store_set (chooser->details->store, &iter, COLUMN_VISIBLE, !visible, -1); gtk_tree_path_free (path); list_changed (chooser); } static void selection_changed_callback (GtkTreeSelection *selection, gpointer user_data) { update_buttons (NEMO_COLUMN_CHOOSER (user_data)); } static void row_deleted_callback (GtkTreeModel *model, GtkTreePath *path, gpointer user_data) { list_changed (NEMO_COLUMN_CHOOSER (user_data)); } static void add_tree_view (NemoColumnChooser *chooser) { GtkWidget *scrolled; GtkWidget *view; GtkListStore *store; GtkCellRenderer *cell; GtkTreeSelection *selection; view = gtk_tree_view_new (); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (store)); g_object_unref (store); gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); g_signal_connect (selection, "changed", G_CALLBACK (selection_changed_callback), chooser); cell = gtk_cell_renderer_toggle_new (); g_signal_connect (G_OBJECT (cell), "toggled", G_CALLBACK (visible_toggled_callback), chooser); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), -1, NULL, cell, "active", COLUMN_VISIBLE, "sensitive", COLUMN_TOGGLE_SENSITIVE, NULL); cell = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), -1, NULL, cell, "text", COLUMN_LABEL, NULL); chooser->details->view = GTK_TREE_VIEW (view); chooser->details->store = store; gtk_widget_show (view); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show (GTK_WIDGET (scrolled)); gtk_container_add (GTK_CONTAINER (scrolled), view); gtk_box_pack_start (GTK_BOX (chooser), scrolled, TRUE, TRUE, 0); } static void move_up_clicked_callback (GtkWidget *button, gpointer user_data) { NemoColumnChooser *chooser; GtkTreeIter iter; GtkTreeSelection *selection; chooser = NEMO_COLUMN_CHOOSER (user_data); selection = gtk_tree_view_get_selection (chooser->details->view); if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { GtkTreePath *path; GtkTreeIter prev; path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store), &iter); gtk_tree_path_prev (path); if (gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), &prev, path)) { gtk_list_store_move_before (chooser->details->store, &iter, &prev); } gtk_tree_path_free (path); } list_changed (chooser); } static void move_down_clicked_callback (GtkWidget *button, gpointer user_data) { NemoColumnChooser *chooser; GtkTreeIter iter; GtkTreeSelection *selection; chooser = NEMO_COLUMN_CHOOSER (user_data); selection = gtk_tree_view_get_selection (chooser->details->view); if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { GtkTreeIter next; next = iter; if (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &next)) { gtk_list_store_move_after (chooser->details->store, &iter, &next); } } list_changed (chooser); } static void use_default_clicked_callback (GtkWidget *button, gpointer user_data) { g_signal_emit (NEMO_COLUMN_CHOOSER (user_data), signals[USE_DEFAULT], 0); } static GtkWidget * button_new_with_mnemonic (const gchar *stockid, const gchar *str) { GtkWidget *image; GtkWidget *button; button = gtk_button_new_with_mnemonic (str); image = gtk_image_new_from_stock (stockid, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button), image); return button; } static void add_buttons (NemoColumnChooser *chooser) { GtkWidget *box; GtkWidget *separator; box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); gtk_widget_show (box); chooser->details->move_up_button = button_new_with_mnemonic (GTK_STOCK_GO_UP, _("Move _Up")); g_signal_connect (chooser->details->move_up_button, "clicked", G_CALLBACK (move_up_clicked_callback), chooser); gtk_widget_show_all (chooser->details->move_up_button); gtk_widget_set_sensitive (chooser->details->move_up_button, FALSE); gtk_box_pack_start (GTK_BOX (box), chooser->details->move_up_button, FALSE, FALSE, 0); chooser->details->move_down_button = button_new_with_mnemonic (GTK_STOCK_GO_DOWN, _("Move Dow_n")); g_signal_connect (chooser->details->move_down_button, "clicked", G_CALLBACK (move_down_clicked_callback), chooser); gtk_widget_show_all (chooser->details->move_down_button); gtk_widget_set_sensitive (chooser->details->move_down_button, FALSE); gtk_box_pack_start (GTK_BOX (box), chooser->details->move_down_button, FALSE, FALSE, 0); separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_widget_show (separator); gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0); chooser->details->use_default_button = gtk_button_new_with_mnemonic (_("Use De_fault")); g_signal_connect (chooser->details->use_default_button, "clicked", G_CALLBACK (use_default_clicked_callback), chooser); gtk_widget_show (chooser->details->use_default_button); gtk_box_pack_start (GTK_BOX (box), chooser->details->use_default_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (chooser), box, FALSE, FALSE, 0); } static void populate_tree (NemoColumnChooser *chooser) { GList *columns; GList *l; columns = nemo_get_columns_for_file (chooser->details->file); for (l = columns; l != NULL; l = l->next) { GtkTreeIter iter; NemoColumn *column; char *name; char *label; column = NEMO_COLUMN (l->data); g_object_get (G_OBJECT (column), "name", &name, "label", &label, NULL); gtk_list_store_append (chooser->details->store, &iter); gtk_list_store_set (chooser->details->store, &iter, COLUMN_VISIBLE, FALSE, COLUMN_LABEL, label, COLUMN_NAME, name, COLUMN_TOGGLE_SENSITIVE, g_strcmp0 (name, "name") != 0, -1); g_free (name); g_free (label); } nemo_column_list_free (columns); } static void nemo_column_chooser_constructed (GObject *object) { NemoColumnChooser *chooser; chooser = NEMO_COLUMN_CHOOSER (object); populate_tree (chooser); g_signal_connect (chooser->details->store, "row_deleted", G_CALLBACK (row_deleted_callback), chooser); } static void nemo_column_chooser_init (NemoColumnChooser *chooser) { chooser->details = G_TYPE_INSTANCE_GET_PRIVATE ((chooser), NEMO_TYPE_COLUMN_CHOOSER, NemoColumnChooserDetails); g_object_set (G_OBJECT (chooser), "homogeneous", FALSE, "spacing", 8, "orientation", GTK_ORIENTATION_HORIZONTAL, NULL); add_tree_view (chooser); add_buttons (chooser); } static void set_visible_columns (NemoColumnChooser *chooser, char **visible_columns) { GHashTable *visible_columns_hash; GtkTreeIter iter; int i; visible_columns_hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; visible_columns[i] != NULL; ++i) { g_hash_table_insert (visible_columns_hash, visible_columns[i], visible_columns[i]); } if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), &iter)) { do { char *name; gboolean visible; gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), &iter, COLUMN_NAME, &name, -1); visible = (g_hash_table_lookup (visible_columns_hash, name) != NULL); gtk_list_store_set (chooser->details->store, &iter, COLUMN_VISIBLE, visible, -1); g_free (name); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter)); } g_hash_table_destroy (visible_columns_hash); } static char ** get_column_names (NemoColumnChooser *chooser, gboolean only_visible) { GPtrArray *ret; GtkTreeIter iter; ret = g_ptr_array_new (); if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), &iter)) { do { char *name; gboolean visible; gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), &iter, COLUMN_VISIBLE, &visible, COLUMN_NAME, &name, -1); if (!only_visible || visible) { /* give ownership to the array */ g_ptr_array_add (ret, name); } } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter)); } g_ptr_array_add (ret, NULL); return (char **) g_ptr_array_free (ret, FALSE); } static gboolean get_column_iter (NemoColumnChooser *chooser, NemoColumn *column, GtkTreeIter *iter) { char *column_name; g_object_get (NEMO_COLUMN (column), "name", &column_name, NULL); if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), iter)) { do { char *name; gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), iter, COLUMN_NAME, &name, -1); if (!strcmp (name, column_name)) { g_free (column_name); g_free (name); return TRUE; } g_free (name); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), iter)); } g_free (column_name); return FALSE; } static void set_column_order (NemoColumnChooser *chooser, char **column_order) { GList *columns; GList *l; GtkTreePath *path; columns = nemo_get_columns_for_file (chooser->details->file); columns = nemo_sort_columns (columns, column_order); g_signal_handlers_block_by_func (chooser->details->store, G_CALLBACK (row_deleted_callback), chooser); path = gtk_tree_path_new_first (); for (l = columns; l != NULL; l = l->next) { GtkTreeIter iter; if (get_column_iter (chooser, NEMO_COLUMN (l->data), &iter)) { GtkTreeIter before; if (path) { gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), &before, path); gtk_list_store_move_after (chooser->details->store, &iter, &before); gtk_tree_path_next (path); } else { gtk_list_store_move_after (chooser->details->store, &iter, NULL); } } } gtk_tree_path_free (path); g_signal_handlers_unblock_by_func (chooser->details->store, G_CALLBACK (row_deleted_callback), chooser); nemo_column_list_free (columns); } void nemo_column_chooser_set_settings (NemoColumnChooser *chooser, char **visible_columns, char **column_order) { g_return_if_fail (NEMO_IS_COLUMN_CHOOSER (chooser)); g_return_if_fail (visible_columns != NULL); g_return_if_fail (column_order != NULL); set_visible_columns (chooser, visible_columns); set_column_order (chooser, column_order); list_changed (chooser); } void nemo_column_chooser_get_settings (NemoColumnChooser *chooser, char ***visible_columns, char ***column_order) { g_return_if_fail (NEMO_IS_COLUMN_CHOOSER (chooser)); g_return_if_fail (visible_columns != NULL); g_return_if_fail (column_order != NULL); *visible_columns = get_column_names (chooser, TRUE); *column_order = get_column_names (chooser, FALSE); } GtkWidget * nemo_column_chooser_new (NemoFile *file) { return g_object_new (NEMO_TYPE_COLUMN_CHOOSER, "file", file, NULL); } nemo-4.4.2/libnemo-private/nemo-column-chooser.h000066400000000000000000000051151357442400300216220ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-column-choose.h - A column chooser widget Copyright (C) 2004 Novell, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the column COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Dave Camp */ #ifndef NEMO_COLUMN_CHOOSER_H #define NEMO_COLUMN_CHOOSER_H #include #include #define NEMO_TYPE_COLUMN_CHOOSER nemo_column_chooser_get_type() #define NEMO_COLUMN_CHOOSER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_COLUMN_CHOOSER, NemoColumnChooser)) #define NEMO_COLUMN_CHOOSER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_COLUMN_CHOOSER, NemoColumnChooserClass)) #define NEMO_IS_COLUMN_CHOOSER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_COLUMN_CHOOSER)) #define NEMO_IS_COLUMN_CHOOSER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_COLUMN_CHOOSER)) #define NEMO_COLUMN_CHOOSER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_COLUMN_CHOOSER, NemoColumnChooserClass)) typedef struct _NemoColumnChooserDetails NemoColumnChooserDetails; typedef struct { GtkBox parent; NemoColumnChooserDetails *details; } NemoColumnChooser; typedef struct { GtkBoxClass parent_slot; void (*changed) (NemoColumnChooser *chooser); void (*use_default) (NemoColumnChooser *chooser); } NemoColumnChooserClass; GType nemo_column_chooser_get_type (void); GtkWidget *nemo_column_chooser_new (NemoFile *file); void nemo_column_chooser_set_settings (NemoColumnChooser *chooser, char **visible_columns, char **column_order); void nemo_column_chooser_get_settings (NemoColumnChooser *chooser, char ***visible_columns, char ***column_order); #endif /* NEMO_COLUMN_CHOOSER_H */ nemo-4.4.2/libnemo-private/nemo-column-utilities.c000066400000000000000000000227541357442400300221760ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-column-utilities.h - Utilities related to column specifications Copyright (C) 2004 Novell, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the column COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Dave Camp */ #include #include "nemo-column-utilities.h" #include #include #include #include #include static GList * get_builtin_columns (void) { GList *columns; columns = g_list_append (NULL, g_object_new (NEMO_TYPE_COLUMN, "name", "name", "attribute", "name", "label", _("Name"), "description", _("The name and icon of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "size", "attribute", "size", "label", _("Size"), "description", _("The size of the file."), "xalign", 1.0, NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "type", "attribute", "type", "label", _("Type"), "description", _("The general type of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "detailed_type", "attribute", "detailed_type", "label", _("Detailed Type"), "description", _("The specific type of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "date_modified", "attribute", "date_modified", "label", _("Date Modified"), "description", _("The date the file was modified."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "date_modified_with_time", "attribute", "date_modified_with_time", "label", _("Modified - Time"), "description", _("The date the file was modified."), "xalign", 1.0, NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "date_created", "attribute", "date_created", "label", _("Date Created"), "description", _("The date the file was created."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "date_created_with_time", "attribute", "date_created_with_time", "label", _("Created - Time"), "description", _("The date the file was created."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "date_accessed", "attribute", "date_accessed", "label", _("Date Accessed"), "description", _("The date the file was accessed."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "owner", "attribute", "owner", "label", _("Owner"), "description", _("The owner of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "group", "attribute", "group", "label", _("Group"), "description", _("The group of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "permissions", "attribute", "permissions", "label", _("Permissions"), "description", _("The permissions of the file."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "octal_permissions", "attribute", "octal_permissions", "label", _("Octal Permissions"), "description", _("The permissions of the file, in octal notation."), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "mime_type", "attribute", "mime_type", "label", _("MIME Type"), "description", _("The mime type of the file."), NULL)); #ifdef HAVE_SELINUX columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "selinux_context", "attribute", "selinux_context", "label", _("SELinux Context"), "description", _("The SELinux security context of the file."), NULL)); #endif columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "where", "attribute", "where", "label", _("Location"), "description", _("The location of the file."), NULL)); return columns; } static GList * get_extension_columns (void) { GList *columns; GList *providers; GList *l; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_COLUMN_PROVIDER); columns = NULL; for (l = providers; l != NULL; l = l->next) { NemoColumnProvider *provider; GList *provider_columns; provider = NEMO_COLUMN_PROVIDER (l->data); provider_columns = nemo_column_provider_get_columns (provider); columns = g_list_concat (columns, provider_columns); } nemo_module_extension_list_free (providers); return columns; } static GList * get_trash_columns (void) { static GList *columns = NULL; if (columns == NULL) { columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "trashed_on", "attribute", "trashed_on", "label", _("Trashed On"), "description", _("Date when file was moved to the Trash"), NULL)); columns = g_list_append (columns, g_object_new (NEMO_TYPE_COLUMN, "name", "trash_orig_path", "attribute", "trash_orig_path", "label", _("Original Location"), "description", _("Original location of file before moved to the Trash"), NULL)); } return nemo_column_list_copy (columns); } GList * nemo_get_common_columns (void) { static GList *columns = NULL; if (!columns) { columns = g_list_concat (get_builtin_columns (), get_extension_columns ()); } return nemo_column_list_copy (columns); } GList * nemo_get_all_columns (void) { GList *columns = NULL; columns = g_list_concat (nemo_get_common_columns (), get_trash_columns ()); return columns; } GList * nemo_get_columns_for_file (NemoFile *file) { GList *columns; columns = nemo_get_common_columns (); if (file != NULL && nemo_file_is_in_trash (file)) { columns = g_list_concat (columns, get_trash_columns ()); } return columns; } GList * nemo_column_list_copy (GList *columns) { GList *ret; GList *l; ret = g_list_copy (columns); for (l = ret; l != NULL; l = l->next) { g_object_ref (l->data); } return ret; } void nemo_column_list_free (GList *columns) { GList *l; for (l = columns; l != NULL; l = l->next) { g_object_unref (l->data); } g_list_free (columns); } static int strv_index (char **strv, const char *str) { int i; for (i = 0; strv[i] != NULL; ++i) { if (strcmp (strv[i], str) == 0) return i; } return -1; } static int column_compare (NemoColumn *a, NemoColumn *b, char **column_order) { int index_a; int index_b; char *name; g_object_get (G_OBJECT (a), "name", &name, NULL); index_a = strv_index (column_order, name); g_free (name); g_object_get (G_OBJECT (b), "name", &name, NULL); index_b = strv_index (column_order, name); g_free (name); if (index_a == index_b) { int ret; char *label_a; char *label_b; g_object_get (G_OBJECT (a), "label", &label_a, NULL); g_object_get (G_OBJECT (b), "label", &label_b, NULL); ret = strcmp (label_a, label_b); g_free (label_a); g_free (label_b); return ret; } else if (index_a == -1) { return 1; } else if (index_b == -1) { return -1; } else { return index_a - index_b; } } GList * nemo_sort_columns (GList *columns, char **column_order) { if (!column_order) { return NULL; } return g_list_sort_with_data (columns, (GCompareDataFunc)column_compare, column_order); } nemo-4.4.2/libnemo-private/nemo-column-utilities.h000066400000000000000000000030161357442400300221710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-column-utilities.h - Utilities related to column specifications Copyright (C) 2004 Novell, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the column COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Dave Camp */ #ifndef NEMO_COLUMN_UTILITIES_H #define NEMO_COLUMN_UTILITIES_H #include #include GList *nemo_get_all_columns (void); GList *nemo_get_common_columns (void); GList *nemo_get_columns_for_file (NemoFile *file); GList *nemo_column_list_copy (GList *columns); void nemo_column_list_free (GList *columns); GList *nemo_sort_columns (GList *columns, char **column_order); #endif /* NEMO_COLUMN_UTILITIES_H */ nemo-4.4.2/libnemo-private/nemo-dbus-manager.c000066400000000000000000000133561357442400300212330ustar00rootroot00000000000000/* * nemo-dbus-manager: nemo DBus interface * * Copyright (C) 2010, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #include #include "nemo-dbus-manager.h" #include "nemo-generated.h" #include "nemo-file-operations.h" #define DEBUG_FLAG NEMO_DEBUG_DBUS #include "nemo-debug.h" #include struct _NemoDBusManager { GObject parent; GDBusObjectManagerServer *object_manager; NemoDBusFileOperations *file_operations; }; struct _NemoDBusManagerClass { GObjectClass parent_class; }; G_DEFINE_TYPE (NemoDBusManager, nemo_dbus_manager, G_TYPE_OBJECT); static void nemo_dbus_manager_dispose (GObject *object) { NemoDBusManager *self = (NemoDBusManager *) object; if (self->file_operations) { g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->file_operations)); g_object_unref (self->file_operations); self->file_operations = NULL; } if (self->object_manager) { g_object_unref (self->object_manager); self->object_manager = NULL; } G_OBJECT_CLASS (nemo_dbus_manager_parent_class)->dispose (object); } static gboolean handle_copy_file (NemoDBusFileOperations *object, GDBusMethodInvocation *invocation, const gchar *source_uri, const gchar *source_display_name, const gchar *dest_dir_uri, const gchar *dest_name) { GFile *source_file, *target_dir; const gchar *target_name = NULL, *source_name = NULL; source_file = g_file_new_for_uri (source_uri); target_dir = g_file_new_for_uri (dest_dir_uri); if (dest_name != NULL && dest_name[0] != '\0') target_name = dest_name; if (source_display_name != NULL && source_display_name[0] != '\0') source_name = source_display_name; nemo_file_operations_copy_file (source_file, target_dir, source_name, target_name, NULL, NULL, NULL); g_object_unref (source_file); g_object_unref (target_dir); nemo_dbus_file_operations_complete_copy_file (object, invocation); return TRUE; /* invocation was handled */ } static gboolean handle_copy_uris (NemoDBusFileOperations *object, GDBusMethodInvocation *invocation, const gchar **sources, const gchar *destination) { GList *source_files = NULL; GFile *dest_dir; gint idx; dest_dir = g_file_new_for_uri (destination); for (idx = 0; sources[idx] != NULL; idx++) source_files = g_list_prepend (source_files, g_file_new_for_uri (sources[idx])); nemo_file_operations_copy (source_files, NULL, dest_dir, NULL, NULL, NULL); g_list_free_full (source_files, g_object_unref); g_object_unref (dest_dir); nemo_dbus_file_operations_complete_copy_uris (object, invocation); return TRUE; /* invocation was handled */ } static gboolean handle_move_uris (NemoDBusFileOperations *object, GDBusMethodInvocation *invocation, const gchar **sources, const gchar *destination) { GList *source_files = NULL; GFile *dest_dir; gint idx; dest_dir = g_file_new_for_uri (destination); for (idx = 0; sources[idx] != NULL; idx++) source_files = g_list_prepend (source_files, g_file_new_for_uri (sources[idx])); nemo_file_operations_move (source_files, NULL, dest_dir, NULL, NULL, NULL); g_list_free_full (source_files, g_object_unref); g_object_unref (dest_dir); nemo_dbus_file_operations_complete_move_uris (object, invocation); return TRUE; /* invocation was handled */ } static gboolean handle_empty_trash (NemoDBusFileOperations *object, GDBusMethodInvocation *invocation) { nemo_file_operations_empty_trash (NULL); nemo_dbus_file_operations_complete_empty_trash (object, invocation); return TRUE; /* invocation was handled */ } static void nemo_dbus_manager_init (NemoDBusManager *self) { GDBusConnection *connection; connection = g_application_get_dbus_connection (g_application_get_default ()); self->object_manager = g_dbus_object_manager_server_new ("/org/Nemo"); self->file_operations = nemo_dbus_file_operations_skeleton_new (); g_signal_connect (self->file_operations, "handle-copy-uris", G_CALLBACK (handle_copy_uris), self); g_signal_connect (self->file_operations, "handle-copy-file", G_CALLBACK (handle_copy_file), self); g_signal_connect (self->file_operations, "handle-move-uris", G_CALLBACK (handle_move_uris), self); g_signal_connect (self->file_operations, "handle-empty-trash", G_CALLBACK (handle_empty_trash), self); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->file_operations), connection, "/org/Nemo", NULL); g_dbus_object_manager_server_set_connection (self->object_manager, connection); } static void nemo_dbus_manager_class_init (NemoDBusManagerClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->dispose = nemo_dbus_manager_dispose; } NemoDBusManager * nemo_dbus_manager_new (void) { return g_object_new (nemo_dbus_manager_get_type (), NULL); } nemo-4.4.2/libnemo-private/nemo-dbus-manager.h000066400000000000000000000022411357442400300212270ustar00rootroot00000000000000/* * nemo-dbus-manager: nemo DBus interface * * Copyright (C) 2010, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #ifndef __NEMO_DBUS_MANAGER_H__ #define __NEMO_DBUS_MANAGER_H__ #include #include typedef struct _NemoDBusManager NemoDBusManager; typedef struct _NemoDBusManagerClass NemoDBusManagerClass; GType nemo_dbus_manager_get_type (void); NemoDBusManager * nemo_dbus_manager_new (void); #endif /* __NEMO_DBUS_MANAGER_H__ */ nemo-4.4.2/libnemo-private/nemo-debug.c000066400000000000000000000076751357442400300177630ustar00rootroot00000000000000/* * nemo-debug: debug loggers for nemo * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * Copyright (C) 2010 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.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Based on Empathy's empathy-debug. */ #include #include #include "nemo-debug.h" #include "nemo-file.h" #ifdef ENABLE_DEBUG static DebugFlags flags = 0; static gboolean initialized = FALSE; static GDebugKey keys[] = { { "Application", NEMO_DEBUG_APPLICATION }, { "Bookmarks", NEMO_DEBUG_BOOKMARKS }, { "DBus", NEMO_DEBUG_DBUS }, { "DirectoryView", NEMO_DEBUG_DIRECTORY_VIEW }, { "File", NEMO_DEBUG_FILE }, { "IconContainer", NEMO_DEBUG_ICON_CONTAINER }, { "IconView", NEMO_DEBUG_ICON_VIEW }, { "ListView", NEMO_DEBUG_LIST_VIEW }, { "Mime", NEMO_DEBUG_MIME }, { "Places", NEMO_DEBUG_PLACES }, { "Previewer", NEMO_DEBUG_PREVIEWER }, { "Smclient", NEMO_DEBUG_SMCLIENT }, { "Window", NEMO_DEBUG_WINDOW }, { "Undo", NEMO_DEBUG_UNDO }, { "Actions", NEMO_DEBUG_ACTIONS }, { "Desktop", NEMO_DEBUG_DESKTOP }, { "Thumbnails", NEMO_DEBUG_THUMBNAILS }, { 0, } }; static void nemo_debug_set_flags_from_env (void) { guint nkeys; const gchar *flags_string; for (nkeys = 0; keys[nkeys].value; nkeys++); flags_string = g_getenv ("NEMO_DEBUG"); if (flags_string) nemo_debug_set_flags (g_parse_debug_string (flags_string, keys, nkeys)); initialized = TRUE; } void nemo_debug_set_flags (DebugFlags new_flags) { flags |= new_flags; initialized = TRUE; } gboolean nemo_debug_flag_is_set (DebugFlags flag) { return flag & flags; } void nemo_debug (DebugFlags flag, const gchar *format, ...) { va_list args; va_start (args, format); nemo_debug_valist (flag, format, args); va_end (args); } void nemo_debug_valist (DebugFlags flag, const gchar *format, va_list args) { if (G_UNLIKELY(!initialized)) nemo_debug_set_flags_from_env (); if (flag & flags) g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args); } static void nemo_debug_files_valist (DebugFlags flag, GList *files, const gchar *format, va_list args) { NemoFile *file; GList *l; gchar *uri, *msg; if (G_UNLIKELY (!initialized)) nemo_debug_set_flags_from_env (); if (!(flag & flags)) return; msg = g_strdup_vprintf (format, args); g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s:", msg); for (l = files; l != NULL; l = l->next) { file = l->data; uri = nemo_file_get_uri (file); if (nemo_file_is_gone (file)) { gchar *new_uri; /* Hack: this will create an invalid URI, but it's for * display purposes only. */ new_uri = g_strconcat (uri ? uri : "", " (gone)", NULL); g_free (uri); uri = new_uri; } g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, " %s", uri); g_free (uri); } g_free (msg); } void nemo_debug_files (DebugFlags flag, GList *files, const gchar *format, ...) { va_list args; va_start (args, format); nemo_debug_files_valist (flag, files, format, args); va_end (args); } #endif /* ENABLE_DEBUG */ nemo-4.4.2/libnemo-private/nemo-debug.h000066400000000000000000000052621357442400300177560ustar00rootroot00000000000000/* * nemo-debug: debug loggers for nemo * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * Copyright (C) 2010 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.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Based on Empathy's empathy-debug. */ #ifndef __NEMO_DEBUG_H__ #define __NEMO_DEBUG_H__ #include #include G_BEGIN_DECLS #ifdef ENABLE_DEBUG typedef enum { NEMO_DEBUG_APPLICATION = 1 << 1, NEMO_DEBUG_BOOKMARKS = 1 << 2, NEMO_DEBUG_DBUS = 1 << 3, NEMO_DEBUG_DIRECTORY_VIEW = 1 << 4, NEMO_DEBUG_FILE = 1 << 5, NEMO_DEBUG_ICON_CONTAINER = 1 << 6, NEMO_DEBUG_ICON_VIEW = 1 << 7, NEMO_DEBUG_LIST_VIEW = 1 << 8, NEMO_DEBUG_MIME = 1 << 9, NEMO_DEBUG_PLACES = 1 << 10, NEMO_DEBUG_PREVIEWER = 1 << 11, NEMO_DEBUG_SMCLIENT = 1 << 12, NEMO_DEBUG_WINDOW = 1 << 13, NEMO_DEBUG_UNDO = 1 << 14, NEMO_DEBUG_ACTIONS = 1 << 15, NEMO_DEBUG_DESKTOP = 1 << 16, NEMO_DEBUG_THUMBNAILS = 1 << 17 } DebugFlags; void nemo_debug_set_flags (DebugFlags flags); gboolean nemo_debug_flag_is_set (DebugFlags flag); void nemo_debug_valist (DebugFlags flag, const gchar *format, va_list args); void nemo_debug (DebugFlags flag, const gchar *format, ...) G_GNUC_PRINTF (2, 3); void nemo_debug_files (DebugFlags flag, GList *files, const gchar *format, ...) G_GNUC_PRINTF (3, 4); #ifdef DEBUG_FLAG #define DEBUG(format, ...) \ nemo_debug (DEBUG_FLAG, "%s: %s: " format, G_STRFUNC, G_STRLOC, \ ##__VA_ARGS__) #define DEBUG_FILES(files, format, ...) \ nemo_debug_files (DEBUG_FLAG, files, "%s:" format, G_STRFUNC, \ ##__VA_ARGS__) #define DEBUGGING nemo_debug_flag_is_set(DEBUG_FLAG) #endif /* DEBUG_FLAG */ #else /* ENABLE_DEBUG */ #ifdef DEBUG_FLAG #define DEBUG(format, ...) \ G_STMT_START { } G_STMT_END #define DEBUG_FILES(files, format, ...) \ G_STMT_START { } G_STMT_END #define DEBUGGING 0 #endif /* DEBUG_FLAG */ #endif /* ENABLE_DEBUG */ G_END_DECLS #endif /* __NEMO_DEBUG_H__ */ nemo-4.4.2/libnemo-private/nemo-default-file-icon.c000066400000000000000000001127641357442400300221600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Default file icon used by the icon factory. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-default-file-icon.h" const int nemo_default_file_icon_width = 48; const int nemo_default_file_icon_height = 48; const unsigned char nemo_default_file_icon[] = /* This is from text-x-preview.svg in the gnome icon theme */ "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\243\255\243\31\252\254\245\307\246\251\243\374\246\251\243\377\246" "\251\243\377\246\251\242\377\246\250\242\377\246\250\242\377\246\250" "\242\377\245\250\242\377\245\250\242\377\245\250\242\377\245\250\241" "\377\245\247\241\377\245\247\241\377\245\247\241\377\244\247\241\377" "\244\247\241\377\244\247\241\377\244\247\240\377\244\246\240\377\244" "\246\240\377\244\246\240\377\243\246\240\377\243\246\240\377\243\246" "\237\377\244\247\240\371\245\251\242\333\245\247\242\216\246\246\233" "\27\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\252\254\246\277\347\351" "\346\376\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\374\374\374\377\362\363\361\377\353\355\352\377" "\344\345\342\377\276\300\272\371\244\245\240\366\244\247\237h\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\246\251\244\373\376\376\376\377\354\355\352\377" "\352\354\350\377\351\353\347\377\351\353\347\377\350\352\346\377\350" "\351\345\377\347\351\344\377\346\350\344\377\345\350\343\377\344\347" "\342\377\344\346\341\377\343\346\340\377\342\345\340\377\341\344\337" "\377\341\343\336\377\340\342\335\377\337\342\334\377\337\341\333\377" "\336\340\332\377\335\337\332\377\334\337\331\377\333\336\330\377\332" "\335\327\377\331\334\326\377\331\334\325\377\333\334\327\377\362\363" "\361\377\333\335\331\377\250\253\245\364\245\246\240\236\200\200\200" "\2\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\245\247\241\377\377\377\377\377\352\354\350\377\351\353\347\377\351" "\353\347\377\350\352\346\377\350\352\346\377\347\351\345\377\347\350" "\344\377\346\351\344\377\345\350\343\377\344\347\342\377\344\346\342" "\377\343\346\341\377\342\345\340\377\341\344\337\377\341\344\336\377" "\340\343\335\377\340\342\335\377\337\341\334\377\336\341\333\377\335" "\340\332\377\334\337\331\377\334\336\330\377\333\336\327\377\332\335" "\326\377\331\334\325\377\326\331\322\377\326\330\324\377\372\372\371" "\377\333\336\331\377\253\257\251\364\241\246\240\251\377\377\377\1\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\244\247\240\377" "\377\377\377\377\351\353\347\377\351\353\347\377\350\353\347\377\350" "\352\346\377\347\352\345\377\347\351\345\377\347\350\344\377\346\350" "\343\377\345\347\343\377\344\347\343\377\344\346\342\377\343\346\341" "\377\342\345\340\377\342\344\337\377\341\344\336\377\341\343\336\377" "\340\342\335\377\337\342\334\377\337\341\333\377\336\340\332\377\335" "\340\332\377\334\337\331\377\333\336\330\377\333\335\327\377\332\335" "\326\377\330\333\324\377\312\314\307\377\374\375\374\377\363\364\362" "\377\325\330\322\377\253\255\250\365\242\244\235\222\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\243\246\240\377\377\377\377\377" "\351\352\346\377\350\352\346\377\350\352\346\377\347\352\346\377\347" "\351\345\377\347\351\344\377\346\350\344\377\346\350\343\377\345\347" "\342\377\344\346\342\377\344\346\342\377\343\346\341\377\342\345\340" "\377\342\345\337\377\342\344\337\377\341\343\336\377\340\343\335\377" "\340\342\334\377\337\341\333\377\336\341\333\377\335\340\332\377\335" "\337\331\377\334\337\330\377\333\336\327\377\332\335\326\377\332\335" "\326\377\314\317\310\377\372\372\372\377\370\370\370\377\346\351\345" "\377\324\330\321\377\245\247\241\364\241\244\235Q\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\243\245\237\377\377\377\377\377\350\352\346\377" "\350\351\345\377\347\351\345\377\347\351\345\377\347\351\344\377\346" "\350\344\377\346\350\343\377\345\347\343\377\345\347\342\377\344\346" "\342\377\344\346\341\377\343\345\341\377\342\345\340\377\342\345\337" "\377\341\344\337\377\340\344\336\377\341\343\335\377\340\342\334\377" "\337\342\334\377\336\341\333\377\336\340\332\377\335\340\331\377\334" "\337\331\377\334\336\330\377\333\336\327\377\332\335\326\377\320\323" "\314\377\305\307\301\377\271\274\266\377\262\265\257\377\300\303\276" "\377\314\317\311\377\240\244\234\355\222\222\222\7\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\242\245\237\377\377\377\377\377\347\351\345\377\347\351\344" "\377\347\350\345\377\346\350\344\377\346\350\344\377\346\350\343\377" "\346\350\343\377\345\347\342\377\345\347\342\377\344\346\342\377\344" "\346\341\377\343\345\341\377\342\345\340\377\342\345\337\377\341\344" "\337\377\341\344\336\377\341\343\335\377\340\343\334\377\337\342\334" "\377\337\341\333\377\336\341\332\377\335\340\332\377\335\340\331\377" "\334\337\330\377\333\336\327\377\333\336\327\377\322\325\317\377\307" "\312\304\377\274\300\271\377\261\264\257\377\246\250\244\377\302\304" "\300\377\260\263\255\363\237\242\235h\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\241" "\244\236\377\377\377\377\377\347\351\344\377\346\350\344\377\346\350" "\344\377\346\350\344\377\345\350\343\377\346\350\343\377\345\347\342" "\377\345\347\343\377\344\347\342\377\344\346\342\377\343\346\341\377" "\343\345\341\377\342\345\340\377\342\344\337\377\342\344\337\377\341" "\343\336\377\341\343\335\377\340\343\335\377\340\342\334\377\337\342" "\333\377\336\341\333\377\336\341\332\377\335\340\331\377\335\340\331" "\377\334\337\330\377\334\337\330\377\334\337\330\377\333\335\327\377" "\331\333\325\377\322\324\317\377\306\310\303\377\273\276\271\377\322" "\325\320\377\242\244\236\312\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\241\243\235" "\377\377\377\377\377\346\350\343\377\346\350\344\377\346\350\343\377" "\345\347\343\377\345\347\343\377\345\347\342\377\345\347\342\377\345" "\347\342\377\344\347\342\377\344\346\341\377\343\346\341\377\343\345" "\340\377\342\345\340\377\342\344\337\377\341\344\337\377\341\343\336" "\377\341\343\335\377\340\342\335\377\340\342\334\377\337\341\334\377" "\337\341\334\377\336\341\333\377\336\340\333\377\335\340\332\377\335" "\337\331\377\335\337\331\377\335\337\331\377\334\337\331\377\334\337" "\331\377\334\337\331\377\334\337\331\377\336\341\333\377\350\352\347" "\377\236\240\232\370\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\240\242\234\377\377" "\377\377\377\346\347\343\377\345\350\343\377\345\347\343\377\345\347" "\343\377\345\347\342\377\344\347\342\377\345\346\342\377\344\347\342" "\377\344\346\342\377\344\346\341\377\343\346\341\377\343\345\340\377" "\342\345\340\377\342\344\337\377\341\344\337\377\342\343\337\377\341" "\343\336\377\341\342\336\377\340\342\335\377\340\341\335\377\337\341" "\334\377\336\340\333\377\336\340\333\377\336\340\333\377\336\340\333" "\377\336\340\333\377\336\340\333\377\336\340\333\377\335\340\332\377" "\335\340\332\377\335\340\332\377\337\342\334\377\363\364\362\377\233" "\235\230\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\237\242\234\377\377\377" "\377\377\345\347\342\377\345\347\342\377\345\347\343\377\345\347\342" "\377\344\347\342\377\344\346\342\377\345\346\342\377\344\346\342\377" "\344\346\341\377\344\346\341\377\343\346\341\377\343\345\340\377\342" "\345\340\377\342\344\337\377\341\344\337\377\342\344\337\377\341\343" "\336\377\341\343\336\377\340\342\335\377\340\342\335\377\337\341\334" "\377\337\341\334\377\337\341\334\377\337\341\334\377\337\341\334\377" "\337\341\334\377\337\341\334\377\337\341\334\377\337\341\334\377\336" "\341\333\377\336\341\333\377\340\343\335\377\373\373\372\377\232\235" "\227\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\237\241\233\377\377\377\377\377" "\344\347\342\377\345\346\342\377\345\347\342\377\344\347\342\377\344" "\347\342\377\344\346\341\377\344\346\342\377\344\346\342\377\344\345" "\341\377\343\346\341\377\343\346\341\377\343\345\340\377\342\345\340" "\377\342\345\337\377\341\344\340\377\341\344\337\377\341\343\337\377" "\341\343\336\377\340\342\336\377\340\342\335\377\340\342\335\377\340" "\342\335\377\340\342\335\377\340\342\335\377\340\342\335\377\340\342" "\335\377\340\342\335\377\337\342\335\377\337\342\335\377\337\342\334" "\377\337\342\334\377\341\344\336\377\375\375\375\377\232\234\226\377" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\236\240\233\377\377\377\377\377\344\346" "\341\377\345\346\342\377\344\346\342\377\344\347\342\377\344\346\341" "\377\344\346\341\377\343\346\342\377\344\346\341\377\344\346\341\377" "\343\345\341\377\343\345\340\377\343\345\340\377\342\345\340\377\342" "\345\337\377\341\344\340\377\341\344\337\377\342\344\337\377\341\343" "\336\377\341\343\336\377\341\343\336\377\341\343\336\377\341\343\336" "\377\341\343\336\377\341\343\336\377\341\343\336\377\341\343\336\377" "\341\343\336\377\341\343\336\377\340\343\336\377\340\343\336\377\340" "\343\335\377\342\345\337\377\375\375\375\377\231\233\226\377\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\235\240\232\377\377\377\377\377\344\346\341\377" "\343\346\341\377\344\346\342\377\344\346\341\377\344\346\341\377\344" "\346\341\377\343\346\341\377\344\346\341\377\344\345\341\377\343\345" "\341\377\343\345\340\377\343\345\340\377\342\345\341\377\342\345\340" "\377\342\345\340\377\342\344\337\377\342\344\337\377\342\344\337\377" "\342\344\337\377\342\344\337\377\342\344\337\377\342\344\337\377\342" "\344\337\377\342\344\337\377\342\344\337\377\342\344\337\377\342\344" "\337\377\342\344\337\377\341\344\337\377\341\344\337\377\341\344\337" "\377\341\343\336\377\375\375\375\377\230\233\225\377\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\235\237\231\377\377\377\377\377\343\345\341\377\343\346\341" "\377\344\346\341\377\344\346\341\377\344\346\341\377\343\345\341\377" "\343\346\341\377\344\346\341\377\344\346\341\377\343\345\341\377\343" "\345\340\377\343\345\340\377\343\345\341\377\342\345\340\377\342\345" "\340\377\342\345\340\377\342\345\340\377\343\345\340\377\343\345\340" "\377\343\345\340\377\343\345\340\377\343\345\340\377\343\345\340\377" "\343\345\340\377\343\345\340\377\343\345\340\377\343\345\340\377\342" "\345\340\377\342\345\340\377\342\345\340\377\342\344\340\377\342\344" "\337\377\377\377\377\377\230\232\224\377\377\377\377\0\377\377\377\0" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\234\236\231\377\377\377\377\377\343\345\341\377\343\345\340\377\343" "\346\341\377\344\346\341\377\344\345\341\377\343\345\341\377\343\345" "\341\377\343\346\341\377\344\346\341\377\344\346\341\377\343\345\340" "\377\343\345\340\377\343\345\341\377\343\345\341\377\343\346\341\377" "\343\346\341\377\344\346\341\377\344\346\341\377\344\346\341\377\344" "\346\341\377\344\346\341\377\344\346\341\377\344\346\341\377\344\346" "\341\377\344\346\341\377\344\346\341\377\344\346\341\377\343\346\341" "\377\343\346\341\377\343\345\341\377\343\345\341\377\343\345\341\377" "\377\377\377\377\227\231\224\377\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\233\236" "\230\377\377\377\377\377\343\345\340\377\343\345\340\377\343\346\341" "\377\343\346\341\377\344\346\341\377\344\346\341\377\343\345\341\377" "\343\345\341\377\344\346\341\377\344\346\341\377\344\346\341\377\344" "\346\342\377\344\346\342\377\344\346\342\377\344\346\342\377\344\346" "\342\377\345\346\342\377\345\346\342\377\345\347\342\377\345\347\342" "\377\345\347\342\377\345\347\342\377\345\347\342\377\345\347\342\377" "\345\347\342\377\345\347\342\377\345\346\342\377\345\346\342\377\344" "\346\342\377\344\346\342\377\344\346\342\377\344\346\342\377\377\377" "\377\377\226\231\223\377\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\233\235\227\377" "\377\377\377\377\343\345\340\377\343\345\340\377\343\345\341\377\343" "\346\341\377\344\346\341\377\344\346\341\377\344\346\342\377\344\346" "\342\377\345\346\342\377\345\347\342\377\345\347\342\377\345\347\343" "\377\345\347\343\377\345\347\343\377\345\347\343\377\346\347\343\377" "\346\347\343\377\346\347\343\377\346\347\343\377\346\347\343\377\346" "\350\343\377\346\350\343\377\346\350\343\377\346\350\343\377\346\347" "\343\377\346\347\343\377\346\347\343\377\346\347\343\377\345\347\343" "\377\345\347\343\377\345\347\343\377\345\347\343\377\377\377\377\377" "\226\230\222\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\232\234\227\377\377\377" "\377\377\343\346\341\377\344\346\341\377\344\346\342\377\344\346\342" "\377\345\346\342\377\345\347\342\377\345\347\343\377\345\347\343\377" "\345\347\343\377\346\347\343\377\346\350\343\377\346\350\344\377\346" "\350\344\377\346\350\344\377\346\350\344\377\346\350\344\377\347\350" "\344\377\347\350\344\377\347\350\344\377\347\350\344\377\347\350\344" "\377\347\350\344\377\347\350\344\377\347\350\344\377\347\350\344\377" "\347\350\344\377\347\350\344\377\346\350\344\377\346\350\344\377\346" "\350\344\377\346\350\344\377\346\350\344\377\377\377\377\377\225\227" "\222\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\231\234\226\377\377\377\377\377" "\344\346\342\377\345\346\342\377\345\347\342\377\345\347\343\377\345" "\347\343\377\346\347\343\377\346\350\344\377\346\350\344\377\346\350" "\344\377\346\350\344\377\347\350\344\377\347\351\345\377\347\351\345" "\377\347\351\345\377\347\351\345\377\347\351\345\377\350\351\345\377" "\350\351\345\377\350\351\346\377\350\351\346\377\350\351\346\377\350" "\351\346\377\350\351\346\377\350\351\346\377\350\351\346\377\350\351" "\346\377\350\351\345\377\347\351\345\377\347\351\345\377\347\351\345" "\377\347\351\345\377\347\351\345\377\377\377\377\377\224\227\221\377" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\231\233\225\377\377\377\377\377\345\347" "\343\377\345\347\343\377\346\347\343\377\346\350\344\377\346\350\344" "\377\346\350\344\377\347\350\344\377\347\351\345\377\347\351\345\377" "\347\351\345\377\350\351\346\377\350\351\346\377\350\352\346\377\350" "\352\346\377\350\352\346\377\350\352\346\377\351\352\346\377\351\352" "\347\377\351\352\347\377\351\352\347\377\351\352\347\377\351\352\347" "\377\351\352\347\377\351\352\347\377\351\352\347\377\351\352\347\377" "\351\352\346\377\351\352\346\377\350\352\346\377\350\352\346\377\350" "\352\346\377\350\352\346\377\377\377\377\377\224\226\220\377\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\230\232\225\377\377\377\377\377\346\350\344\377" "\346\350\344\377\346\350\344\377\347\350\344\377\347\351\345\377\347" "\351\345\377\350\351\346\377\350\351\346\377\350\352\346\377\350\352" "\346\377\351\352\346\377\351\352\347\377\351\352\347\377\351\352\347" "\377\351\353\347\377\351\353\347\377\351\353\347\377\352\353\350\377" "\352\353\350\377\352\353\350\377\352\353\350\377\352\353\350\377\352" "\353\350\377\352\353\350\377\352\353\350\377\352\353\350\377\352\353" "\350\377\351\353\347\377\351\353\347\377\351\353\347\377\351\352\347" "\377\351\352\347\377\377\377\377\377\223\225\220\377\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\227\232\224\377\377\377\377\377\347\350\344\377\347\351\345" "\377\347\351\345\377\350\351\345\377\350\351\346\377\350\352\346\377" "\351\352\346\377\351\352\347\377\351\352\347\377\351\353\347\377\351" "\353\347\377\352\353\350\377\352\353\350\377\352\353\350\377\352\353" "\350\377\352\354\350\377\352\354\350\377\353\354\351\377\353\354\351" "\377\353\354\351\377\353\354\351\377\353\354\351\377\353\354\351\377" "\353\354\351\377\353\354\351\377\353\354\351\377\353\354\351\377\352" "\354\350\377\352\354\350\377\352\353\350\377\352\353\350\377\352\353" "\350\377\377\377\377\377\222\224\217\377\377\377\377\0\377\377\377\0" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\227\231\223\377\377\377\377\377\347\351\345\377\350\351\346\377\350" "\352\346\377\350\352\346\377\351\352\347\377\351\352\347\377\351\353" "\347\377\352\353\350\377\352\353\350\377\352\353\350\377\352\354\350" "\377\353\354\351\377\353\354\351\377\353\354\351\377\353\354\351\377" "\353\354\351\377\353\355\352\377\354\355\352\377\354\355\352\377\354" "\355\352\377\354\355\352\377\354\355\352\377\354\355\352\377\354\355" "\352\377\354\355\352\377\354\355\352\377\354\355\352\377\353\355\352" "\377\353\354\351\377\353\354\351\377\353\354\351\377\353\354\351\377" "\377\377\377\377\222\224\216\377\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\226\230" "\223\377\377\377\377\377\350\352\346\377\350\352\346\377\351\352\347" "\377\351\352\347\377\351\353\347\377\352\353\350\377\352\353\350\377" "\352\354\350\377\353\354\351\377\353\354\351\377\353\354\351\377\354" "\355\352\377\354\355\352\377\354\355\352\377\354\355\352\377\354\355" "\352\377\354\356\353\377\354\356\353\377\355\356\353\377\355\356\353" "\377\355\356\353\377\355\356\353\377\355\356\353\377\355\356\353\377" "\355\356\353\377\355\356\353\377\354\356\353\377\354\355\353\377\354" "\355\352\377\354\355\352\377\354\355\352\377\354\355\352\377\377\377" "\377\377\221\223\216\377\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\225\230\222\377" "\377\377\377\377\351\352\347\377\351\352\347\377\351\353\347\377\352" "\353\350\377\352\353\350\377\352\354\350\377\353\354\351\377\353\354" "\351\377\354\355\352\377\354\355\352\377\354\355\352\377\354\355\353" "\377\355\356\353\377\355\356\353\377\355\356\353\377\355\356\353\377" "\355\356\354\377\356\356\354\377\356\356\354\377\356\357\354\377\356" "\357\354\377\356\357\354\377\356\357\354\377\356\357\354\377\356\357" "\354\377\356\356\354\377\355\356\354\377\355\356\354\377\355\356\353" "\377\355\356\353\377\355\356\353\377\354\356\353\377\377\377\377\377" "\220\222\215\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\225\227\221\377\377\377" "\377\377\351\353\347\377\352\353\350\377\352\353\350\377\352\354\350" "\377\353\354\351\377\353\354\351\377\354\355\352\377\354\355\352\377" "\354\355\352\377\354\356\353\377\355\356\353\377\355\356\353\377\355" "\356\354\377\356\357\354\377\356\357\354\377\356\357\354\377\356\357" "\355\377\357\357\355\377\357\357\355\377\357\357\355\377\357\360\355" "\377\357\360\355\377\357\360\355\377\357\360\355\377\357\357\355\377" "\357\357\355\377\356\357\355\377\356\357\355\377\356\357\354\377\356" "\357\354\377\356\356\354\377\355\356\354\377\377\377\377\377\220\222" "\215\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\224\226\221\377\377\377\377\377" "\352\353\350\377\352\353\350\377\353\354\351\377\353\354\351\377\353" "\355\352\377\354\355\352\377\354\355\352\377\355\356\353\377\355\356" "\353\377\355\356\354\377\356\356\354\377\356\357\354\377\356\357\355" "\377\357\357\355\377\357\360\355\377\357\360\356\377\357\360\356\377" "\357\360\356\377\360\360\356\377\360\360\356\377\360\360\356\377\360" "\360\356\377\360\360\356\377\360\360\356\377\360\360\356\377\357\360" "\356\377\357\360\356\377\357\360\356\377\357\360\355\377\357\357\355" "\377\356\357\355\377\356\357\354\377\377\377\377\377\217\221\214\377" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\223\225\220\377\377\377\377\377\352\353" "\350\377\353\354\351\377\353\354\351\377\354\355\352\377\354\355\352" "\377\354\355\353\377\355\356\353\377\355\356\353\377\356\356\354\377" "\356\357\354\377\356\357\355\377\357\357\355\377\357\360\356\377\357" "\360\356\377\360\360\356\377\360\361\356\377\360\361\357\377\360\361" "\357\377\361\361\357\377\361\361\357\377\361\361\357\377\361\361\357" "\377\361\361\357\377\361\361\357\377\361\361\357\377\360\361\357\377" "\360\361\357\377\360\361\357\377\360\360\356\377\357\360\356\377\357" "\360\356\377\357\360\355\377\377\377\377\377\216\220\213\377\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\223\225\217\377\377\377\377\377\353\354\351\377" "\353\354\351\377\354\355\352\377\354\355\352\377\354\355\353\377\355" "\356\353\377\355\356\354\377\356\357\354\377\356\357\354\377\357\357" "\355\377\357\360\355\377\357\360\356\377\360\360\356\377\360\361\357" "\377\360\361\357\377\361\361\357\377\361\362\360\377\361\362\360\377" "\362\362\360\377\362\362\360\377\362\362\360\377\362\362\360\377\362" "\362\360\377\362\362\360\377\362\362\360\377\361\362\360\377\361\362" "\360\377\361\361\357\377\361\361\357\377\360\361\357\377\360\361\356" "\377\357\360\356\377\377\377\377\377\216\220\213\377\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\222\224\217\377\377\377\377\377\353\354\351\377\353\355\352" "\377\354\355\352\377\354\355\352\377\355\356\353\377\355\356\353\377" "\356\357\354\377\356\357\354\377\357\357\355\377\357\360\355\377\357" "\360\356\377\360\361\356\377\360\361\357\377\361\361\357\377\361\362" "\360\377\361\362\360\377\362\362\360\377\362\362\361\377\362\363\361" "\377\363\363\361\377\363\363\362\377\363\363\362\377\363\363\362\377" "\363\363\361\377\362\363\361\377\362\363\361\377\362\362\361\377\362" "\362\360\377\361\362\360\377\361\361\357\377\360\361\357\377\360\361" "\357\377\377\377\377\377\215\217\212\377\377\377\377\0\377\377\377\0" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\221\223\216\377\377\377\377\377\353\354\351\377\354\355\352\377\354" "\355\352\377\354\356\353\377\355\356\353\377\355\356\354\377\356\357" "\354\377\356\357\355\377\357\360\355\377\357\360\356\377\360\360\356" "\377\360\361\357\377\361\361\357\377\361\362\360\377\362\362\360\377" "\362\362\361\377\362\363\361\377\363\363\362\377\363\363\362\377\363" "\364\362\377\364\364\363\377\364\364\363\377\364\364\363\377\364\364" "\362\377\363\364\362\377\363\363\362\377\363\363\361\377\362\363\361" "\377\362\362\360\377\361\362\360\377\361\362\360\377\360\361\357\377" "\377\377\377\377\214\216\211\377\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\221\223" "\215\377\377\377\377\377\353\354\351\377\354\355\352\377\354\355\352" "\377\355\356\353\377\355\356\353\377\356\356\354\377\356\357\354\377" "\357\357\355\377\357\360\356\377\360\360\356\377\360\361\357\377\361" "\361\357\377\361\362\360\377\362\362\360\377\362\362\361\377\362\363" "\361\377\363\363\362\377\363\364\362\377\364\364\363\377\364\364\363" "\377\365\365\363\377\365\365\364\377\365\365\364\377\364\365\363\377" "\364\364\363\377\364\364\362\377\363\363\362\377\363\363\361\377\362" "\363\361\377\362\362\360\377\361\362\360\377\361\361\357\377\377\377" "\377\377\214\216\211\377\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\220\222\215\377" "\377\377\377\377\353\354\351\377\354\355\352\377\354\355\352\377\355" "\356\353\377\355\356\353\377\356\357\354\377\356\357\354\377\357\357" "\355\377\357\360\356\377\360\360\356\377\360\361\357\377\361\361\357" "\377\361\362\360\377\362\362\360\377\362\362\361\377\362\363\361\377" "\363\363\362\377\363\364\362\377\364\364\363\377\364\365\363\377\365" "\365\364\377\365\365\364\377\365\365\364\377\365\365\364\377\364\364" "\363\377\364\364\363\377\363\363\362\377\363\363\362\377\362\363\361" "\377\362\362\360\377\361\362\360\377\361\361\357\377\377\377\377\377" "\213\215\210\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\217\221\214\377\377\377" "\377\377\353\354\351\377\354\355\352\377\354\355\352\377\355\356\353" "\377\355\356\353\377\356\356\354\377\356\357\354\377\357\357\355\377" "\357\360\355\377\357\360\356\377\360\361\356\377\360\361\357\377\361" "\361\357\377\361\362\360\377\362\362\360\377\362\363\361\377\363\363" "\362\377\363\363\362\377\364\364\362\377\364\364\363\377\364\364\363" "\377\364\364\363\377\364\364\363\377\364\364\363\377\364\364\363\377" "\363\364\362\377\363\363\362\377\362\363\361\377\362\362\361\377\362" "\362\360\377\361\362\360\377\361\361\357\377\377\377\377\377\212\214" "\207\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\217\221\213\377\377\377\377\377" "\353\354\351\377\354\355\352\377\354\355\352\377\354\355\353\377\355" "\356\353\377\355\356\354\377\356\357\354\377\356\357\355\377\357\360" "\355\377\357\360\356\377\360\360\356\377\360\361\357\377\361\361\357" "\377\361\362\360\377\361\362\360\377\362\362\360\377\362\363\361\377" "\362\363\361\377\363\363\362\377\363\363\362\377\363\363\362\377\363" "\364\362\377\363\364\362\377\363\363\362\377\363\363\362\377\363\363" "\361\377\362\363\361\377\362\362\361\377\362\362\360\377\361\362\360" "\377\361\361\357\377\360\361\357\377\377\377\377\377\212\214\207\377" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\0\0\0\5\216\220\213\377\377\377\377\377\353\354\351" "\377\353\354\351\377\354\355\352\377\354\355\352\377\355\356\353\377" "\355\356\353\377\355\356\354\377\356\357\354\377\356\357\355\377\357" "\360\355\377\357\360\356\377\360\360\356\377\360\361\357\377\360\361" "\357\377\361\361\357\377\361\362\360\377\361\362\360\377\362\362\360" "\377\362\362\361\377\362\362\361\377\362\363\361\377\362\363\361\377" "\362\363\361\377\362\363\361\377\362\362\361\377\362\362\360\377\362" "\362\360\377\361\362\360\377\361\362\360\377\361\361\357\377\360\361" "\357\377\360\360\356\377\377\377\377\377\211\213\206\377\0\0\0\4\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\0\0\0\10\0\0\0\21" "\215\217\212\377\377\377\377\377\352\354\350\377\353\354\351\377\353" "\354\351\377\354\355\352\377\354\355\352\377\355\356\353\377\355\356" "\353\377\355\356\354\377\356\357\354\377\356\357\355\377\357\357\355" "\377\357\360\355\377\357\360\356\377\360\360\356\377\360\361\357\377" "\360\361\357\377\361\361\357\377\361\361\357\377\361\362\360\377\361" "\362\360\377\361\362\360\377\361\362\360\377\361\362\360\377\361\362" "\360\377\361\362\360\377\361\362\360\377\361\361\357\377\360\361\357" "\377\360\361\357\377\360\361\356\377\357\360\356\377\357\360\356\377" "\377\377\377\377\210\212\205\377\0\0\0\20\0\0\0\7\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\0\0\0\4\0\0\0\17\0\0\0\37\216\220\212\374\376\376\376\377\353" "\354\351\377\352\354\350\377\353\354\351\377\353\354\351\377\354\355" "\352\377\354\355\352\377\354\356\353\377\355\356\353\377\355\356\354" "\377\356\356\354\377\356\357\354\377\356\357\355\377\357\357\355\377" "\357\360\355\377\357\360\356\377\357\360\356\377\360\360\356\377\360" "\361\356\377\360\361\357\377\360\361\357\377\360\361\357\377\360\361" "\357\377\360\361\357\377\360\361\357\377\360\361\357\377\360\361\357" "\377\360\360\356\377\360\360\356\377\357\360\356\377\357\360\356\377" "\357\360\355\377\360\360\356\377\376\376\376\377\212\214\207\374\0\0" "\0\33\0\0\0\16\0\0\0\2\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\0\0\0\6\0\0\0\22\0\0\0*\206\207" "\203\320\335\335\334\376\376\376\376\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\376\376\376\377\334\335" "\332\376\203\205\200\315\0\0\0&\0\0\0\20\0\0\0\4\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\0\0\0" "\4\0\0\0\17\0\0\0\37//,L\205\206\202\327\213\215\210\375\213\215\210" "\377\213\215\210\377\213\215\210\377\212\214\207\377\212\214\207\377" "\212\214\207\377\212\214\207\377\212\214\207\377\212\214\207\377\212" "\214\207\377\211\213\206\377\211\213\206\377\211\213\206\377\211\213" "\206\377\211\213\206\377\211\213\206\377\211\213\206\377\210\212\205" "\377\210\212\205\377\210\212\205\377\210\212\205\377\210\212\205\377" "\210\212\205\377\210\212\205\377\210\212\205\377\210\212\205\377\210" "\212\205\377\210\212\205\377\210\212\205\377\210\212\205\377\210\212" "\205\375\204\205\200\325-1-I\0\0\0\33\0\0\0\16\0\0\0\2\377\377\377\0" "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" "\0\377\377\377\0\0\0\0\10\0\0\0\21\0\0\0\32\0\0\0%\0\0\0+\0\0\0""2\0" "\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2" "\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0" "2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0" "\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0""2\0\0\0*\0\0\0$\0\0" "\0\30\0\0\0\20\0\0\0\7\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" "\377\377\0\0\0\0\5\0\0\0\13\0\0\0\17\0\0\0\20\0\0\0\21\0\0\0\21\0\0\0" "\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0" "\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21" "\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0" "\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\21\0\0\0\20\0\0\0\16\0\0\0\12\0" "\0\0\4\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" "\377\0\377\377\377\0\377\377\377\0\377\377\377\0"; nemo-4.4.2/libnemo-private/nemo-default-file-icon.h000066400000000000000000000022421357442400300221520ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Default file icon used by the icon factory. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_DEFAULT_FILE_ICON_H #define NEMO_DEFAULT_FILE_ICON_H extern const int nemo_default_file_icon_width; extern const int nemo_default_file_icon_height; extern const unsigned char nemo_default_file_icon[]; #endif /* NEMO_DEFAULT_FILE_ICON_H */ nemo-4.4.2/libnemo-private/nemo-desktop-directory-file.c000066400000000000000000000436151357442400300232570ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-directory-file.c: Subclass of NemoFile to help implement the virtual desktop. Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-desktop-directory-file.h" #include "nemo-desktop-metadata.h" #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include #include "nemo-desktop-directory.h" #include "nemo-metadata.h" #include #include #include struct NemoDesktopDirectoryFileDetails { NemoDesktopDirectory *desktop_directory; NemoFile *real_dir_file; GHashTable *callbacks; GHashTable *monitors; }; typedef struct { NemoDesktopDirectoryFile *desktop_file; NemoFileCallback callback; gpointer callback_data; NemoFileAttributes delegated_attributes; NemoFileAttributes non_delegated_attributes; GList *non_ready_files; gboolean initializing; } DesktopCallback; typedef struct { NemoDesktopDirectoryFile *desktop_file; NemoFileAttributes delegated_attributes; NemoFileAttributes non_delegated_attributes; } DesktopMonitor; G_DEFINE_TYPE (NemoDesktopDirectoryFile, nemo_desktop_directory_file, NEMO_TYPE_FILE); static gchar * get_indexed_key (NemoFile *file) { NemoDesktopDirectory *desktop_directory; gchar *indexed_key; desktop_directory = NEMO_DESKTOP_DIRECTORY_FILE (file)->details->desktop_directory; indexed_key = g_strdup_printf ("desktop-monitor-%d", NEMO_DESKTOP_DIRECTORY (desktop_directory)->display_number); return indexed_key; } static guint desktop_callback_hash (gconstpointer desktop_callback_as_pointer) { const DesktopCallback *desktop_callback; desktop_callback = desktop_callback_as_pointer; return GPOINTER_TO_UINT (desktop_callback->callback) ^ GPOINTER_TO_UINT (desktop_callback->callback_data); } static gboolean desktop_callback_equal (gconstpointer desktop_callback_as_pointer, gconstpointer desktop_callback_as_pointer_2) { const DesktopCallback *desktop_callback, *desktop_callback_2; desktop_callback = desktop_callback_as_pointer; desktop_callback_2 = desktop_callback_as_pointer_2; return desktop_callback->callback == desktop_callback_2->callback && desktop_callback->callback_data == desktop_callback_2->callback_data; } static void real_file_changed_callback (NemoFile *real_file, gpointer callback_data) { NemoDesktopDirectoryFile *desktop_file; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (callback_data); nemo_file_changed (NEMO_FILE (desktop_file)); } static NemoFileAttributes get_delegated_attributes_mask (void) { return NEMO_FILE_ATTRIBUTE_DEEP_COUNTS | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES; } static void partition_attributes (NemoFileAttributes attributes, NemoFileAttributes *delegated_attributes, NemoFileAttributes *non_delegated_attributes) { NemoFileAttributes mask; mask = get_delegated_attributes_mask (); *delegated_attributes = attributes & mask; *non_delegated_attributes = attributes & ~mask; } static void desktop_directory_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes) { NemoDesktopDirectoryFile *desktop_file; DesktopMonitor *monitor; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); /* Map the client to a unique value so this doesn't interfere * with direct monitoring of the file by the same client. */ monitor = g_hash_table_lookup (desktop_file->details->monitors, client); if (monitor != NULL) { g_assert (monitor->desktop_file == desktop_file); } else { monitor = g_new0 (DesktopMonitor, 1); monitor->desktop_file = desktop_file; g_hash_table_insert (desktop_file->details->monitors, (gpointer) client, monitor); } partition_attributes (attributes, &monitor->delegated_attributes, &monitor->non_delegated_attributes); /* Pawn off partioned attributes to real dir file */ nemo_file_monitor_add (desktop_file->details->real_dir_file, monitor, monitor->delegated_attributes); /* Do the rest ourself */ nemo_directory_monitor_add_internal (file->details->directory, file, client, TRUE, monitor->non_delegated_attributes, NULL, NULL); } static void desktop_directory_file_monitor_remove (NemoFile *file, gconstpointer client) { NemoDesktopDirectoryFile *desktop_file; DesktopMonitor *monitor; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); /* Map the client to the value used by the earlier add call. */ monitor = g_hash_table_lookup (desktop_file->details->monitors, client); if (monitor == NULL) { return; } /* Call through to the real file remove calls. */ g_hash_table_remove (desktop_file->details->monitors, client); /* Remove the locally handled parts */ nemo_directory_monitor_remove_internal (file->details->directory, file, client); } static void desktop_callback_destroy (DesktopCallback *desktop_callback) { g_assert (desktop_callback != NULL); g_assert (NEMO_IS_DESKTOP_DIRECTORY_FILE (desktop_callback->desktop_file)); nemo_file_unref (NEMO_FILE (desktop_callback->desktop_file)); g_list_free (desktop_callback->non_ready_files); g_free (desktop_callback); } static void desktop_callback_check_done (DesktopCallback *desktop_callback) { NemoFile *file; gchar *name; /* Check if we are ready. */ if (desktop_callback->initializing || desktop_callback->non_ready_files != NULL) { return; } /* Ensure our metadata is updated before calling back */ file = NEMO_FILE (desktop_callback->desktop_file); name = get_indexed_key (file); nemo_desktop_update_metadata_from_keyfile (file, name); g_free (name); /* Remove from the hash table before sending it. */ g_hash_table_remove (desktop_callback->desktop_file->details->callbacks, desktop_callback); /* We are ready, so do the real callback. */ (* desktop_callback->callback) (NEMO_FILE (desktop_callback->desktop_file), desktop_callback->callback_data); /* And we are done. */ desktop_callback_destroy (desktop_callback); } static void desktop_callback_remove_file (DesktopCallback *desktop_callback, NemoFile *file) { desktop_callback->non_ready_files = g_list_remove (desktop_callback->non_ready_files, file); desktop_callback_check_done (desktop_callback); } static void ready_callback (NemoFile *file, gpointer callback_data) { DesktopCallback *desktop_callback; g_assert (NEMO_IS_FILE (file)); g_assert (callback_data != NULL); desktop_callback = callback_data; g_assert (g_list_find (desktop_callback->non_ready_files, file) != NULL); desktop_callback_remove_file (desktop_callback, file); } static void desktop_directory_file_call_when_ready (NemoFile *file, NemoFileAttributes attributes, NemoFileCallback callback, gpointer callback_data) { NemoDesktopDirectoryFile *desktop_file; DesktopCallback search_key, *desktop_callback; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); /* Check to be sure we aren't overwriting. */ search_key.callback = callback; search_key.callback_data = callback_data; if (g_hash_table_lookup (desktop_file->details->callbacks, &search_key) != NULL) { g_warning ("tried to add a new callback while an old one was pending"); return; } /* Create a desktop_callback record. */ desktop_callback = g_new0 (DesktopCallback, 1); nemo_file_ref (file); desktop_callback->desktop_file = desktop_file; desktop_callback->callback = callback; desktop_callback->callback_data = callback_data; desktop_callback->initializing = TRUE; partition_attributes (attributes, &desktop_callback->delegated_attributes, &desktop_callback->non_delegated_attributes); desktop_callback->non_ready_files = g_list_prepend (desktop_callback->non_ready_files, file); desktop_callback->non_ready_files = g_list_prepend (desktop_callback->non_ready_files, desktop_file->details->real_dir_file); /* Put it in the hash table. */ g_hash_table_insert (desktop_file->details->callbacks, desktop_callback, desktop_callback); /* Now connect to each file's call_when_ready. */ nemo_directory_call_when_ready_internal (file->details->directory, file, desktop_callback->non_delegated_attributes, FALSE, NULL, ready_callback, desktop_callback); nemo_file_call_when_ready (desktop_file->details->real_dir_file, desktop_callback->delegated_attributes, ready_callback, desktop_callback); desktop_callback->initializing = FALSE; /* Check if any files became read while we were connecting up * the call_when_ready callbacks (also handles the pathological * case where there are no files at all). */ desktop_callback_check_done (desktop_callback); } static void desktop_directory_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data) { NemoDesktopDirectoryFile *desktop_file; DesktopCallback search_key, *desktop_callback; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); /* Find the entry in the table. */ search_key.callback = callback; search_key.callback_data = callback_data; desktop_callback = g_hash_table_lookup (desktop_file->details->callbacks, &search_key); if (desktop_callback == NULL) { return; } /* Remove from the hash table before working with it. */ g_hash_table_remove (desktop_callback->desktop_file->details->callbacks, desktop_callback); /* Tell the real directory to cancel the call. */ nemo_directory_cancel_callback_internal (file->details->directory, file, NULL, ready_callback, desktop_callback); nemo_file_cancel_call_when_ready (desktop_file->details->real_dir_file, ready_callback, desktop_callback); desktop_callback_destroy (desktop_callback); } static gboolean real_check_if_ready (NemoFile *file, NemoFileAttributes attributes) { return nemo_directory_check_if_ready_internal (file->details->directory, file, attributes); } static gboolean desktop_directory_file_check_if_ready (NemoFile *file, NemoFileAttributes attributes) { NemoFileAttributes delegated_attributes, non_delegated_attributes; NemoDesktopDirectoryFile *desktop_file; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); partition_attributes (attributes, &delegated_attributes, &non_delegated_attributes); return real_check_if_ready (file, non_delegated_attributes) && nemo_file_check_if_ready (desktop_file->details->real_dir_file, delegated_attributes); } static gboolean desktop_directory_file_get_item_count (NemoFile *file, guint *count, gboolean *count_unreadable) { NemoDesktopDirectoryFile *desktop_file; gboolean got_count; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); got_count = nemo_file_get_directory_item_count (desktop_file->details->real_dir_file, count, count_unreadable); if (count) { *count += g_list_length (file->details->directory->details->file_list); } return got_count; } static NemoRequestStatus desktop_directory_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size) { NemoDesktopDirectoryFile *desktop_file; NemoRequestStatus status; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); status = nemo_file_get_deep_counts (desktop_file->details->real_dir_file, directory_count, file_count, unreadable_directory_count, hidden_count, total_size, TRUE); if (file_count) { *file_count += g_list_length (file->details->directory->details->file_list); } return status; } static gboolean desktop_directory_file_get_date (NemoFile *file, NemoDateType date_type, time_t *date) { NemoDesktopDirectoryFile *desktop_file; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (file); return nemo_file_get_date (desktop_file->details->real_dir_file, date_type, date); } static char * desktop_directory_file_get_where_string (NemoFile *file) { return g_strdup (_("on the desktop")); } static void monitor_destroy (gpointer data) { DesktopMonitor *monitor = data; nemo_file_monitor_remove (NEMO_FILE (monitor->desktop_file->details->real_dir_file), monitor); g_free (monitor); } static void nemo_desktop_directory_file_set_metadata (NemoFile *file, const char *key, const char *value) { gchar *name; name = get_indexed_key (file); nemo_desktop_set_metadata_string (file, name, key, value); g_free (name); } static void nemo_desktop_directory_file_set_metadata_as_list (NemoFile *file, const char *key, char **value) { gchar *name; name = get_indexed_key (file); nemo_desktop_set_metadata_stringv (file, name, key, (const gchar **) value); g_free (name); } static gchar * nemo_desktop_directory_file_get_metadata (NemoFile *file, const char *key) { gchar *name; gchar *string; name = get_indexed_key (file); string = nemo_desktop_get_metadata_string (file, name, key); g_free (name); return string; } static gchar ** nemo_desktop_directory_file_get_metadata_as_list (NemoFile *file, const char *key) { gchar *name; gchar **stringv; name = get_indexed_key (file); stringv = nemo_desktop_get_metadata_stringv (file, name, key); g_free (name); return stringv; } static void nemo_desktop_directory_file_init (NemoDesktopDirectoryFile *desktop_file) { NemoDesktopDirectory *desktop_directory; NemoDirectory *real_dir; NemoFile *real_dir_file; desktop_file->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_file, NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NemoDesktopDirectoryFileDetails); desktop_directory = NEMO_DESKTOP_DIRECTORY (nemo_directory_get_by_uri (EEL_DESKTOP_URI)); desktop_file->details->desktop_directory = desktop_directory; desktop_file->details->callbacks = g_hash_table_new (desktop_callback_hash, desktop_callback_equal); desktop_file->details->monitors = g_hash_table_new_full (NULL, NULL, NULL, monitor_destroy); real_dir = nemo_desktop_directory_get_real_directory (desktop_directory); real_dir_file = nemo_directory_get_corresponding_file (real_dir); nemo_directory_unref (real_dir); desktop_file->details->real_dir_file = real_dir_file; g_signal_connect_object (real_dir_file, "changed", G_CALLBACK (real_file_changed_callback), desktop_file, 0); } static void desktop_callback_remove_file_cover (gpointer key, gpointer value, gpointer callback_data) { desktop_callback_remove_file (value, NEMO_FILE (callback_data)); } static void desktop_finalize (GObject *object) { NemoDesktopDirectoryFile *desktop_file; NemoDesktopDirectory *desktop_directory; desktop_file = NEMO_DESKTOP_DIRECTORY_FILE (object); desktop_directory = desktop_file->details->desktop_directory; /* Todo: ghash now safe? */ eel_g_hash_table_safe_for_each (desktop_file->details->callbacks, desktop_callback_remove_file_cover, desktop_file->details->real_dir_file); if (g_hash_table_size (desktop_file->details->callbacks) != 0) { g_warning ("call_when_ready still pending when desktop virtual file is destroyed"); } g_hash_table_destroy (desktop_file->details->callbacks); g_hash_table_destroy (desktop_file->details->monitors); nemo_file_unref (desktop_file->details->real_dir_file); nemo_directory_unref (NEMO_DIRECTORY (desktop_directory)); G_OBJECT_CLASS (nemo_desktop_directory_file_parent_class)->finalize (object); } static void nemo_desktop_directory_file_class_init (NemoDesktopDirectoryFileClass *klass) { GObjectClass *object_class; NemoFileClass *file_class; object_class = G_OBJECT_CLASS (klass); file_class = NEMO_FILE_CLASS (klass); object_class->finalize = desktop_finalize; file_class->default_file_type = G_FILE_TYPE_DIRECTORY; file_class->monitor_add = desktop_directory_file_monitor_add; file_class->monitor_remove = desktop_directory_file_monitor_remove; file_class->call_when_ready = desktop_directory_file_call_when_ready; file_class->cancel_call_when_ready = desktop_directory_file_cancel_call_when_ready; file_class->check_if_ready = desktop_directory_file_check_if_ready; file_class->get_item_count = desktop_directory_file_get_item_count; file_class->get_deep_counts = desktop_directory_file_get_deep_counts; file_class->get_date = desktop_directory_file_get_date; file_class->get_where_string = desktop_directory_file_get_where_string; file_class->set_metadata = nemo_desktop_directory_file_set_metadata; file_class->get_metadata = nemo_desktop_directory_file_get_metadata; file_class->set_metadata_as_list = nemo_desktop_directory_file_set_metadata_as_list; file_class->get_metadata_as_list = nemo_desktop_directory_file_get_metadata_as_list; g_type_class_add_private (klass, sizeof (NemoDesktopDirectoryFileDetails)); } nemo-4.4.2/libnemo-private/nemo-desktop-directory-file.h000066400000000000000000000043331357442400300232560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-directory-file.h: Subclass of NemoFile to implement the the case of the desktop directory Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_DESKTOP_DIRECTORY_FILE_H #define NEMO_DESKTOP_DIRECTORY_FILE_H #include #define NEMO_TYPE_DESKTOP_DIRECTORY_FILE nemo_desktop_directory_file_get_type() #define NEMO_DESKTOP_DIRECTORY_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NemoDesktopDirectoryFile)) #define NEMO_DESKTOP_DIRECTORY_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NemoDesktopDirectoryFileClass)) #define NEMO_IS_DESKTOP_DIRECTORY_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_DIRECTORY_FILE)) #define NEMO_IS_DESKTOP_DIRECTORY_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_DIRECTORY_FILE)) #define NEMO_DESKTOP_DIRECTORY_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NemoDesktopDirectoryFileClass)) typedef struct NemoDesktopDirectoryFileDetails NemoDesktopDirectoryFileDetails; typedef struct { NemoFile parent_slot; NemoDesktopDirectoryFileDetails *details; } NemoDesktopDirectoryFile; typedef struct { NemoFileClass parent_slot; } NemoDesktopDirectoryFileClass; GType nemo_desktop_directory_file_get_type (void); #endif /* NEMO_DESKTOP_DIRECTORY_FILE_H */ nemo-4.4.2/libnemo-private/nemo-desktop-directory.c000066400000000000000000000370611357442400300223400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-directory.c: Subclass of NemoDirectory to implement a virtual directory consisting of the desktop directory and the desktop icons Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-desktop-directory.h" #include "nemo-directory-private.h" #include "nemo-file.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include "nemo-global-preferences.h" #include struct NemoDesktopDirectoryDetails { NemoDirectory *real_directory; GHashTable *callbacks; GHashTable *monitors; }; typedef struct { NemoDesktopDirectory *desktop_dir; NemoDirectoryCallback callback; gpointer callback_data; NemoFileAttributes wait_for_attributes; gboolean wait_for_file_list; GList *non_ready_directories; GList *merged_file_list; } MergedCallback; typedef struct { NemoDesktopDirectory *desktop_dir; gboolean monitor_hidden_files; NemoFileAttributes monitor_attributes; } MergedMonitor; static void desktop_directory_changed_callback (gpointer data); G_DEFINE_TYPE (NemoDesktopDirectory, nemo_desktop_directory, NEMO_TYPE_DIRECTORY); static gboolean desktop_contains_file (NemoDirectory *directory, NemoFile *file) { NemoDesktopDirectory *desktop; desktop = NEMO_DESKTOP_DIRECTORY (directory); if (nemo_directory_contains_file (desktop->details->real_directory, file)) { return TRUE; } return file->details->directory == directory; } static guint merged_callback_hash (gconstpointer merged_callback_as_pointer) { const MergedCallback *merged_callback; merged_callback = merged_callback_as_pointer; return GPOINTER_TO_UINT (merged_callback->callback) ^ GPOINTER_TO_UINT (merged_callback->callback_data); } static gboolean merged_callback_equal (gconstpointer merged_callback_as_pointer, gconstpointer merged_callback_as_pointer_2) { const MergedCallback *merged_callback, *merged_callback_2; merged_callback = merged_callback_as_pointer; merged_callback_2 = merged_callback_as_pointer_2; return merged_callback->callback == merged_callback_2->callback && merged_callback->callback_data == merged_callback_2->callback_data; } static void merged_callback_destroy (MergedCallback *merged_callback) { g_assert (merged_callback != NULL); g_assert (NEMO_IS_DESKTOP_DIRECTORY (merged_callback->desktop_dir)); g_list_free (merged_callback->non_ready_directories); nemo_file_list_free (merged_callback->merged_file_list); g_free (merged_callback); } static void merged_callback_check_done (MergedCallback *merged_callback) { /* Check if we are ready. */ if (merged_callback->non_ready_directories != NULL) { return; } /* Remove from the hash table before sending it. */ g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback); /* We are ready, so do the real callback. */ (* merged_callback->callback) (NEMO_DIRECTORY (merged_callback->desktop_dir), merged_callback->merged_file_list, merged_callback->callback_data); /* And we are done. */ merged_callback_destroy (merged_callback); } static void merged_callback_remove_directory (MergedCallback *merged_callback, NemoDirectory *directory) { merged_callback->non_ready_directories = g_list_remove (merged_callback->non_ready_directories, directory); merged_callback_check_done (merged_callback); } static void directory_ready_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { MergedCallback *merged_callback; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (callback_data != NULL); merged_callback = callback_data; g_assert (g_list_find (merged_callback->non_ready_directories, directory) != NULL); /* Update based on this call. */ merged_callback->merged_file_list = g_list_concat (merged_callback->merged_file_list, nemo_file_list_copy (files)); /* Check if we are ready. */ merged_callback_remove_directory (merged_callback, directory); } static void desktop_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback callback, gpointer callback_data) { NemoDesktopDirectory *desktop; MergedCallback search_key, *merged_callback; desktop = NEMO_DESKTOP_DIRECTORY (directory); /* Check to be sure we aren't overwriting. */ search_key.callback = callback; search_key.callback_data = callback_data; if (g_hash_table_lookup (desktop->details->callbacks, &search_key) != NULL) { g_warning ("tried to add a new callback while an old one was pending"); return; } /* Create a merged_callback record. */ merged_callback = g_new0 (MergedCallback, 1); merged_callback->desktop_dir = desktop; merged_callback->callback = callback; merged_callback->callback_data = callback_data; merged_callback->wait_for_attributes = file_attributes; merged_callback->wait_for_file_list = wait_for_file_list; merged_callback->non_ready_directories = g_list_prepend (merged_callback->non_ready_directories, directory); merged_callback->non_ready_directories = g_list_prepend (merged_callback->non_ready_directories, desktop->details->real_directory); merged_callback->merged_file_list = g_list_concat (NULL, nemo_file_list_copy (directory->details->file_list)); /* Put it in the hash table. */ g_hash_table_insert (desktop->details->callbacks, merged_callback, merged_callback); /* Now tell all the directories about it. */ nemo_directory_call_when_ready (desktop->details->real_directory, merged_callback->wait_for_attributes, merged_callback->wait_for_file_list, directory_ready_callback, merged_callback); nemo_directory_call_when_ready_internal (directory, NULL, merged_callback->wait_for_attributes, merged_callback->wait_for_file_list, directory_ready_callback, NULL, merged_callback); } static void desktop_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data) { NemoDesktopDirectory *desktop; MergedCallback search_key, *merged_callback; GList *node; desktop = NEMO_DESKTOP_DIRECTORY (directory); /* Find the entry in the table. */ search_key.callback = callback; search_key.callback_data = callback_data; merged_callback = g_hash_table_lookup (desktop->details->callbacks, &search_key); if (merged_callback == NULL) { return; } /* Remove from the hash table before working with it. */ g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback); /* Tell all the directories to cancel the call. */ for (node = merged_callback->non_ready_directories; node != NULL; node = node->next) { nemo_directory_cancel_callback (node->data, directory_ready_callback, merged_callback); } merged_callback_destroy (merged_callback); } static void merged_monitor_destroy (MergedMonitor *monitor) { NemoDesktopDirectory *desktop; desktop = monitor->desktop_dir; /* Call through to the real directory remove calls. */ nemo_directory_file_monitor_remove (desktop->details->real_directory, monitor); nemo_directory_monitor_remove_internal (NEMO_DIRECTORY (desktop), NULL, monitor); g_free (monitor); } static void build_merged_callback_list (NemoDirectory *directory, GList *file_list, gpointer callback_data) { GList **merged_list; merged_list = callback_data; *merged_list = g_list_concat (*merged_list, nemo_file_list_copy (file_list)); } static void desktop_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { NemoDesktopDirectory *desktop; MergedMonitor *monitor; GList *merged_callback_list; desktop = NEMO_DESKTOP_DIRECTORY (directory); /* Map the client to a unique value so this doesn't interfere * with direct monitoring of the directory by the same client. */ monitor = g_hash_table_lookup (desktop->details->monitors, client); if (monitor != NULL) { g_assert (monitor->desktop_dir == desktop); } else { monitor = g_new0 (MergedMonitor, 1); monitor->desktop_dir = desktop; g_hash_table_insert (desktop->details->monitors, (gpointer) client, monitor); } monitor->monitor_hidden_files = monitor_hidden_files; monitor->monitor_attributes = file_attributes; /* Call through to the real directory add calls. */ merged_callback_list = NULL; /* Call up to real dir */ nemo_directory_file_monitor_add (desktop->details->real_directory, monitor, monitor_hidden_files, file_attributes, build_merged_callback_list, &merged_callback_list); /* Handle the desktop part */ merged_callback_list = g_list_concat (merged_callback_list, nemo_file_list_copy (directory->details->file_list)); if (callback != NULL) { (* callback) (directory, merged_callback_list, callback_data); } nemo_file_list_free (merged_callback_list); } static void desktop_monitor_remove (NemoDirectory *directory, gconstpointer client) { NemoDesktopDirectory *desktop; MergedMonitor *monitor; desktop = NEMO_DESKTOP_DIRECTORY (directory); monitor = g_hash_table_lookup (desktop->details->monitors, client); if (monitor == NULL) { return; } g_hash_table_remove (desktop->details->monitors, client); } static void desktop_force_reload (NemoDirectory *directory) { NemoDesktopDirectory *desktop; desktop = NEMO_DESKTOP_DIRECTORY (directory); nemo_directory_force_reload (desktop->details->real_directory); /* We don't invalidate the files in desktop, since they are always up to date. (And we don't ever want to mark them invalid.) */ } static gboolean desktop_are_all_files_seen (NemoDirectory *directory) { NemoDesktopDirectory *desktop; desktop = NEMO_DESKTOP_DIRECTORY (directory); if (!nemo_directory_are_all_files_seen (desktop->details->real_directory)) { return FALSE; } return TRUE; } static gboolean desktop_is_not_empty (NemoDirectory *directory) { NemoDesktopDirectory *desktop; desktop = NEMO_DESKTOP_DIRECTORY (directory); if (nemo_directory_is_not_empty (desktop->details->real_directory)) { return TRUE; } return directory->details->file_list != NULL; } static GList * desktop_get_file_list (NemoDirectory *directory) { GList *real_dir_file_list, *desktop_dir_file_list = NULL; real_dir_file_list = nemo_directory_get_file_list (NEMO_DESKTOP_DIRECTORY (directory)->details->real_directory); desktop_dir_file_list = NEMO_DIRECTORY_CLASS (nemo_desktop_directory_parent_class)->get_file_list (directory); return g_list_concat (real_dir_file_list, desktop_dir_file_list); } NemoDirectory * nemo_desktop_directory_get_real_directory (NemoDesktopDirectory *desktop) { nemo_directory_ref (desktop->details->real_directory); return desktop->details->real_directory; } static void desktop_finalize (GObject *object) { NemoDesktopDirectory *desktop; desktop = NEMO_DESKTOP_DIRECTORY (object); nemo_directory_unref (desktop->details->real_directory); g_hash_table_destroy (desktop->details->callbacks); g_hash_table_destroy (desktop->details->monitors); g_free (desktop->details); g_signal_handlers_disconnect_by_func (nemo_preferences, desktop_directory_changed_callback, desktop); G_OBJECT_CLASS (nemo_desktop_directory_parent_class)->finalize (object); } static void done_loading_callback (NemoDirectory *real_directory, NemoDesktopDirectory *desktop) { nemo_directory_emit_done_loading (NEMO_DIRECTORY (desktop)); } static void forward_files_added_cover (NemoDirectory *real_directory, GList *files, gpointer callback_data) { nemo_directory_emit_files_added (NEMO_DIRECTORY (callback_data), files); } static void forward_files_changed_cover (NemoDirectory *real_directory, GList *files, gpointer callback_data) { nemo_directory_emit_files_changed (NEMO_DIRECTORY (callback_data), files); } static void update_desktop_directory (NemoDesktopDirectory *desktop) { char *desktop_path; char *desktop_uri; NemoDirectory *real_directory; real_directory = desktop->details->real_directory; if (real_directory != NULL) { g_hash_table_remove_all (desktop->details->callbacks); g_hash_table_remove_all (desktop->details->monitors); g_signal_handlers_disconnect_by_func (real_directory, done_loading_callback, desktop); g_signal_handlers_disconnect_by_func (real_directory, forward_files_added_cover, desktop); g_signal_handlers_disconnect_by_func (real_directory, forward_files_changed_cover, desktop); nemo_directory_unref (real_directory); } desktop_path = nemo_get_desktop_directory (); desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL); real_directory = nemo_directory_get_by_uri (desktop_uri); g_free (desktop_uri); g_free (desktop_path); g_signal_connect_object (real_directory, "done_loading", G_CALLBACK (done_loading_callback), desktop, 0); g_signal_connect_object (real_directory, "files_added", G_CALLBACK (forward_files_added_cover), desktop, 0); g_signal_connect_object (real_directory, "files_changed", G_CALLBACK (forward_files_changed_cover), desktop, 0); desktop->details->real_directory = real_directory; } static void desktop_directory_changed_callback (gpointer data) { update_desktop_directory (NEMO_DESKTOP_DIRECTORY (data)); nemo_directory_force_reload (NEMO_DIRECTORY (data)); } static void nemo_desktop_directory_init (NemoDesktopDirectory *desktop) { desktop->details = g_new0 (NemoDesktopDirectoryDetails, 1); desktop->details->callbacks = g_hash_table_new_full (merged_callback_hash, merged_callback_equal, NULL, (GDestroyNotify)merged_callback_destroy); desktop->details->monitors = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)merged_monitor_destroy); desktop->display_number = -1; update_desktop_directory (NEMO_DESKTOP_DIRECTORY (desktop)); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_directory_changed_callback), desktop); } static void nemo_desktop_directory_class_init (NemoDesktopDirectoryClass *class) { NemoDirectoryClass *directory_class; directory_class = NEMO_DIRECTORY_CLASS (class); G_OBJECT_CLASS (class)->finalize = desktop_finalize; directory_class->contains_file = desktop_contains_file; directory_class->call_when_ready = desktop_call_when_ready; directory_class->cancel_callback = desktop_cancel_callback; directory_class->file_monitor_add = desktop_monitor_add; directory_class->file_monitor_remove = desktop_monitor_remove; directory_class->force_reload = desktop_force_reload; directory_class->are_all_files_seen = desktop_are_all_files_seen; directory_class->is_not_empty = desktop_is_not_empty; /* Override get_file_list so that we can return the list of files * in NemoDesktopDirectory->details->real_directory, * in addition to the list of standard desktop icons on the desktop. */ directory_class->get_file_list = desktop_get_file_list; } nemo-4.4.2/libnemo-private/nemo-desktop-directory.h000066400000000000000000000044561357442400300223470ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-directory.h: Subclass of NemoDirectory to implement a virtual directory consisting of the desktop directory and the desktop icons Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_DESKTOP_DIRECTORY_H #define NEMO_DESKTOP_DIRECTORY_H #include #define NEMO_TYPE_DESKTOP_DIRECTORY nemo_desktop_directory_get_type() #define NEMO_DESKTOP_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_DIRECTORY, NemoDesktopDirectory)) #define NEMO_DESKTOP_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_DIRECTORY, NemoDesktopDirectoryClass)) #define NEMO_IS_DESKTOP_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_DIRECTORY)) #define NEMO_IS_DESKTOP_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_DIRECTORY)) #define NEMO_DESKTOP_DIRECTORY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_DIRECTORY, NemoDesktopDirectoryClass)) typedef struct NemoDesktopDirectoryDetails NemoDesktopDirectoryDetails; typedef struct { NemoDirectory parent_slot; NemoDesktopDirectoryDetails *details; gint display_number; } NemoDesktopDirectory; typedef struct { NemoDirectoryClass parent_slot; } NemoDesktopDirectoryClass; GType nemo_desktop_directory_get_type (void); NemoDirectory * nemo_desktop_directory_get_real_directory (NemoDesktopDirectory *desktop_directory); #endif /* NEMO_DESKTOP_DIRECTORY_H */ nemo-4.4.2/libnemo-private/nemo-desktop-icon-file.c000066400000000000000000000247401357442400300222010ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-icon-file.c: Subclass of NemoFile to help implement the virtual desktop icons. Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-desktop-icon-file.h" #include "nemo-desktop-metadata.h" #include "nemo-desktop-directory-file.h" #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include "nemo-file-operations.h" #include #include "nemo-desktop-directory.h" #include #include #include struct NemoDesktopIconFileDetails { NemoDesktopLink *link; }; G_DEFINE_TYPE(NemoDesktopIconFile, nemo_desktop_icon_file, NEMO_TYPE_FILE) static void desktop_icon_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes) { nemo_directory_monitor_add_internal (file->details->directory, file, client, TRUE, attributes, NULL, NULL); } static void desktop_icon_file_monitor_remove (NemoFile *file, gconstpointer client) { nemo_directory_monitor_remove_internal (file->details->directory, file, client); } static void desktop_icon_file_call_when_ready (NemoFile *file, NemoFileAttributes attributes, NemoFileCallback callback, gpointer callback_data) { nemo_directory_call_when_ready_internal (file->details->directory, file, attributes, FALSE, NULL, callback, callback_data); } static void desktop_icon_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data) { nemo_directory_cancel_callback_internal (file->details->directory, file, NULL, callback, callback_data); } static gboolean desktop_icon_file_check_if_ready (NemoFile *file, NemoFileAttributes attributes) { return nemo_directory_check_if_ready_internal (file->details->directory, file, attributes); } static gboolean desktop_icon_file_get_item_count (NemoFile *file, guint *count, gboolean *count_unreadable) { if (count != NULL) { *count = 0; } if (count_unreadable != NULL) { *count_unreadable = FALSE; } return TRUE; } static NemoRequestStatus desktop_icon_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size) { if (directory_count != NULL) { *directory_count = 0; } if (file_count != NULL) { *file_count = 0; } if (unreadable_directory_count != NULL) { *unreadable_directory_count = 0; } if (total_size != NULL) { *total_size = 0; } if (hidden_count != NULL) { *hidden_count = 0; } return NEMO_REQUEST_DONE; } static gboolean desktop_icon_file_get_date (NemoFile *file, NemoDateType date_type, time_t *date) { NemoDesktopIconFile *desktop_file; desktop_file = NEMO_DESKTOP_ICON_FILE (file); return nemo_desktop_link_get_date (desktop_file->details->link, date_type, date); } static char * desktop_icon_file_get_where_string (NemoFile *file) { return g_strdup (_("on the desktop")); } static void nemo_desktop_icon_file_init (NemoDesktopIconFile *desktop_file) { desktop_file->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_file, NEMO_TYPE_DESKTOP_ICON_FILE, NemoDesktopIconFileDetails); } static void update_info_from_link (NemoDesktopIconFile *icon_file) { NemoFile *file; NemoDesktopLink *link; char *display_name; GMount *mount; file = NEMO_FILE (icon_file); link = icon_file->details->link; if (link == NULL) { return; } eel_ref_str_unref (file->details->mime_type); file->details->mime_type = eel_ref_str_get_unique ("application/x-nemo-link"); file->details->type = G_FILE_TYPE_SHORTCUT; file->details->size = 0; file->details->has_permissions = FALSE; file->details->can_read = TRUE; file->details->can_write = TRUE; file->details->can_mount = FALSE; file->details->can_unmount = FALSE; file->details->can_eject = FALSE; if (file->details->mount) { g_object_unref (file->details->mount); } mount = nemo_desktop_link_get_mount (link); file->details->mount = mount; if (mount) { file->details->can_unmount = g_mount_can_unmount (mount); file->details->can_eject = g_mount_can_eject (mount); } file->details->file_info_is_up_to_date = TRUE; display_name = nemo_desktop_link_get_display_name (link); nemo_file_set_display_name (file, display_name, NULL, TRUE); g_free (display_name); if (file->details->icon != NULL) { g_object_unref (file->details->icon); } file->details->icon = nemo_desktop_link_get_icon (link); g_free (file->details->activation_uri); file->details->activation_uri = nemo_desktop_link_get_activation_uri (link); file->details->got_link_info = TRUE; file->details->link_info_is_up_to_date = TRUE; file->details->directory_count = 0; file->details->got_directory_count = TRUE; file->details->directory_count_is_up_to_date = TRUE; } void nemo_desktop_icon_file_update (NemoDesktopIconFile *icon_file) { NemoFile *file; update_info_from_link (icon_file); file = NEMO_FILE (icon_file); nemo_file_changed (file); } void nemo_desktop_icon_file_remove (NemoDesktopIconFile *icon_file) { NemoFile *file; GList list; icon_file->details->link = NULL; file = NEMO_FILE (icon_file); /* ref here because we might be removing the last ref when we * mark the file gone below, but we need to keep a ref at * least long enough to send the change notification. */ nemo_file_ref (file); file->details->is_gone = TRUE; list.data = file; list.next = NULL; list.prev = NULL; nemo_directory_remove_file (file->details->directory, file); nemo_directory_emit_change_signals (file->details->directory, &list); nemo_file_unref (file); } NemoDesktopIconFile * nemo_desktop_icon_file_new (NemoDesktopLink *link) { NemoFile *file; NemoDirectory *directory; NemoDesktopIconFile *icon_file; GList list; char *name; directory = nemo_directory_get_by_uri (EEL_DESKTOP_URI); file = NEMO_FILE (g_object_new (NEMO_TYPE_DESKTOP_ICON_FILE, NULL)); #ifdef NEMO_FILE_DEBUG_REF printf("%10p ref'd\n", file); eazel_dump_stack_trace ("\t", 10); #endif file->details->directory = directory; icon_file = NEMO_DESKTOP_ICON_FILE (file); icon_file->details->link = link; name = nemo_desktop_link_get_file_name (link); file->details->name = eel_ref_str_new (name); g_free (name); update_info_from_link (icon_file); nemo_desktop_update_metadata_from_keyfile (file, file->details->name); nemo_directory_add_file (directory, file); list.data = file; list.next = NULL; list.prev = NULL; nemo_directory_emit_files_added (directory, &list); return icon_file; } /* Note: This can return NULL if the link was recently removed (i.e. unmounted) */ NemoDesktopLink * nemo_desktop_icon_file_get_link (NemoDesktopIconFile *icon_file) { if (icon_file->details->link) return g_object_ref (icon_file->details->link); else return NULL; } static void nemo_desktop_icon_file_unmount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoDesktopIconFile *desktop_file; GMount *mount; desktop_file = NEMO_DESKTOP_ICON_FILE (file); if (desktop_file) { mount = nemo_desktop_link_get_mount (desktop_file->details->link); if (mount != NULL) { nemo_file_operations_unmount_mount (NULL, mount, FALSE, TRUE); } } } static void nemo_desktop_icon_file_eject (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoDesktopIconFile *desktop_file; GMount *mount; desktop_file = NEMO_DESKTOP_ICON_FILE (file); if (desktop_file) { mount = nemo_desktop_link_get_mount (desktop_file->details->link); if (mount != NULL) { nemo_file_operations_unmount_mount (NULL, mount, TRUE, TRUE); } } } static void nemo_desktop_icon_file_set_metadata (NemoFile *file, const char *key, const char *value) { nemo_desktop_set_metadata_string (file, file->details->name, key, value); } static void nemo_desktop_icon_file_set_metadata_as_list (NemoFile *file, const char *key, char **value) { nemo_desktop_set_metadata_stringv (file, file->details->name, key, (const gchar **) value); } static void nemo_desktop_icon_file_class_init (NemoDesktopIconFileClass *klass) { GObjectClass *object_class; NemoFileClass *file_class; object_class = G_OBJECT_CLASS (klass); file_class = NEMO_FILE_CLASS (klass); file_class->default_file_type = G_FILE_TYPE_DIRECTORY; file_class->monitor_add = desktop_icon_file_monitor_add; file_class->monitor_remove = desktop_icon_file_monitor_remove; file_class->call_when_ready = desktop_icon_file_call_when_ready; file_class->cancel_call_when_ready = desktop_icon_file_cancel_call_when_ready; file_class->check_if_ready = desktop_icon_file_check_if_ready; file_class->get_item_count = desktop_icon_file_get_item_count; file_class->get_deep_counts = desktop_icon_file_get_deep_counts; file_class->get_date = desktop_icon_file_get_date; file_class->get_where_string = desktop_icon_file_get_where_string; file_class->set_metadata = nemo_desktop_icon_file_set_metadata; file_class->set_metadata_as_list = nemo_desktop_icon_file_set_metadata_as_list; file_class->unmount = nemo_desktop_icon_file_unmount; file_class->eject = nemo_desktop_icon_file_eject; g_type_class_add_private (object_class, sizeof(NemoDesktopIconFileDetails)); } nemo-4.4.2/libnemo-private/nemo-desktop-icon-file.h000066400000000000000000000047421357442400300222060ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-file.h: Subclass of NemoFile to implement the the case of a desktop icon file Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_DESKTOP_ICON_FILE_H #define NEMO_DESKTOP_ICON_FILE_H #include #include #define NEMO_TYPE_DESKTOP_ICON_FILE nemo_desktop_icon_file_get_type() #define NEMO_DESKTOP_ICON_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_ICON_FILE, NemoDesktopIconFile)) #define NEMO_DESKTOP_ICON_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_ICON_FILE, NemoDesktopIconFileClass)) #define NEMO_IS_DESKTOP_ICON_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_ICON_FILE)) #define NEMO_IS_DESKTOP_ICON_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_ICON_FILE)) #define NEMO_DESKTOP_ICON_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_ICON_FILE, NemoDesktopIconFileClass)) typedef struct NemoDesktopIconFileDetails NemoDesktopIconFileDetails; typedef struct { NemoFile parent_slot; NemoDesktopIconFileDetails *details; } NemoDesktopIconFile; typedef struct { NemoFileClass parent_slot; } NemoDesktopIconFileClass; GType nemo_desktop_icon_file_get_type (void); NemoDesktopIconFile *nemo_desktop_icon_file_new (NemoDesktopLink *link); void nemo_desktop_icon_file_update (NemoDesktopIconFile *icon_file); void nemo_desktop_icon_file_remove (NemoDesktopIconFile *icon_file); NemoDesktopLink *nemo_desktop_icon_file_get_link (NemoDesktopIconFile *icon_file); #endif /* NEMO_DESKTOP_ICON_FILE_H */ nemo-4.4.2/libnemo-private/nemo-desktop-link-monitor.c000066400000000000000000000341071357442400300227540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-link-monitor.c: singleton that manages the links Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-desktop-link-monitor.h" #include "nemo-desktop-metadata.h" #include "nemo-desktop-link.h" #include "nemo-desktop-icon-file.h" #include "nemo-directory.h" #include "nemo-desktop-directory.h" #include "nemo-global-preferences.h" #include #include #include #include #include #include #include #include struct NemoDesktopLinkMonitorDetails { GVolumeMonitor *volume_monitor; NemoDirectory *desktop_dir; NemoDesktopLink *home_link; NemoDesktopLink *computer_link; NemoDesktopLink *trash_link; NemoDesktopLink *network_link; GList *mount_links; }; G_DEFINE_TYPE (NemoDesktopLinkMonitor, nemo_desktop_link_monitor, G_TYPE_OBJECT); static NemoDesktopLinkMonitor *the_link_monitor = NULL; static void destroy_desktop_link_monitor (void) { if (the_link_monitor != NULL) { g_object_unref (the_link_monitor); } } NemoDesktopLinkMonitor * nemo_desktop_link_monitor_get (void) { if (the_link_monitor == NULL) { g_object_new (NEMO_TYPE_DESKTOP_LINK_MONITOR, NULL); eel_debug_call_at_shutdown (destroy_desktop_link_monitor); } return the_link_monitor; } static void volume_delete_dialog (GtkWidget *parent_view, NemoDesktopLink *link) { GMount *mount; char *dialog_str; char *display_name; mount = nemo_desktop_link_get_mount (link); if (mount != NULL) { display_name = nemo_desktop_link_get_display_name (link); dialog_str = g_strdup_printf (_("You cannot move the volume \"%s\" to the trash."), display_name); g_free (display_name); if (g_mount_can_eject (mount)) { eel_run_simple_dialog (parent_view, FALSE, GTK_MESSAGE_ERROR, dialog_str, _("If you want to eject the volume, please use \"Eject\" in the " "popup menu of the volume."), GTK_STOCK_OK, NULL); } else { eel_run_simple_dialog (parent_view, FALSE, GTK_MESSAGE_ERROR, dialog_str, _("If you want to unmount the volume, please use \"Unmount Volume\" in the " "popup menu of the volume."), GTK_STOCK_OK, NULL); } g_object_unref (mount); g_free (dialog_str); } } void nemo_desktop_link_monitor_delete_link (NemoDesktopLinkMonitor *monitor, NemoDesktopLink *link, GtkWidget *parent_view) { switch (nemo_desktop_link_get_link_type (link)) { case NEMO_DESKTOP_LINK_HOME: case NEMO_DESKTOP_LINK_COMPUTER: case NEMO_DESKTOP_LINK_TRASH: case NEMO_DESKTOP_LINK_NETWORK: /* just ignore. We don't allow you to delete these */ break; case NEMO_DESKTOP_LINK_MOUNT: default: volume_delete_dialog (parent_view, link); break; } } static gboolean volume_file_name_used (NemoDesktopLinkMonitor *monitor, const char *name) { GList *l; char *other_name; gboolean same; for (l = monitor->details->mount_links; l != NULL; l = l->next) { other_name = nemo_desktop_link_get_file_name (l->data); same = strcmp (name, other_name) == 0; g_free (other_name); if (same) { return TRUE; } } return FALSE; } char * nemo_desktop_link_monitor_make_filename_unique (NemoDesktopLinkMonitor *monitor, const char *filename) { char *unique_name; int i; i = 2; unique_name = g_strdup (filename); while (volume_file_name_used (monitor, unique_name)) { g_free (unique_name); unique_name = g_strdup_printf ("%s.%d", filename, i++); } return unique_name; } static gboolean has_mount (NemoDesktopLinkMonitor *monitor, GMount *mount) { gboolean ret; GMount *other_mount; GList *l; ret = FALSE; for (l = monitor->details->mount_links; l != NULL; l = l->next) { other_mount = nemo_desktop_link_get_mount (l->data); if (mount == other_mount) { g_object_unref (other_mount); ret = TRUE; break; } g_object_unref (other_mount); } return ret; } static void create_mount_link (NemoDesktopLinkMonitor *monitor, GMount *mount) { NemoDesktopLink *link; if (has_mount (monitor, mount)) return; if ((!g_mount_is_shadowed (mount)) && g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) { link = nemo_desktop_link_new_from_mount (mount); monitor->details->mount_links = g_list_prepend (monitor->details->mount_links, link); } } static void remove_mount_link (NemoDesktopLinkMonitor *monitor, GMount *mount) { GList *l; NemoDesktopLink *link; GMount *other_mount; link = NULL; for (l = monitor->details->mount_links; l != NULL; l = l->next) { other_mount = nemo_desktop_link_get_mount (l->data); if (mount == other_mount) { g_object_unref (other_mount); link = l->data; break; } g_object_unref (other_mount); } if (link) { monitor->details->mount_links = g_list_remove (monitor->details->mount_links, link); g_object_unref (link); } } static void mount_added_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoDesktopLinkMonitor *monitor) { create_mount_link (monitor, mount); } static void mount_removed_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoDesktopLinkMonitor *monitor) { remove_mount_link (monitor, mount); } static void mount_changed_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoDesktopLinkMonitor *monitor) { /* TODO: update the mount with other details */ /* remove a mount if it goes into the shadows */ if (g_mount_is_shadowed (mount) && has_mount (monitor, mount)) { remove_mount_link (monitor, mount); }} static void update_link_visibility (NemoDesktopLinkMonitor *monitor, NemoDesktopLink **link_ref, NemoDesktopLinkType link_type, const char *preference_key) { if (g_settings_get_boolean (nemo_desktop_preferences, preference_key)) { if (*link_ref == NULL) { *link_ref = nemo_desktop_link_new (link_type); } } else { if (*link_ref != NULL) { /* If this were a real file, removing (deleting or moving) it would * also remove its metadata, though for a different reason, and * unmanaged by us. We have to simulate that when removing a fake * 'desktop' file, so if it gets added again later, it behaves like a * 'new' file. */ nemo_desktop_clear_metadata (nemo_desktop_link_get_file (*link_ref)); g_object_unref (*link_ref); *link_ref = NULL; } } } static void desktop_home_visible_changed (gpointer callback_data) { NemoDesktopLinkMonitor *monitor; monitor = NEMO_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (NEMO_DESKTOP_LINK_MONITOR (monitor), &monitor->details->home_link, NEMO_DESKTOP_LINK_HOME, NEMO_PREFERENCES_DESKTOP_HOME_VISIBLE); } static void desktop_computer_visible_changed (gpointer callback_data) { NemoDesktopLinkMonitor *monitor; monitor = NEMO_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (NEMO_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->computer_link, NEMO_DESKTOP_LINK_COMPUTER, NEMO_PREFERENCES_DESKTOP_COMPUTER_VISIBLE); } static void desktop_trash_visible_changed (gpointer callback_data) { NemoDesktopLinkMonitor *monitor; monitor = NEMO_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (NEMO_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->trash_link, NEMO_DESKTOP_LINK_TRASH, NEMO_PREFERENCES_DESKTOP_TRASH_VISIBLE); } static void desktop_network_visible_changed (gpointer callback_data) { NemoDesktopLinkMonitor *monitor; monitor = NEMO_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (NEMO_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->network_link, NEMO_DESKTOP_LINK_NETWORK, NEMO_PREFERENCES_DESKTOP_NETWORK_VISIBLE); } static void desktop_volumes_visible_changed (gpointer callback_data) { NemoDesktopLinkMonitor *monitor; GList *l, *mounts; monitor = NEMO_DESKTOP_LINK_MONITOR (callback_data); if (g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) { if (monitor->details->mount_links == NULL) { mounts = g_volume_monitor_get_mounts (monitor->details->volume_monitor); for (l = mounts; l != NULL; l = l->next) { create_mount_link (monitor, l->data); g_object_unref (l->data); } g_list_free (mounts); } } else { g_list_foreach (monitor->details->mount_links, (GFunc)g_object_unref, NULL); g_list_free (monitor->details->mount_links); monitor->details->mount_links = NULL; } } static void create_link_and_add_preference (NemoDesktopLink **link_ref, NemoDesktopLinkType link_type, const char *preference_key, GCallback callback, gpointer callback_data) { char *detailed_signal; if (g_settings_get_boolean (nemo_desktop_preferences, preference_key)) { *link_ref = nemo_desktop_link_new (link_type); } detailed_signal = g_strconcat ("changed::", preference_key, NULL); g_signal_connect_swapped (nemo_desktop_preferences, detailed_signal, callback, callback_data); g_free (detailed_signal); } static void nemo_desktop_link_monitor_init (NemoDesktopLinkMonitor *monitor) { GList *l, *mounts; GMount *mount; monitor->details = G_TYPE_INSTANCE_GET_PRIVATE (monitor, NEMO_TYPE_DESKTOP_LINK_MONITOR, NemoDesktopLinkMonitorDetails); the_link_monitor = monitor; monitor->details->volume_monitor = g_volume_monitor_get (); /* We keep around a ref to the desktop dir */ monitor->details->desktop_dir = nemo_directory_get_by_uri (EEL_DESKTOP_URI); /* Default links */ create_link_and_add_preference (&monitor->details->home_link, NEMO_DESKTOP_LINK_HOME, NEMO_PREFERENCES_DESKTOP_HOME_VISIBLE, G_CALLBACK (desktop_home_visible_changed), monitor); create_link_and_add_preference (&monitor->details->computer_link, NEMO_DESKTOP_LINK_COMPUTER, NEMO_PREFERENCES_DESKTOP_COMPUTER_VISIBLE, G_CALLBACK (desktop_computer_visible_changed), monitor); create_link_and_add_preference (&monitor->details->trash_link, NEMO_DESKTOP_LINK_TRASH, NEMO_PREFERENCES_DESKTOP_TRASH_VISIBLE, G_CALLBACK (desktop_trash_visible_changed), monitor); create_link_and_add_preference (&monitor->details->network_link, NEMO_DESKTOP_LINK_NETWORK, NEMO_PREFERENCES_DESKTOP_NETWORK_VISIBLE, G_CALLBACK (desktop_network_visible_changed), monitor); /* Mount links */ mounts = g_volume_monitor_get_mounts (monitor->details->volume_monitor); for (l = mounts; l != NULL; l = l->next) { mount = l->data; create_mount_link (monitor, mount); g_object_unref (mount); } g_list_free (mounts); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_VOLUMES_VISIBLE, G_CALLBACK (desktop_volumes_visible_changed), monitor); g_signal_connect_object (monitor->details->volume_monitor, "mount_added", G_CALLBACK (mount_added_callback), monitor, 0); g_signal_connect_object (monitor->details->volume_monitor, "mount_removed", G_CALLBACK (mount_removed_callback), monitor, 0); g_signal_connect_object (monitor->details->volume_monitor, "mount_changed", G_CALLBACK (mount_changed_callback), monitor, 0); } static void remove_link_and_preference (NemoDesktopLink **link_ref, const char *preference_key, GCallback callback, gpointer callback_data) { if (*link_ref != NULL) { g_object_unref (*link_ref); *link_ref = NULL; } g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, callback, callback_data); } static void desktop_link_monitor_finalize (GObject *object) { NemoDesktopLinkMonitor *monitor; monitor = NEMO_DESKTOP_LINK_MONITOR (object); g_object_unref (monitor->details->volume_monitor); /* Default links */ remove_link_and_preference (&monitor->details->home_link, NEMO_PREFERENCES_DESKTOP_HOME_VISIBLE, G_CALLBACK (desktop_home_visible_changed), monitor); remove_link_and_preference (&monitor->details->computer_link, NEMO_PREFERENCES_DESKTOP_COMPUTER_VISIBLE, G_CALLBACK (desktop_computer_visible_changed), monitor); remove_link_and_preference (&monitor->details->trash_link, NEMO_PREFERENCES_DESKTOP_TRASH_VISIBLE, G_CALLBACK (desktop_trash_visible_changed), monitor); remove_link_and_preference (&monitor->details->network_link, NEMO_PREFERENCES_DESKTOP_NETWORK_VISIBLE, G_CALLBACK (desktop_network_visible_changed), monitor); /* Mounts */ g_list_foreach (monitor->details->mount_links, (GFunc)g_object_unref, NULL); g_list_free (monitor->details->mount_links); monitor->details->mount_links = NULL; nemo_directory_unref (monitor->details->desktop_dir); monitor->details->desktop_dir = NULL; g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, desktop_volumes_visible_changed, monitor); G_OBJECT_CLASS (nemo_desktop_link_monitor_parent_class)->finalize (object); } static void nemo_desktop_link_monitor_class_init (NemoDesktopLinkMonitorClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = desktop_link_monitor_finalize; g_type_class_add_private (klass, sizeof (NemoDesktopLinkMonitorDetails)); } nemo-4.4.2/libnemo-private/nemo-desktop-link-monitor.h000066400000000000000000000050101357442400300227500ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-link-monitor.h: singleton that manages the desktop links Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_DESKTOP_LINK_MONITOR_H #define NEMO_DESKTOP_LINK_MONITOR_H #include #include #define NEMO_TYPE_DESKTOP_LINK_MONITOR nemo_desktop_link_monitor_get_type() #define NEMO_DESKTOP_LINK_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_LINK_MONITOR, NemoDesktopLinkMonitor)) #define NEMO_DESKTOP_LINK_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_LINK_MONITOR, NemoDesktopLinkMonitorClass)) #define NEMO_IS_DESKTOP_LINK_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_LINK_MONITOR)) #define NEMO_IS_DESKTOP_LINK_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_LINK_MONITOR)) #define NEMO_DESKTOP_LINK_MONITOR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_LINK_MONITOR, NemoDesktopLinkMonitorClass)) typedef struct NemoDesktopLinkMonitorDetails NemoDesktopLinkMonitorDetails; typedef struct { GObject parent_slot; NemoDesktopLinkMonitorDetails *details; } NemoDesktopLinkMonitor; typedef struct { GObjectClass parent_slot; } NemoDesktopLinkMonitorClass; GType nemo_desktop_link_monitor_get_type (void); NemoDesktopLinkMonitor * nemo_desktop_link_monitor_get (void); void nemo_desktop_link_monitor_delete_link (NemoDesktopLinkMonitor *monitor, NemoDesktopLink *link, GtkWidget *parent_view); /* Used by nemo-desktop-link.c */ char * nemo_desktop_link_monitor_make_filename_unique (NemoDesktopLinkMonitor *monitor, const char *filename); #endif /* NEMO_DESKTOP_LINK_MONITOR_H */ nemo-4.4.2/libnemo-private/nemo-desktop-link.c000066400000000000000000000217271357442400300212730ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-link.c: Class that handles the links on the desktop Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-desktop-link.h" #include "nemo-desktop-link-monitor.h" #include "nemo-desktop-icon-file.h" #include "nemo-directory-private.h" #include "nemo-desktop-directory.h" #include "nemo-icon-names.h" #include #include #include #include #include #include struct NemoDesktopLinkDetails { NemoDesktopLinkType type; char *filename; char *display_name; GFile *activation_location; GIcon *icon; NemoDesktopIconFile *icon_file; GObject *signal_handler_obj; gulong signal_handler; /* Just for mount icons: */ GMount *mount; }; G_DEFINE_TYPE(NemoDesktopLink, nemo_desktop_link, G_TYPE_OBJECT) static void create_icon_file (NemoDesktopLink *link) { link->details->icon_file = nemo_desktop_icon_file_new (link); } static void nemo_desktop_link_changed (NemoDesktopLink *link) { if (link->details->icon_file != NULL) { nemo_desktop_icon_file_update (link->details->icon_file); } } static void mount_changed_callback (GMount *mount, NemoDesktopLink *link) { g_free (link->details->display_name); if (link->details->activation_location) { g_object_unref (link->details->activation_location); } if (link->details->icon) { g_object_unref (link->details->icon); } link->details->display_name = g_mount_get_name (mount); link->details->activation_location = g_mount_get_default_location (mount); link->details->icon = g_mount_get_icon (mount); nemo_desktop_link_changed (link); } static void trash_state_changed_callback (NemoTrashMonitor *trash_monitor, gboolean state, gpointer callback_data) { NemoDesktopLink *link; link = NEMO_DESKTOP_LINK (callback_data); g_assert (link->details->type == NEMO_DESKTOP_LINK_TRASH); if (link->details->icon) { g_object_unref (link->details->icon); } link->details->icon = nemo_trash_monitor_get_icon (); nemo_desktop_link_changed (link); } NemoDesktopLink * nemo_desktop_link_new (NemoDesktopLinkType type) { NemoDesktopLink *link; link = NEMO_DESKTOP_LINK (g_object_new (NEMO_TYPE_DESKTOP_LINK, NULL)); link->details->type = type; switch (type) { case NEMO_DESKTOP_LINK_HOME: link->details->filename = g_strdup ("home"); link->details->display_name = g_strdup (_("Home")); link->details->activation_location = g_file_new_for_path (g_get_home_dir ()); link->details->icon = g_themed_icon_new (NEMO_ICON_HOME); break; case NEMO_DESKTOP_LINK_COMPUTER: link->details->filename = g_strdup ("computer"); link->details->display_name = g_strdup (_("Computer")); link->details->activation_location = g_file_new_for_uri ("computer:///"); /* TODO: This might need a different icon: */ link->details->icon = g_themed_icon_new (NEMO_ICON_COMPUTER); break; case NEMO_DESKTOP_LINK_TRASH: link->details->filename = g_strdup ("trash"); link->details->display_name = g_strdup (_("Trash")); link->details->activation_location = g_file_new_for_uri (EEL_TRASH_URI); link->details->icon = nemo_trash_monitor_get_icon (); link->details->signal_handler_obj = G_OBJECT (nemo_trash_monitor_get ()); link->details->signal_handler = g_signal_connect_object (nemo_trash_monitor_get (), "trash_state_changed", G_CALLBACK (trash_state_changed_callback), link, 0); break; case NEMO_DESKTOP_LINK_NETWORK: link->details->filename = g_strdup ("network"); link->details->display_name = g_strdup (_("Network")); link->details->activation_location = g_file_new_for_uri ("network:///"); link->details->icon = g_themed_icon_new (NEMO_ICON_NETWORK); break; default: case NEMO_DESKTOP_LINK_MOUNT: g_assert_not_reached(); } create_icon_file (link); return link; } NemoDesktopLink * nemo_desktop_link_new_from_mount (GMount *mount) { NemoDesktopLink *link; GVolume *volume; char *name, *filename; link = NEMO_DESKTOP_LINK (g_object_new (NEMO_TYPE_DESKTOP_LINK, NULL)); link->details->type = NEMO_DESKTOP_LINK_MOUNT; link->details->mount = g_object_ref (mount); /* We try to use the drive name to get somewhat stable filenames for metadata */ volume = g_mount_get_volume (mount); if (volume != NULL) { name = g_volume_get_name (volume); g_object_unref (volume); } else { name = g_mount_get_name (mount); } /* Replace slashes in name */ filename = g_strconcat (g_strdelimit (name, "/", '-'), ".volume", NULL); link->details->filename = nemo_desktop_link_monitor_make_filename_unique (nemo_desktop_link_monitor_get (), filename); g_free (filename); g_free (name); link->details->display_name = g_mount_get_name (mount); link->details->activation_location = g_mount_get_default_location (mount); link->details->icon = g_mount_get_icon (mount); link->details->signal_handler_obj = G_OBJECT (mount); link->details->signal_handler = g_signal_connect (mount, "changed", G_CALLBACK (mount_changed_callback), link); create_icon_file (link); return link; } GMount * nemo_desktop_link_get_mount (NemoDesktopLink *link) { if (link->details->mount) { return g_object_ref (link->details->mount); } return NULL; } NemoDesktopLinkType nemo_desktop_link_get_link_type (NemoDesktopLink *link) { return link->details->type; } NemoFile * nemo_desktop_link_get_file (NemoDesktopLink *link) { return NEMO_FILE (link->details->icon_file); } char * nemo_desktop_link_get_file_name (NemoDesktopLink *link) { return g_strdup (link->details->filename); } char * nemo_desktop_link_get_display_name (NemoDesktopLink *link) { return g_strdup (link->details->display_name); } GIcon * nemo_desktop_link_get_icon (NemoDesktopLink *link) { if (link->details->icon != NULL) { return g_object_ref (link->details->icon); } return NULL; } GFile * nemo_desktop_link_get_activation_location (NemoDesktopLink *link) { if (link->details->activation_location) { return g_object_ref (link->details->activation_location); } return NULL; } char * nemo_desktop_link_get_activation_uri (NemoDesktopLink *link) { if (link->details->activation_location) { return g_file_get_uri (link->details->activation_location); } return NULL; } gboolean nemo_desktop_link_get_date (NemoDesktopLink *link, NemoDateType date_type, time_t *date) { return FALSE; } gboolean nemo_desktop_link_can_rename (NemoDesktopLink *link) { return !(link->details->type == NEMO_DESKTOP_LINK_HOME || link->details->type == NEMO_DESKTOP_LINK_TRASH || link->details->type == NEMO_DESKTOP_LINK_NETWORK || link->details->type == NEMO_DESKTOP_LINK_COMPUTER || link->details->type == NEMO_DESKTOP_LINK_MOUNT); } gboolean nemo_desktop_link_rename (NemoDesktopLink *link, const char *name) { /* Do we want volume renaming? */ return TRUE; } static void nemo_desktop_link_init (NemoDesktopLink *link) { link->details = G_TYPE_INSTANCE_GET_PRIVATE (link, NEMO_TYPE_DESKTOP_LINK, NemoDesktopLinkDetails); } static void desktop_link_finalize (GObject *object) { NemoDesktopLink *link; link = NEMO_DESKTOP_LINK (object); if (link->details->signal_handler != 0) { g_signal_handler_disconnect (link->details->signal_handler_obj, link->details->signal_handler); } if (link->details->icon_file != NULL) { nemo_desktop_icon_file_remove (link->details->icon_file); nemo_file_unref (NEMO_FILE (link->details->icon_file)); link->details->icon_file = NULL; } if (link->details->type == NEMO_DESKTOP_LINK_MOUNT) { g_object_unref (link->details->mount); } g_free (link->details->filename); g_free (link->details->display_name); if (link->details->activation_location) { g_object_unref (link->details->activation_location); } if (link->details->icon) { g_object_unref (link->details->icon); } G_OBJECT_CLASS (nemo_desktop_link_parent_class)->finalize (object); } static void nemo_desktop_link_class_init (NemoDesktopLinkClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = desktop_link_finalize; g_type_class_add_private (object_class, sizeof(NemoDesktopLinkDetails)); } nemo-4.4.2/libnemo-private/nemo-desktop-link.h000066400000000000000000000067301357442400300212750ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-desktop-link.h: Class that handles the links on the desktop Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_DESKTOP_LINK_H #define NEMO_DESKTOP_LINK_H #include #include #define NEMO_TYPE_DESKTOP_LINK nemo_desktop_link_get_type() #define NEMO_DESKTOP_LINK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_LINK, NemoDesktopLink)) #define NEMO_DESKTOP_LINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_LINK, NemoDesktopLinkClass)) #define NEMO_IS_DESKTOP_LINK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_LINK)) #define NEMO_IS_DESKTOP_LINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_LINK)) #define NEMO_DESKTOP_LINK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_LINK, NemoDesktopLinkClass)) typedef struct NemoDesktopLinkDetails NemoDesktopLinkDetails; typedef struct { GObject parent_slot; NemoDesktopLinkDetails *details; } NemoDesktopLink; typedef struct { GObjectClass parent_slot; } NemoDesktopLinkClass; typedef enum { NEMO_DESKTOP_LINK_HOME, NEMO_DESKTOP_LINK_COMPUTER, NEMO_DESKTOP_LINK_TRASH, NEMO_DESKTOP_LINK_MOUNT, NEMO_DESKTOP_LINK_NETWORK } NemoDesktopLinkType; GType nemo_desktop_link_get_type (void); NemoDesktopLink * nemo_desktop_link_new (NemoDesktopLinkType type); NemoDesktopLink * nemo_desktop_link_new_from_mount (GMount *mount); NemoDesktopLinkType nemo_desktop_link_get_link_type (NemoDesktopLink *link); NemoFile * nemo_desktop_link_get_file (NemoDesktopLink *link); char * nemo_desktop_link_get_file_name (NemoDesktopLink *link); char * nemo_desktop_link_get_display_name (NemoDesktopLink *link); GIcon * nemo_desktop_link_get_icon (NemoDesktopLink *link); GFile * nemo_desktop_link_get_activation_location (NemoDesktopLink *link); char * nemo_desktop_link_get_activation_uri (NemoDesktopLink *link); gboolean nemo_desktop_link_get_date (NemoDesktopLink *link, NemoDateType date_type, time_t *date); GMount * nemo_desktop_link_get_mount (NemoDesktopLink *link); gboolean nemo_desktop_link_can_rename (NemoDesktopLink *link); gboolean nemo_desktop_link_rename (NemoDesktopLink *link, const char *name); #endif /* NEMO_DESKTOP_LINK_H */ nemo-4.4.2/libnemo-private/nemo-desktop-metadata.c000066400000000000000000000201331357442400300221040ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi */ #include #include "nemo-desktop-metadata.h" #include "nemo-directory-notify.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include #include #include #include static guint save_in_idle_source_id = 0; static gchar * get_keyfile_path (void) { gchar *xdg_dir, *retval; xdg_dir = nemo_get_user_directory (); retval = g_build_filename (xdg_dir, "desktop-metadata", NULL); g_free (xdg_dir); return retval; } static gboolean save_in_idle_cb (gpointer data) { GKeyFile *keyfile = data; gchar *contents, *filename; gsize length; GError *error = NULL; save_in_idle_source_id = 0; contents = g_key_file_to_data (keyfile, &length, NULL); filename = get_keyfile_path (); if (contents != NULL) { g_file_set_contents (filename, contents, length, &error); g_free (contents); } if (error != NULL) { g_warning ("Couldn't save the desktop metadata keyfile to disk: %s", error->message); g_error_free (error); } g_free (filename); return FALSE; } static void save_in_idle (GKeyFile *keyfile) { if (save_in_idle_source_id != 0) { g_source_remove (save_in_idle_source_id); } save_in_idle_source_id = g_idle_add (save_in_idle_cb, keyfile); } static GKeyFile * load_metadata_keyfile (void) { GKeyFile *retval; GError *error = NULL; gchar *filename; retval = g_key_file_new (); filename = get_keyfile_path (); g_key_file_load_from_file (retval, filename, G_KEY_FILE_NONE, &error); if (error != NULL) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { g_print ("Unable to open the desktop metadata keyfile: %s\n", error->message); } g_error_free (error); } g_free (filename); return retval; } static GKeyFile * get_keyfile (void) { static gboolean keyfile_loaded = FALSE; static GKeyFile *keyfile = NULL; if (!keyfile_loaded) { keyfile = load_metadata_keyfile (); keyfile_loaded = TRUE; } return keyfile; } void nemo_desktop_metadata_init (void) { get_keyfile (); } void nemo_desktop_set_metadata_string (NemoFile *file, const gchar *name, const gchar *key, const gchar *string) { GKeyFile *keyfile; keyfile = get_keyfile (); if (!string) { GError *error = NULL; g_key_file_remove_key (keyfile, name, key, &error); if (error != NULL) { if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) { g_warning ("Problem setting metadata for %s: %s", name, error->message); } g_error_free (error); } } else { g_key_file_set_string (keyfile, name, key, string); } save_in_idle (keyfile); if (nemo_desktop_update_metadata_from_keyfile (file, name)) { nemo_file_changed (file); } } #define STRV_TERMINATOR "@x-nemo-desktop-metadata-term@" void nemo_desktop_set_metadata_stringv (NemoFile *file, const char *name, const char *key, const char * const *stringv) { GKeyFile *keyfile; guint length; gchar **actual_stringv = NULL; gboolean free_strv = FALSE; keyfile = get_keyfile (); /* if we would be setting a single-length strv, append a fake * terminator to the array, to be able to differentiate it later from * the single string case */ length = g_strv_length ((gchar **) stringv); if (length == 1) { actual_stringv = g_malloc0 (3 * sizeof (gchar *)); actual_stringv[0] = (gchar *) stringv[0]; actual_stringv[1] = (gchar *)STRV_TERMINATOR; actual_stringv[2] = NULL; length = 2; free_strv = TRUE; } else { actual_stringv = (gchar **) stringv; } g_key_file_set_string_list (keyfile, name, key, (const gchar **) actual_stringv, length); save_in_idle (keyfile); if (nemo_desktop_update_metadata_from_keyfile (file, name)) { nemo_file_changed (file); } if (free_strv) { g_free (actual_stringv); } } void nemo_desktop_clear_metadata (NemoFile *file) { GKeyFile *keyfile; keyfile = get_keyfile (); if (g_key_file_remove_group (keyfile, file->details->name, NULL)) { save_in_idle (keyfile); } } gchar * nemo_desktop_get_metadata_string (NemoFile *file, const gchar *name, const gchar *key) { GKeyFile *keyfile; gchar *string; keyfile = get_keyfile (); string = g_key_file_get_string (keyfile, name, key, NULL); return string; } gchar ** nemo_desktop_get_metadata_stringv (NemoFile *file, const char *name, const char *key) { GKeyFile *keyfile; gsize length; gchar **stringv = NULL; keyfile = get_keyfile (); stringv = g_key_file_get_string_list (keyfile, name, key, &length, NULL); return stringv; } gboolean nemo_desktop_update_metadata_from_keyfile (NemoFile *file, const gchar *name) { gchar **keys, **values; const gchar *actual_values[2]; const gchar *key, *value; gchar *gio_key; gsize length, values_length; GKeyFile *keyfile; GFileInfo *info; guint idx; gboolean res; keyfile = get_keyfile (); keys = g_key_file_get_keys (keyfile, name, &length, NULL); if (keys == NULL) { return FALSE; } info = g_file_info_new (); for (idx = 0; idx < length; idx++) { key = keys[idx]; values = g_key_file_get_string_list (keyfile, name, key, &values_length, NULL); gio_key = g_strconcat ("metadata::", key, NULL); if (values_length < 1) { continue; } else if (values_length == 1) { g_file_info_set_attribute_string (info, gio_key, values[0]); } else if (values_length == 2) { /* deal with the fact that single-length strv are stored * with an additional terminator in the keyfile string, to differentiate * them from the regular string case. */ value = values[1]; if (g_strcmp0 (value, STRV_TERMINATOR) == 0) { /* if the 2nd value is the terminator, remove it */ actual_values[0] = values[0]; actual_values[1] = NULL; g_file_info_set_attribute_stringv (info, gio_key, (gchar **) actual_values); } else { /* otherwise, set it as a regular strv */ g_file_info_set_attribute_stringv (info, gio_key, values); } } else { g_file_info_set_attribute_stringv (info, gio_key, values); } g_free (gio_key); g_strfreev (values); } res = nemo_file_update_metadata_from_info (file, info); g_strfreev (keys); g_object_unref (info); return res; } nemo-4.4.2/libnemo-private/nemo-desktop-metadata.h000066400000000000000000000042111357442400300221100ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi */ #ifndef __NEMO_DESKTOP_METADATA_H__ #define __NEMO_DESKTOP_METADATA_H__ #include #include void nemo_desktop_metadata_init (void); void nemo_desktop_set_metadata_string (NemoFile *file, const gchar *name, const gchar *key, const gchar *string); void nemo_desktop_set_metadata_stringv (NemoFile *file, const char *name, const char *key, const char * const *stringv); void nemo_desktop_clear_metadata (NemoFile *file); gchar *nemo_desktop_get_metadata_string (NemoFile *file, const gchar *name, const gchar *key); gchar **nemo_desktop_get_metadata_stringv (NemoFile *file, const char *name, const char *key); gboolean nemo_desktop_update_metadata_from_keyfile (NemoFile *file, const gchar *name); #endif /* __NEMO_DESKTOP_METADATA_H__ */ nemo-4.4.2/libnemo-private/nemo-desktop-utils.c000066400000000000000000000107571357442400300214770ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * */ #include "nemo-desktop-utils.h" static GdkScreen *default_screen = NULL; static void ensure_screen (void) { if (!default_screen) default_screen = gdk_screen_get_default (); } #if GTK_CHECK_VERSION (3, 22, 0) static GdkDisplay *default_display = NULL; static void ensure_display (void) { if (!default_display) default_display = gdk_display_get_default (); } #endif void nemo_desktop_utils_get_monitor_work_rect (gint num, GdkRectangle *rect) { #if GTK_CHECK_VERSION (3, 22, 0) ensure_display (); g_return_if_fail (num >= 0 && num < gdk_display_get_n_monitors (default_display)); GdkMonitor *monitor = gdk_display_get_monitor (default_display, num); gdk_monitor_get_workarea (monitor, rect); #else ensure_screen (); g_return_if_fail (num >= 0 && num < gdk_screen_get_n_monitors (default_screen)); gdk_screen_get_monitor_workarea (default_screen, num, rect); #endif } void nemo_desktop_utils_get_monitor_geometry (gint num, GdkRectangle *rect) { #if GTK_CHECK_VERSION (3, 22, 0) ensure_display (); g_return_if_fail (num >= 0 && num < gdk_display_get_n_monitors (default_display)); GdkMonitor *monitor = gdk_display_get_monitor (default_display, num); gdk_monitor_get_geometry (monitor, rect); #else ensure_screen (); g_return_if_fail (num >= 0 && num < gdk_screen_get_n_monitors (default_screen)); gdk_screen_get_monitor_geometry (default_screen, num, rect); #endif } gint nemo_desktop_utils_get_primary_monitor (void) { #if GTK_CHECK_VERSION (3, 22, 0) gint n_mon, i; ensure_display (); n_mon = gdk_display_get_n_monitors (default_display); for (i = 0; i < n_mon; i ++) { GdkMonitor *monitor = gdk_display_get_monitor (default_display, i); if (gdk_monitor_is_primary (monitor)) { return i; } } return 0; #else ensure_screen (); return gdk_screen_get_primary_monitor (default_screen); #endif } gint nemo_desktop_utils_get_monitor_for_widget (GtkWidget *widget) { GdkWindow *window; GtkWidget *toplevel; gint monitor; g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); toplevel = gtk_widget_get_toplevel (widget); if (toplevel != NULL && g_object_get_data (G_OBJECT (toplevel), "is_desktop_window")) { monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toplevel), "monitor_number")); return monitor; } ensure_screen (); window = gtk_widget_get_window (widget); if (window == NULL) { return 0; } monitor = gdk_screen_get_monitor_at_window (default_screen, window); return monitor; } gint nemo_desktop_utils_get_num_monitors (void) { ensure_screen (); return gdk_screen_get_n_monitors (default_screen); } gboolean nemo_desktop_utils_get_monitor_cloned (gint monitor, gint x_primary) { GdkRectangle rect_primary; GdkRectangle rect_test; gint n_monitors; ensure_screen (); n_monitors = gdk_screen_get_n_monitors (default_screen); g_return_val_if_fail (monitor >= 0 && monitor < n_monitors, FALSE); g_return_val_if_fail (x_primary >= 0 && x_primary < n_monitors, FALSE); gdk_screen_get_monitor_geometry(default_screen, x_primary, &rect_primary); gdk_screen_get_monitor_geometry(default_screen, monitor, &rect_test); if (rect_primary.x == rect_test.x && rect_primary.y == rect_test.y) { return TRUE; } return FALSE; } gint nemo_desktop_utils_get_scale_factor (void) { guint scale; GValue value = G_VALUE_INIT; ensure_screen (); g_value_init (&value, G_TYPE_UINT); if (gdk_screen_get_setting (default_screen, "gdk-window-scaling-factor", &value)) { scale = g_value_get_uint (&value); } else { scale = 1; } return (gint) scale; } nemo-4.4.2/libnemo-private/nemo-desktop-utils.h000066400000000000000000000025451357442400300215000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * */ #ifndef NEMO_DESKTOP_UTILS_H #define NEMO_DESKTOP_UTILS_H #include #include G_BEGIN_DECLS void nemo_desktop_utils_get_monitor_work_rect (gint num, GdkRectangle *rect); void nemo_desktop_utils_get_monitor_geometry (gint num, GdkRectangle *rect); gint nemo_desktop_utils_get_primary_monitor (void); gint nemo_desktop_utils_get_monitor_for_widget (GtkWidget *widget); gint nemo_desktop_utils_get_num_monitors (void); gboolean nemo_desktop_utils_get_monitor_cloned (gint monitor, gint x_primary); gint nemo_desktop_utils_get_scale_factor (void); G_END_DECLS #endif nemo-4.4.2/libnemo-private/nemo-directory-async.c000066400000000000000000003553531357442400300220130ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-directory-async.c: Nemo directory model state machine. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include "nemo-signaller.h" #include "nemo-global-preferences.h" #include "nemo-link.h" #include #include #include #include #include /* turn this on to see messages about each load_directory call: */ #if 0 #define DEBUG_LOAD_DIRECTORY #endif /* turn this on to check if async. job calls are balanced */ #if 0 #define DEBUG_ASYNC_JOBS #endif /* turn this on to log things starting and stopping */ #if 0 #define DEBUG_START_STOP #endif #define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100 /* Keep async. jobs down to this number for all directories. */ #define MAX_ASYNC_JOBS 10 struct LinkInfoReadState { NemoDirectory *directory; GCancellable *cancellable; NemoFile *file; }; struct ThumbnailState { NemoDirectory *directory; GCancellable *cancellable; NemoFile *file; gboolean trying_original; gboolean tried_original; }; struct MountState { NemoDirectory *directory; GCancellable *cancellable; NemoFile *file; }; struct FilesystemInfoState { NemoDirectory *directory; GCancellable *cancellable; NemoFile *file; }; struct DirectoryLoadState { NemoDirectory *directory; GCancellable *cancellable; GFileEnumerator *enumerator; GHashTable *load_mime_list_hash; NemoFile *load_directory_file; int load_file_count; }; struct MimeListState { NemoDirectory *directory; NemoFile *mime_list_file; GCancellable *cancellable; GFileEnumerator *enumerator; GHashTable *mime_list_hash; }; struct GetInfoState { NemoDirectory *directory; GCancellable *cancellable; }; struct GetBTimeState { NemoDirectory *directory; GCancellable *cancellable; }; struct NewFilesState { NemoDirectory *directory; GCancellable *cancellable; int count; }; struct DirectoryCountState { NemoDirectory *directory; NemoFile *count_file; GCancellable *cancellable; GFileEnumerator *enumerator; int file_count; }; struct DeepCountState { NemoDirectory *directory; GCancellable *cancellable; GFileEnumerator *enumerator; GFile *deep_count_location; GList *deep_count_subdirectories; GArray *seen_deep_count_inodes; char *fs_id; }; typedef struct { NemoFile *file; /* Which file, NULL means all. */ union { NemoDirectoryCallback directory; NemoFileCallback file; } callback; gpointer callback_data; Request request; gboolean active; /* Set to FALSE when the callback is triggered and * scheduled to be called at idle, its still kept * in the list so we can kill it when the file * goes away. */ } ReadyCallback; typedef struct { NemoFile *file; /* Which file, NULL means all. */ gboolean monitor_hidden_files; /* defines whether "all" includes hidden files */ gconstpointer client; Request request; } Monitor; typedef struct { NemoDirectory *directory; NemoInfoProvider *provider; NemoOperationHandle *handle; NemoOperationResult result; } InfoProviderResponse; typedef gboolean (* RequestCheck) (Request); typedef gboolean (* FileCheck) (NemoFile *); /* Current number of async. jobs. */ static int async_job_count; static GHashTable *waiting_directories; #ifdef DEBUG_ASYNC_JOBS static GHashTable *async_jobs; #endif /* Hide kde trashcan directory */ static char *kde_trash_dir_name = NULL; /* Forward declarations for functions that need them. */ static void deep_count_load (DeepCountState *state, GFile *location); static gboolean request_is_satisfied (NemoDirectory *directory, NemoFile *file, Request request); static void cancel_loading_attributes (NemoDirectory *directory, NemoFileAttributes file_attributes); static void add_all_files_to_work_queue (NemoDirectory *directory); static void link_info_done (NemoDirectory *directory, NemoFile *file, const char *uri, const char *name, GIcon *icon, gboolean is_launcher, gboolean is_foreign); static void move_file_to_low_priority_queue (NemoDirectory *directory, NemoFile *file); static void move_file_to_extension_queue (NemoDirectory *directory, NemoFile *file); static void nemo_directory_invalidate_file_attributes (NemoDirectory *directory, NemoFileAttributes file_attributes); void nemo_set_kde_trash_name (const char *trash_dir) { g_free (kde_trash_dir_name); kde_trash_dir_name = g_strdup (trash_dir); } /* Some helpers for case-insensitive strings. * Move to nemo-glib-extensions? */ static gboolean istr_equal (gconstpointer v, gconstpointer v2) { return g_ascii_strcasecmp (v, v2) == 0; } static guint istr_hash (gconstpointer key) { const char *p; guint h; h = 0; for (p = key; *p != '\0'; p++) { h = (h << 5) - h + g_ascii_tolower (*p); } return h; } static GHashTable * istr_set_new (void) { return g_hash_table_new_full (istr_hash, istr_equal, g_free, NULL); } static void istr_set_insert (GHashTable *table, const char *istr) { char *key; key = g_strdup (istr); g_hash_table_replace (table, key, key); } static void add_istr_to_list (gpointer key, gpointer value, gpointer callback_data) { GList **list; list = callback_data; *list = g_list_prepend (*list, g_strdup (key)); } static GList * istr_set_get_as_list (GHashTable *table) { GList *list; list = NULL; g_hash_table_foreach (table, add_istr_to_list, &list); return list; } static void istr_set_destroy (GHashTable *table) { g_hash_table_destroy (table); } static void request_counter_add_request (RequestCounter counter, Request request) { guint i; for (i = 0; i < REQUEST_TYPE_LAST; i++) { if (REQUEST_WANTS_TYPE (request, i)) { counter[i]++; } } } static void request_counter_remove_request (RequestCounter counter, Request request) { guint i; for (i = 0; i < REQUEST_TYPE_LAST; i++) { if (REQUEST_WANTS_TYPE (request, i)) { counter[i]--; } } } #if 0 static void nemo_directory_verify_request_counts (NemoDirectory *directory) { GList *l; RequestCounter counters; int i; gboolean fail; fail = FALSE; for (i = 0; i < REQUEST_TYPE_LAST; i ++) { counters[i] = 0; } for (l = directory->details->monitor_list; l != NULL; l = l->next) { Monitor *monitor = l->data; request_counter_add_request (counters, monitor->request); } for (i = 0; i < REQUEST_TYPE_LAST; i ++) { if (counters[i] != directory->details->monitor_counters[i]) { g_warning ("monitor counter for %i is wrong, expecting %d but found %d", i, counters[i], directory->details->monitor_counters[i]); fail = TRUE; } } for (i = 0; i < REQUEST_TYPE_LAST; i ++) { counters[i] = 0; } for (l = directory->details->call_when_ready_list; l != NULL; l = l->next) { ReadyCallback *callback = l->data; request_counter_add_request (counters, callback->request); } for (i = 0; i < REQUEST_TYPE_LAST; i ++) { if (counters[i] != directory->details->call_when_ready_counters[i]) { g_warning ("call when ready counter for %i is wrong, expecting %d but found %d", i, counters[i], directory->details->call_when_ready_counters[i]); fail = TRUE; } } g_assert (!fail); } #endif /* Start a job. This is really just a way of limiting the number of * async. requests that we issue at any given time. Without this, the * number of requests is unbounded. */ static gboolean async_job_start (NemoDirectory *directory, const char *job) { #ifdef DEBUG_ASYNC_JOBS char *key; #endif #ifdef DEBUG_START_STOP g_message ("starting %s in %p", job, directory->details->location); #endif g_assert (async_job_count >= 0); g_assert (async_job_count <= MAX_ASYNC_JOBS); if (async_job_count >= MAX_ASYNC_JOBS) { if (waiting_directories == NULL) { waiting_directories = g_hash_table_new (NULL, NULL); } g_hash_table_insert (waiting_directories, directory, directory); return FALSE; } #ifdef DEBUG_ASYNC_JOBS { char *uri; if (async_jobs == NULL) { async_jobs = g_hash_table_new (g_str_hash, g_str_equal); } uri = nemo_directory_get_uri (directory); key = g_strconcat (uri, ": ", job, NULL); if (g_hash_table_lookup (async_jobs, key) != NULL) { g_warning ("same job twice: %s in %s", job, uri); } g_free (uri); g_hash_table_insert (async_jobs, key, directory); } #endif async_job_count += 1; return TRUE; } /* End a job. */ static void async_job_end (NemoDirectory *directory, const char *job) { #ifdef DEBUG_ASYNC_JOBS char *key; gpointer table_key, value; #endif #ifdef DEBUG_START_STOP g_message ("stopping %s in %p", job, directory->details->location); #endif g_assert (async_job_count > 0); #ifdef DEBUG_ASYNC_JOBS { char *uri; uri = nemo_directory_get_uri (directory); g_assert (async_jobs != NULL); key = g_strconcat (uri, ": ", job, NULL); if (!g_hash_table_lookup_extended (async_jobs, key, &table_key, &value)) { g_warning ("ending job we didn't start: %s in %s", job, uri); } else { g_hash_table_remove (async_jobs, key); g_free (table_key); } g_free (uri); g_free (key); } #endif async_job_count -= 1; } /* Helper to get one value from a hash table. */ static void get_one_value_callback (gpointer key, gpointer value, gpointer callback_data) { gpointer *returned_value; returned_value = callback_data; *returned_value = value; } /* return a single value from a hash table. */ static gpointer get_one_value (GHashTable *table) { gpointer value; value = NULL; if (table != NULL) { g_hash_table_foreach (table, get_one_value_callback, &value); } return value; } /* Wake up directories that are "blocked" as long as there are job * slots available. */ static void async_job_wake_up (void) { static gboolean already_waking_up = FALSE; gpointer value; g_assert (async_job_count >= 0); g_assert (async_job_count <= MAX_ASYNC_JOBS); if (already_waking_up) { return; } already_waking_up = TRUE; while (async_job_count < MAX_ASYNC_JOBS) { value = get_one_value (waiting_directories); if (value == NULL) { break; } g_hash_table_remove (waiting_directories, value); nemo_directory_async_state_changed (NEMO_DIRECTORY (value)); } already_waking_up = FALSE; } static void directory_count_cancel (NemoDirectory *directory) { if (directory->details->count_in_progress != NULL) { g_cancellable_cancel (directory->details->count_in_progress->cancellable); } } static void deep_count_cancel (NemoDirectory *directory) { if (directory->details->deep_count_in_progress != NULL) { g_assert (NEMO_IS_FILE (directory->details->deep_count_file)); g_cancellable_cancel (directory->details->deep_count_in_progress->cancellable); directory->details->deep_count_file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED; directory->details->deep_count_in_progress->directory = NULL; directory->details->deep_count_in_progress = NULL; directory->details->deep_count_file = NULL; async_job_end (directory, "deep count"); } } static void mime_list_cancel (NemoDirectory *directory) { if (directory->details->mime_list_in_progress != NULL) { g_cancellable_cancel (directory->details->mime_list_in_progress->cancellable); } } static void link_info_cancel (NemoDirectory *directory) { if (directory->details->link_info_read_state != NULL) { g_cancellable_cancel (directory->details->link_info_read_state->cancellable); directory->details->link_info_read_state->directory = NULL; directory->details->link_info_read_state = NULL; async_job_end (directory, "link info"); } } static void thumbnail_cancel (NemoDirectory *directory) { if (directory->details->thumbnail_state != NULL) { g_cancellable_cancel (directory->details->thumbnail_state->cancellable); directory->details->thumbnail_state->directory = NULL; directory->details->thumbnail_state = NULL; async_job_end (directory, "thumbnail"); } } static void mount_cancel (NemoDirectory *directory) { if (directory->details->mount_state != NULL) { g_cancellable_cancel (directory->details->mount_state->cancellable); directory->details->mount_state->directory = NULL; directory->details->mount_state = NULL; async_job_end (directory, "mount"); } } static void file_info_cancel (NemoDirectory *directory) { if (directory->details->get_info_in_progress != NULL) { g_cancellable_cancel (directory->details->get_info_in_progress->cancellable); directory->details->get_info_in_progress->directory = NULL; directory->details->get_info_in_progress = NULL; directory->details->get_info_file = NULL; async_job_end (directory, "file info"); } } static void btime_cancel (NemoDirectory *directory) { if (directory->details->get_btime_in_progress != NULL) { g_cancellable_cancel (directory->details->get_btime_in_progress->cancellable); directory->details->get_btime_in_progress->directory = NULL; directory->details->get_btime_in_progress = NULL; directory->details->get_btime_file = NULL; async_job_end (directory, "get btime"); } } static void new_files_cancel (NemoDirectory *directory) { GList *l; NewFilesState *state; if (directory->details->new_files_in_progress != NULL) { for (l = directory->details->new_files_in_progress; l != NULL; l = l->next) { state = l->data; g_cancellable_cancel (state->cancellable); state->directory = NULL; } g_list_free (directory->details->new_files_in_progress); directory->details->new_files_in_progress = NULL; } if (directory->details->new_files_in_progress_changes != NULL) { g_list_free_full (directory->details->new_files_in_progress_changes, (GDestroyNotify) g_object_unref); directory->details->new_files_in_progress_changes = NULL; } } static int monitor_key_compare (gconstpointer a, gconstpointer data) { const Monitor *monitor; const Monitor *compare_monitor; monitor = a; compare_monitor = data; if (monitor->client < compare_monitor->client) { return -1; } if (monitor->client > compare_monitor->client) { return +1; } if (monitor->file < compare_monitor->file) { return -1; } if (monitor->file > compare_monitor->file) { return +1; } return 0; } static GList * find_monitor (NemoDirectory *directory, NemoFile *file, gconstpointer client) { Monitor monitor; monitor.client = client; monitor.file = file; return g_list_find_custom (directory->details->monitor_list, &monitor, monitor_key_compare); } static void remove_monitor_link (NemoDirectory *directory, GList *link) { Monitor *monitor; if (link != NULL) { monitor = link->data; request_counter_remove_request (directory->details->monitor_counters, monitor->request); directory->details->monitor_list = g_list_remove_link (directory->details->monitor_list, link); g_free (monitor); g_list_free_1 (link); } } static void remove_monitor (NemoDirectory *directory, NemoFile *file, gconstpointer client) { remove_monitor_link (directory, find_monitor (directory, file, client)); } Request nemo_directory_set_up_request (NemoFileAttributes file_attributes) { Request request; request = 0; if ((file_attributes & NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT) != 0) { REQUEST_SET_TYPE (request, REQUEST_DIRECTORY_COUNT); } if ((file_attributes & NEMO_FILE_ATTRIBUTE_DEEP_COUNTS) != 0) { REQUEST_SET_TYPE (request, REQUEST_DEEP_COUNT); } if ((file_attributes & NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES) != 0) { REQUEST_SET_TYPE (request, REQUEST_MIME_LIST); } if ((file_attributes & NEMO_FILE_ATTRIBUTE_INFO) != 0) { REQUEST_SET_TYPE (request, REQUEST_FILE_INFO); } if ((file_attributes & NEMO_FILE_ATTRIBUTE_BTIME) != 0) { REQUEST_SET_TYPE (request, REQUEST_BTIME); } if (file_attributes & NEMO_FILE_ATTRIBUTE_LINK_INFO) { REQUEST_SET_TYPE (request, REQUEST_FILE_INFO); REQUEST_SET_TYPE (request, REQUEST_LINK_INFO); } if ((file_attributes & NEMO_FILE_ATTRIBUTE_EXTENSION_INFO) != 0) { REQUEST_SET_TYPE (request, REQUEST_EXTENSION_INFO); } if (file_attributes & NEMO_FILE_ATTRIBUTE_THUMBNAIL) { REQUEST_SET_TYPE (request, REQUEST_THUMBNAIL); REQUEST_SET_TYPE (request, REQUEST_FILE_INFO); } if (file_attributes & NEMO_FILE_ATTRIBUTE_MOUNT) { REQUEST_SET_TYPE (request, REQUEST_MOUNT); REQUEST_SET_TYPE (request, REQUEST_FILE_INFO); } if (file_attributes & NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO) { REQUEST_SET_TYPE (request, REQUEST_FILESYSTEM_INFO); } return request; } static void mime_db_changed_callback (GObject *ignore, NemoDirectory *dir) { NemoFileAttributes attrs; g_assert (dir != NULL); g_assert (dir->details != NULL); attrs = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES; nemo_directory_force_reload_internal (dir, attrs); } void nemo_directory_monitor_add_internal (NemoDirectory *directory, NemoFile *file, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { Monitor *monitor; GList *file_list; g_assert (NEMO_IS_DIRECTORY (directory)); /* Replace any current monitor for this client/file pair. */ remove_monitor (directory, file, client); /* Add the new monitor. */ monitor = g_new (Monitor, 1); monitor->file = file; monitor->monitor_hidden_files = monitor_hidden_files; monitor->client = client; monitor->request = nemo_directory_set_up_request (file_attributes); if (file == NULL) { REQUEST_SET_TYPE (monitor->request, REQUEST_FILE_LIST); } directory->details->monitor_list = g_list_prepend (directory->details->monitor_list, monitor); request_counter_add_request (directory->details->monitor_counters, monitor->request); if (callback != NULL) { file_list = nemo_directory_get_file_list (directory); (* callback) (directory, file_list, callback_data); nemo_file_list_free (file_list); } /* Start the "real" monitoring (FAM or whatever). */ /* We always monitor the whole directory since in practice * nemo almost always shows the whole directory anyway, and * it allows us to avoid one file monitor per file in a directory. */ if (directory->details->monitor == NULL) { directory->details->monitor = nemo_monitor_directory (directory->details->location); } if (REQUEST_WANTS_TYPE (monitor->request, REQUEST_FILE_INFO) && directory->details->mime_db_monitor == 0) { directory->details->mime_db_monitor = g_signal_connect_object (nemo_signaller_get_current (), "mime_data_changed", G_CALLBACK (mime_db_changed_callback), directory, 0); } /* Put the monitor file or all the files on the work queue. */ if (file != NULL) { nemo_directory_add_file_to_work_queue (directory, file); } else { add_all_files_to_work_queue (directory); } /* Kick off I/O. */ nemo_directory_async_state_changed (directory); } static void set_file_unconfirmed (NemoFile *file, gboolean unconfirmed) { NemoDirectory *directory; g_assert (NEMO_IS_FILE (file)); g_assert (unconfirmed == FALSE || unconfirmed == TRUE); if (file->details->unconfirmed == unconfirmed) { return; } file->details->unconfirmed = unconfirmed; directory = file->details->directory; if (unconfirmed) { directory->details->confirmed_file_count--; } else { directory->details->confirmed_file_count++; } } static gboolean show_hidden_files = TRUE; static void show_hidden_files_changed_callback (gpointer callback_data) { show_hidden_files = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES); } static gboolean should_skip_file (NemoDirectory *directory, GFileInfo *info) { static gboolean show_hidden_files_changed_callback_installed = FALSE; /* Add the callback once for the life of our process */ if (!show_hidden_files_changed_callback_installed) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_HIDDEN_FILES, G_CALLBACK(show_hidden_files_changed_callback), NULL); show_hidden_files_changed_callback_installed = TRUE; /* Peek for the first time */ show_hidden_files_changed_callback (NULL); } if (!show_hidden_files && (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info) || (directory != NULL && directory->details->hidden_file_hash != NULL && g_hash_table_lookup (directory->details->hidden_file_hash, g_file_info_get_name (info)) != NULL))) { return TRUE; } return FALSE; } static void process_files_changed_while_being_added (NemoDirectory *directory) { if (directory->details->new_files_in_progress_changes == NULL) { return; } directory->details->new_files_in_progress_changes = g_list_reverse (directory->details->new_files_in_progress_changes); nemo_directory_notify_files_changed (directory->details->new_files_in_progress_changes); g_list_free_full (directory->details->new_files_in_progress_changes, (GDestroyNotify) g_object_unref); directory->details->new_files_in_progress_changes = NULL; } static gboolean dequeue_pending_idle_callback (gpointer callback_data) { NemoDirectory *directory; GList *pending_file_info; GList *node, *next; NemoFile *file; GList *changed_files, *added_files; GFileInfo *file_info; const char *mimetype, *name; DirectoryLoadState *dir_load_state; directory = NEMO_DIRECTORY (callback_data); nemo_directory_ref (directory); directory->details->dequeue_pending_idle_id = 0; /* Handle the files in the order we saw them. */ pending_file_info = g_list_reverse (directory->details->pending_file_info); directory->details->pending_file_info = NULL; /* If we are no longer monitoring, then throw away these. */ if (!nemo_directory_is_file_list_monitored (directory)) { nemo_directory_async_state_changed (directory); goto drain; } added_files = NULL; changed_files = NULL; dir_load_state = directory->details->directory_load_in_progress; /* Build a list of NemoFile objects. */ for (node = pending_file_info; node != NULL; node = node->next) { file_info = node->data; name = g_file_info_get_name (file_info); /* Update the file count. */ /* FIXME bugzilla.gnome.org 45063: This could count a * file twice if we get it from both load_directory * and from new_files_callback. Not too hard to fix by * moving this into the actual callback instead of * waiting for the idle function. */ if (dir_load_state && !should_skip_file (directory, file_info)) { dir_load_state->load_file_count += 1; /* Add the MIME type to the set. */ mimetype = g_file_info_get_content_type (file_info); if (mimetype != NULL) { istr_set_insert (dir_load_state->load_mime_list_hash, mimetype); } } /* check if the file already exists */ file = nemo_directory_find_file_by_name (directory, name); if (file != NULL) { /* file already exists in dir, check if we still need to * emit file_added or if it changed */ set_file_unconfirmed (file, FALSE); if (!file->details->is_added) { /* We consider this newly added even if its in the list. * This can happen if someone called nemo_file_get_by_uri() * on a file in the folder before the add signal was * emitted */ nemo_file_ref (file); file->details->is_added = TRUE; added_files = g_list_prepend (added_files, file); } else if (nemo_file_update_info (file, file_info)) { /* File changed, notify about the change. */ nemo_file_ref (file); changed_files = g_list_prepend (changed_files, file); } } else { /* new file, create a nemo file object and add it to the list */ file = nemo_file_new_from_info (directory, file_info); nemo_directory_add_file (directory, file); file->details->is_added = TRUE; added_files = g_list_prepend (added_files, file); } } /* If we are done loading, then we assume that any unconfirmed * files are gone. */ if (directory->details->directory_loaded) { for (node = directory->details->file_list; node != NULL; node = next) { file = NEMO_FILE (node->data); next = node->next; if (file->details->unconfirmed) { nemo_file_ref (file); changed_files = g_list_prepend (changed_files, file); nemo_file_mark_gone (file); } } } /* Send the changed and added signals. */ nemo_directory_emit_change_signals (directory, changed_files); nemo_file_list_free (changed_files); nemo_directory_emit_files_added (directory, added_files); nemo_file_list_free (added_files); if (directory->details->directory_loaded && !directory->details->directory_loaded_sent_notification) { /* Send the done_loading signal. */ nemo_directory_emit_done_loading (directory); if (dir_load_state) { file = dir_load_state->load_directory_file; file->details->directory_count = dir_load_state->load_file_count; file->details->directory_count_is_up_to_date = TRUE; file->details->got_directory_count = TRUE; file->details->got_mime_list = TRUE; file->details->mime_list_is_up_to_date = TRUE; g_list_free_full (file->details->mime_list, g_free); file->details->mime_list = istr_set_get_as_list (dir_load_state->load_mime_list_hash); nemo_file_changed (file); } nemo_directory_async_state_changed (directory); directory->details->directory_loaded_sent_notification = TRUE; } /* Process changes received for files while they were still * being added. See Bug 703179 for a situation this happens. */ process_files_changed_while_being_added (directory); drain: g_list_free_full (pending_file_info, g_object_unref); /* Get the state machine running again. */ nemo_directory_async_state_changed (directory); nemo_directory_unref (directory); return FALSE; } void nemo_directory_schedule_dequeue_pending (NemoDirectory *directory) { if (directory->details->dequeue_pending_idle_id == 0) { directory->details->dequeue_pending_idle_id = g_idle_add (dequeue_pending_idle_callback, directory); } } static void directory_load_one (NemoDirectory *directory, GFileInfo *info) { if (info == NULL) { return; } if (g_file_info_get_name (info) == NULL) { char *uri; uri = nemo_directory_get_uri (directory); g_warning ("Got GFileInfo with NULL name in %s, ignoring. This shouldn't happen unless the gvfs backend is broken.\n", uri); g_free (uri); return; } /* Arrange for the "loading" part of the work. */ g_object_ref (info); directory->details->pending_file_info = g_list_prepend (directory->details->pending_file_info, info); nemo_directory_schedule_dequeue_pending (directory); } static void directory_load_cancel (NemoDirectory *directory) { NemoFile *file; DirectoryLoadState *state; state = directory->details->directory_load_in_progress; if (state != NULL) { file = state->load_directory_file; file->details->loading_directory = FALSE; if (file->details->directory != directory) { nemo_directory_async_state_changed (file->details->directory); } g_cancellable_cancel (state->cancellable); state->directory = NULL; directory->details->directory_load_in_progress = NULL; async_job_end (directory, "file list"); } } static void file_list_cancel (NemoDirectory *directory) { directory_load_cancel (directory); if (directory->details->dequeue_pending_idle_id != 0) { g_source_remove (directory->details->dequeue_pending_idle_id); directory->details->dequeue_pending_idle_id = 0; } if (directory->details->pending_file_info != NULL) { g_list_free_full (directory->details->pending_file_info, g_object_unref); directory->details->pending_file_info = NULL; } if (directory->details->hidden_file_hash) { g_hash_table_remove_all (directory->details->hidden_file_hash); } } static void directory_load_done (NemoDirectory *directory, GError *error) { GList *node; directory->details->directory_loaded = TRUE; directory->details->directory_loaded_sent_notification = FALSE; if (error != NULL) { /* The load did not complete successfully. This means * we don't know the status of the files in this directory. * We clear the unconfirmed bit on each file here so that * they won't be marked "gone" later -- we don't know enough * about them to know whether they are really gone. */ for (node = directory->details->file_list; node != NULL; node = node->next) { set_file_unconfirmed (NEMO_FILE (node->data), FALSE); } nemo_directory_emit_load_error (directory, error); } /* Call the idle function right away. */ if (directory->details->dequeue_pending_idle_id != 0) { g_source_remove (directory->details->dequeue_pending_idle_id); } dequeue_pending_idle_callback (directory); directory_load_cancel (directory); } void nemo_directory_monitor_remove_internal (NemoDirectory *directory, NemoFile *file, gconstpointer client) { g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (file == NULL || NEMO_IS_FILE (file)); g_assert (client != NULL); remove_monitor (directory, file, client); if (directory->details->monitor != NULL && directory->details->monitor_list == NULL) { nemo_monitor_cancel (directory->details->monitor); directory->details->monitor = NULL; } /* XXX - do we need to remove anything from the work queue? */ nemo_directory_async_state_changed (directory); } FileMonitors * nemo_directory_remove_file_monitors (NemoDirectory *directory, NemoFile *file) { GList *result, **list, *node, *next; Monitor *monitor; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); result = NULL; list = &directory->details->monitor_list; for (node = directory->details->monitor_list; node != NULL; node = next) { next = node->next; monitor = node->data; if (monitor->file == file) { *list = g_list_remove_link (*list, node); result = g_list_concat (node, result); request_counter_remove_request (directory->details->monitor_counters, monitor->request); } } /* XXX - do we need to remove anything from the work queue? */ nemo_directory_async_state_changed (directory); return (FileMonitors *) result; } void nemo_directory_add_file_monitors (NemoDirectory *directory, NemoFile *file, FileMonitors *monitors) { GList **list; GList *l; Monitor *monitor; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (monitors == NULL) { return; } for (l = (GList *)monitors; l != NULL; l = l->next) { monitor = l->data; request_counter_add_request (directory->details->monitor_counters, monitor->request); } list = &directory->details->monitor_list; *list = g_list_concat (*list, (GList *) monitors); nemo_directory_add_file_to_work_queue (directory, file); nemo_directory_async_state_changed (directory); } static int ready_callback_key_compare (gconstpointer a, gconstpointer b) { const ReadyCallback *callback_a, *callback_b; callback_a = a; callback_b = b; if (callback_a->file < callback_b->file) { return -1; } if (callback_a->file > callback_b->file) { return 1; } if (callback_a->file == NULL) { /* ANSI C doesn't allow ordered compares of function pointers, so we cast them to * normal pointers to make some overly pedantic compilers (*cough* HP-UX *cough*) * compile this. Of course, on any compiler where ordered function pointers actually * break this probably won't work, but at least it will compile on platforms where it * works, but stupid compilers won't let you use it. */ if ((void *)callback_a->callback.directory < (void *)callback_b->callback.directory) { return -1; } if ((void *)callback_a->callback.directory > (void *)callback_b->callback.directory) { return 1; } } else { if ((void *)callback_a->callback.file < (void *)callback_b->callback.file) { return -1; } if ((void *)callback_a->callback.file > (void *)callback_b->callback.file) { return 1; } } if (callback_a->callback_data < callback_b->callback_data) { return -1; } if (callback_a->callback_data > callback_b->callback_data) { return 1; } return 0; } static int ready_callback_key_compare_only_active (gconstpointer a, gconstpointer b) { const ReadyCallback *callback_a; callback_a = a; /* Non active callbacks never match */ if (!callback_a->active) { return -1; } return ready_callback_key_compare (a, b); } static void ready_callback_call (NemoDirectory *directory, const ReadyCallback *callback) { GList *file_list; /* Call the callback. */ if (callback->file != NULL) { if (callback->callback.file) { (* callback->callback.file) (callback->file, callback->callback_data); } } else if (callback->callback.directory != NULL) { if (directory == NULL || !REQUEST_WANTS_TYPE (callback->request, REQUEST_FILE_LIST)) { file_list = NULL; } else { file_list = nemo_directory_get_file_list (directory); } /* Pass back the file list if the user was waiting for it. */ (* callback->callback.directory) (directory, file_list, callback->callback_data); nemo_file_list_free (file_list); } } void nemo_directory_call_when_ready_internal (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback directory_callback, NemoFileCallback file_callback, gpointer callback_data) { ReadyCallback callback; g_assert (directory == NULL || NEMO_IS_DIRECTORY (directory)); g_assert (file == NULL || NEMO_IS_FILE (file)); g_assert (file != NULL || directory_callback != NULL); /* Construct a callback object. */ callback.active = TRUE; callback.file = file; if (file == NULL) { callback.callback.directory = directory_callback; } else { callback.callback.file = file_callback; } callback.callback_data = callback_data; callback.request = nemo_directory_set_up_request (file_attributes); if (wait_for_file_list) { REQUEST_SET_TYPE (callback.request, REQUEST_FILE_LIST); } /* Handle the NULL case. */ if (directory == NULL) { ready_callback_call (NULL, &callback); return; } /* Check if the callback is already there. */ if (g_list_find_custom (directory->details->call_when_ready_list, &callback, ready_callback_key_compare_only_active) != NULL) { if (file_callback != NULL && directory_callback != NULL) { g_warning ("tried to add a new callback while an old one was pending"); } /* NULL callback means, just read it. Conflicts are ok. */ return; } /* Add the new callback to the list. */ directory->details->call_when_ready_list = g_list_prepend (directory->details->call_when_ready_list, g_memdup (&callback, sizeof (callback))); request_counter_add_request (directory->details->call_when_ready_counters, callback.request); /* Put the callback file or all the files on the work queue. */ if (file != NULL) { nemo_directory_add_file_to_work_queue (directory, file); } else { add_all_files_to_work_queue (directory); } nemo_directory_async_state_changed (directory); } gboolean nemo_directory_check_if_ready_internal (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes) { Request request; g_assert (NEMO_IS_DIRECTORY (directory)); request = nemo_directory_set_up_request (file_attributes); return request_is_satisfied (directory, file, request); } static void remove_callback_link_keep_data (NemoDirectory *directory, GList *link) { ReadyCallback *callback; callback = link->data; directory->details->call_when_ready_list = g_list_remove_link (directory->details->call_when_ready_list, link); request_counter_remove_request (directory->details->call_when_ready_counters, callback->request); g_list_free_1 (link); } static void remove_callback_link (NemoDirectory *directory, GList *link) { ReadyCallback *callback; callback = link->data; remove_callback_link_keep_data (directory, link); g_free (callback); } void nemo_directory_cancel_callback_internal (NemoDirectory *directory, NemoFile *file, NemoDirectoryCallback directory_callback, NemoFileCallback file_callback, gpointer callback_data) { ReadyCallback callback; GList *node; if (directory == NULL) { return; } g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (file == NULL || NEMO_IS_FILE (file)); g_assert (file != NULL || directory_callback != NULL); g_assert (file == NULL || file_callback != NULL); /* Construct a callback object. */ callback.file = file; if (file == NULL) { callback.callback.directory = directory_callback; } else { callback.callback.file = file_callback; } callback.callback_data = callback_data; /* Remove all queued callback from the list (including non-active). */ do { node = g_list_find_custom (directory->details->call_when_ready_list, &callback, ready_callback_key_compare); if (node != NULL) { remove_callback_link (directory, node); nemo_directory_async_state_changed (directory); } } while (node != NULL); } static void new_files_state_unref (NewFilesState *state) { state->count--; if (state->count == 0) { if (state->directory) { state->directory->details->new_files_in_progress = g_list_remove (state->directory->details->new_files_in_progress, state); } g_object_unref (state->cancellable); g_free (state); } } static void new_files_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoDirectory *directory; GFileInfo *info; NewFilesState *state; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ new_files_state_unref (state); return; } directory = nemo_directory_ref (state->directory); /* Queue up the new file. */ info = g_file_query_info_finish (G_FILE (source_object), res, NULL); if (info != NULL) { directory_load_one (directory, info); g_object_unref (info); } new_files_state_unref (state); nemo_directory_unref (directory); } void nemo_directory_get_info_for_new_files (NemoDirectory *directory, GList *location_list) { NewFilesState *state; GFile *location; GList *l; if (location_list == NULL) { return; } state = g_new (NewFilesState, 1); state->directory = directory; state->cancellable = g_cancellable_new (); state->count = 0; for (l = location_list; l != NULL; l = l->next) { location = l->data; state->count++; g_file_query_info_async (location, NEMO_FILE_DEFAULT_ATTRIBUTES, 0, G_PRIORITY_DEFAULT, state->cancellable, new_files_callback, state); } directory->details->new_files_in_progress = g_list_prepend (directory->details->new_files_in_progress, state); } void nemo_async_destroying_file (NemoFile *file) { NemoDirectory *directory; gboolean changed; GList *node, *next; ReadyCallback *callback; Monitor *monitor; directory = file->details->directory; changed = FALSE; /* Check for callbacks. */ for (node = directory->details->call_when_ready_list; node != NULL; node = next) { next = node->next; callback = node->data; if (callback->file == file) { /* Client should have cancelled callback. */ if (callback->active) { g_warning ("destroyed file has call_when_ready pending"); } remove_callback_link (directory, node); changed = TRUE; } } /* Check for monitors. */ for (node = directory->details->monitor_list; node != NULL; node = next) { next = node->next; monitor = node->data; if (monitor->file == file) { /* Client should have removed monitor earlier. */ g_warning ("destroyed file still being monitored"); remove_monitor_link (directory, node); changed = TRUE; } } /* Check if it's a file that's currently being worked on. * If so, make that NULL so it gets canceled right away. */ if (directory->details->count_in_progress != NULL && directory->details->count_in_progress->count_file == file) { directory->details->count_in_progress->count_file = NULL; changed = TRUE; } if (directory->details->deep_count_file == file) { directory->details->deep_count_file = NULL; changed = TRUE; } if (directory->details->mime_list_in_progress != NULL && directory->details->mime_list_in_progress->mime_list_file == file) { directory->details->mime_list_in_progress->mime_list_file = NULL; changed = TRUE; } if (directory->details->get_info_file == file) { directory->details->get_info_file = NULL; changed = TRUE; } if (directory->details->get_btime_file == file) { directory->details->get_btime_file = NULL; changed = TRUE; } if (directory->details->link_info_read_state != NULL && directory->details->link_info_read_state->file == file) { directory->details->link_info_read_state->file = NULL; changed = TRUE; } if (directory->details->extension_info_file == file) { directory->details->extension_info_file = NULL; changed = TRUE; } if (directory->details->thumbnail_state != NULL && directory->details->thumbnail_state->file == file) { directory->details->thumbnail_state->file = NULL; changed = TRUE; } if (directory->details->mount_state != NULL && directory->details->mount_state->file == file) { directory->details->mount_state->file = NULL; changed = TRUE; } if (directory->details->filesystem_info_state != NULL && directory->details->filesystem_info_state->file == file) { directory->details->filesystem_info_state->file = NULL; changed = TRUE; } /* Let the directory take care of the rest. */ if (changed) { nemo_directory_async_state_changed (directory); } } static gboolean lacks_directory_count (NemoFile *file) { return !file->details->directory_count_is_up_to_date && nemo_file_should_show_directory_item_count (file); } static gboolean should_get_directory_count_now (NemoFile *file) { return lacks_directory_count (file) && !file->details->loading_directory; } static gboolean lacks_info (NemoFile *file) { return !file->details->file_info_is_up_to_date && !file->details->is_gone; } static gboolean lacks_btime (NemoFile *file) { return !file->details->btime_is_up_to_date && !file->details->is_gone; } static gboolean lacks_filesystem_info (NemoFile *file) { return !file->details->filesystem_info_is_up_to_date; } static gboolean lacks_deep_count (NemoFile *file) { return file->details->deep_counts_status != NEMO_REQUEST_DONE; } static gboolean lacks_mime_list (NemoFile *file) { return !file->details->mime_list_is_up_to_date; } static gboolean should_get_mime_list (NemoFile *file) { return lacks_mime_list (file) && !file->details->loading_directory; } static gboolean lacks_link_info (NemoFile *file) { if (file->details->file_info_is_up_to_date && !file->details->link_info_is_up_to_date) { if (nemo_file_is_nemo_link (file)) { return TRUE; } else { link_info_done (file->details->directory, file, NULL, NULL, NULL, FALSE, FALSE); return FALSE; } } else { return FALSE; } } static gboolean lacks_extension_info (NemoFile *file) { return file->details->pending_info_providers != NULL; } static gboolean lacks_thumbnail (NemoFile *file) { return nemo_file_should_show_thumbnail (file) && file->details->thumbnail_path != NULL && !file->details->thumbnail_is_up_to_date; } static gboolean lacks_mount (NemoFile *file) { return (!file->details->mount_is_up_to_date && ( /* Unix mountpoint, could be a GMount */ file->details->is_mountpoint || /* The toplevel directory of something */ (file->details->type == G_FILE_TYPE_DIRECTORY && nemo_file_is_self_owned (file)) || /* Mountable, could be a mountpoint */ (file->details->type == G_FILE_TYPE_MOUNTABLE) ) ); } static gboolean has_problem (NemoDirectory *directory, NemoFile *file, FileCheck problem) { GList *node; if (file != NULL) { return (* problem) (file); } for (node = directory->details->file_list; node != NULL; node = node->next) { if ((* problem) (node->data)) { return TRUE; } } return FALSE; } static gboolean request_is_satisfied (NemoDirectory *directory, NemoFile *file, Request request) { if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_LIST) && !(directory->details->directory_loaded && directory->details->directory_loaded_sent_notification)) { return FALSE; } if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) { if (has_problem (directory, file, lacks_directory_count)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) { if (has_problem (directory, file, lacks_info)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) { if (has_problem (directory, file, lacks_btime)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) { if (has_problem (directory, file, lacks_filesystem_info)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) { if (has_problem (directory, file, lacks_deep_count)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) { if (has_problem (directory, file, lacks_thumbnail)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) { if (has_problem (directory, file, lacks_mount)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) { if (has_problem (directory, file, lacks_mime_list)) { return FALSE; } } if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) { if (has_problem (directory, file, lacks_link_info)) { return FALSE; } } return TRUE; } static gboolean call_ready_callbacks_at_idle (gpointer callback_data) { NemoDirectory *directory; GList *node, *next; ReadyCallback *callback; directory = NEMO_DIRECTORY (callback_data); directory->details->call_ready_idle_id = 0; nemo_directory_ref (directory); callback = NULL; while (1) { /* Check if any callbacks are non-active and call them if they are. */ for (node = directory->details->call_when_ready_list; node != NULL; node = next) { next = node->next; callback = node->data; if (!callback->active) { /* Non-active, remove and call */ break; } } if (node == NULL) { break; } /* Callbacks are one-shots, so remove it now. */ remove_callback_link_keep_data (directory, node); /* Call the callback. */ ready_callback_call (directory, callback); g_free (callback); } nemo_directory_async_state_changed (directory); nemo_directory_unref (directory); return FALSE; } static void schedule_call_ready_callbacks (NemoDirectory *directory) { if (directory->details->call_ready_idle_id == 0) { directory->details->call_ready_idle_id = g_idle_add (call_ready_callbacks_at_idle, directory); } } /* Marks all callbacks that are ready as non-active and * calls them at idle time, unless they are removed * before then */ static gboolean call_ready_callbacks (NemoDirectory *directory) { gboolean found_any; GList *node, *next; ReadyCallback *callback; found_any = FALSE; /* Check if any callbacks are satisifed and mark them for call them if they are. */ for (node = directory->details->call_when_ready_list; node != NULL; node = next) { next = node->next; callback = node->data; if (callback->active && request_is_satisfied (directory, callback->file, callback->request)) { callback->active = FALSE; found_any = TRUE; } } if (found_any) { schedule_call_ready_callbacks (directory); } return found_any; } gboolean nemo_directory_has_active_request_for_file (NemoDirectory *directory, NemoFile *file) { GList *node; ReadyCallback *callback; Monitor *monitor; for (node = directory->details->call_when_ready_list; node != NULL; node = node->next) { callback = node->data; if (callback->file == file || callback->file == NULL) { return TRUE; } } for (node = directory->details->monitor_list; node != NULL; node = node->next) { monitor = node->data; if (monitor->file == file || monitor->file == NULL) { return TRUE; } } return FALSE; } /* This checks if there's a request for monitoring the file list. */ gboolean nemo_directory_is_anyone_monitoring_file_list (NemoDirectory *directory) { if (directory->details->call_when_ready_counters[REQUEST_FILE_LIST] > 0) { return TRUE; } if (directory->details->monitor_counters[REQUEST_FILE_LIST] > 0) { return TRUE; } return FALSE; } /* This checks if the file list being monitored. */ gboolean nemo_directory_is_file_list_monitored (NemoDirectory *directory) { return directory->details->file_list_monitored; } static void mark_all_files_unconfirmed (NemoDirectory *directory) { GList *node; NemoFile *file; for (node = directory->details->file_list; node != NULL; node = node->next) { file = node->data; set_file_unconfirmed (file, TRUE); } } static void read_dot_hidden_file (NemoDirectory *directory) { gsize file_size; char *file_contents; GFile *child; GFileInfo *info; GFileType type; guint i; /* FIXME: We only support .hidden on file: uri's for the moment. * Need to figure out if we should do this async or sync to extend * it to all types of uris. */ if (directory->details->location == NULL || !g_file_is_native (directory->details->location)) { return; } child = g_file_get_child (directory->details->location, ".hidden"); type = G_FILE_TYPE_UNKNOWN; info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL); if (info != NULL) { type = g_file_info_get_file_type (info); g_object_unref (info); } if (type != G_FILE_TYPE_REGULAR) { g_object_unref (child); return; } if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { g_object_unref (child); return; } g_object_unref (child); if (directory->details->hidden_file_hash == NULL) { directory->details->hidden_file_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } /* Now parse the data */ i = 0; while (i < file_size) { guint start; start = i; while (i < file_size && file_contents[i] != '\n') { i++; } if (i > start) { char *hidden_filename; hidden_filename = g_strndup (file_contents + start, i - start); g_hash_table_insert (directory->details->hidden_file_hash, hidden_filename, hidden_filename); } i++; } g_free (file_contents); } static void directory_load_state_free (DirectoryLoadState *state) { if (state->enumerator) { if (!g_file_enumerator_is_closed (state->enumerator)) { g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); } g_object_unref (state->enumerator); } if (state->load_mime_list_hash != NULL) { istr_set_destroy (state->load_mime_list_hash); } nemo_file_unref (state->load_directory_file); g_object_unref (state->cancellable); g_free (state); } static void more_files_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DirectoryLoadState *state; NemoDirectory *directory; GError *error; GList *files, *l; GFileInfo *info; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ directory_load_state_free (state); return; } directory = nemo_directory_ref (state->directory); g_assert (directory->details->directory_load_in_progress != NULL); g_assert (directory->details->directory_load_in_progress == state); error = NULL; files = g_file_enumerator_next_files_finish (state->enumerator, res, &error); for (l = files; l != NULL; l = l->next) { info = l->data; directory_load_one (directory, info); g_object_unref (info); } if (files == NULL) { directory_load_done (directory, error); directory_load_state_free (state); } else { g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, more_files_callback, state); } nemo_directory_unref (directory); if (error) { g_error_free (error); } g_list_free (files); } static void enumerate_children_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DirectoryLoadState *state; GFileEnumerator *enumerator; GError *error; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ directory_load_state_free (state); return; } error = NULL; enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, &error); if (enumerator == NULL) { directory_load_done (state->directory, error); g_error_free (error); directory_load_state_free (state); return; } else { state->enumerator = enumerator; g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, more_files_callback, state); } } /* Start monitoring the file list if it isn't already. */ static void start_monitoring_file_list (NemoDirectory *directory) { DirectoryLoadState *state; if (!directory->details->file_list_monitored) { g_assert (!directory->details->directory_load_in_progress); directory->details->file_list_monitored = TRUE; nemo_file_list_ref (directory->details->file_list); } if (directory->details->directory_loaded || directory->details->directory_load_in_progress != NULL) { return; } if (!async_job_start (directory, "file list")) { return; } mark_all_files_unconfirmed (directory); state = g_new0 (DirectoryLoadState, 1); state->directory = directory; state->cancellable = g_cancellable_new (); state->load_mime_list_hash = istr_set_new (); state->load_file_count = 0; g_assert (directory->details->location != NULL); state->load_directory_file = nemo_directory_get_corresponding_file (directory); state->load_directory_file->details->loading_directory = TRUE; read_dot_hidden_file (directory); /* Hack to work around kde trash dir */ if (kde_trash_dir_name != NULL && nemo_directory_is_desktop_directory (directory)) { char *fn; if (directory->details->hidden_file_hash == NULL) { directory->details->hidden_file_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } fn = g_strdup (kde_trash_dir_name); g_hash_table_insert (directory->details->hidden_file_hash, fn, fn); } #ifdef DEBUG_LOAD_DIRECTORY g_message ("load_directory called to monitor file list of %p", directory->details->location); #endif directory->details->directory_load_in_progress = state; g_file_enumerate_children_async (directory->details->location, NEMO_FILE_DEFAULT_ATTRIBUTES, 0, /* flags */ G_PRIORITY_DEFAULT, /* prio */ state->cancellable, enumerate_children_callback, state); } /* Stop monitoring the file list if it is being monitored. */ void nemo_directory_stop_monitoring_file_list (NemoDirectory *directory) { if (!directory->details->file_list_monitored) { g_assert (directory->details->directory_load_in_progress == NULL); return; } directory->details->file_list_monitored = FALSE; file_list_cancel (directory); nemo_file_list_unref (directory->details->file_list); directory->details->directory_loaded = FALSE; } static void file_list_start_or_stop (NemoDirectory *directory) { if (nemo_directory_is_anyone_monitoring_file_list (directory)) { start_monitoring_file_list (directory); } else { nemo_directory_stop_monitoring_file_list (directory); } } void nemo_file_invalidate_count_and_mime_list (NemoFile *file) { NemoFileAttributes attributes; attributes = NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES; nemo_file_invalidate_attributes (file, attributes); } /* Reset count and mime list. Invalidating deep counts is handled by * itself elsewhere because it's a relatively heavyweight and * special-purpose operation (see bug 5863). Also, the shallow count * needs to be refreshed when filtering changes, but the deep count * deliberately does not take filtering into account. */ void nemo_directory_invalidate_count_and_mime_list (NemoDirectory *directory) { NemoFile *file; file = nemo_directory_get_existing_corresponding_file (directory); if (file != NULL) { nemo_file_invalidate_count_and_mime_list (file); } nemo_file_unref (file); } static void nemo_directory_invalidate_file_attributes (NemoDirectory *directory, NemoFileAttributes file_attributes) { GList *node; cancel_loading_attributes (directory, file_attributes); for (node = directory->details->file_list; node != NULL; node = node->next) { nemo_file_invalidate_attributes_internal (NEMO_FILE (node->data), file_attributes); } if (directory->details->as_file != NULL) { nemo_file_invalidate_attributes_internal (directory->details->as_file, file_attributes); } } void nemo_directory_force_reload_internal (NemoDirectory *directory, NemoFileAttributes file_attributes) { /* invalidate attributes that are getting reloaded for all files */ nemo_directory_invalidate_file_attributes (directory, file_attributes); /* Start a new directory load. */ file_list_cancel (directory); directory->details->directory_loaded = FALSE; /* Start a new directory count. */ nemo_directory_invalidate_count_and_mime_list (directory); add_all_files_to_work_queue (directory); nemo_directory_async_state_changed (directory); } static gboolean monitor_includes_file (const Monitor *monitor, NemoFile *file) { if (monitor->file == file) { return TRUE; } if (monitor->file != NULL) { return FALSE; } if (file == file->details->directory->details->as_file) { return FALSE; } return nemo_file_should_show (file, monitor->monitor_hidden_files, TRUE); } static gboolean is_needy (NemoFile *file, FileCheck check_missing, RequestType request_type_wanted) { NemoDirectory *directory; GList *node; ReadyCallback *callback; Monitor *monitor; if (!(* check_missing) (file)) { return FALSE; } directory = file->details->directory; if (directory->details->call_when_ready_counters[request_type_wanted] > 0) { for (node = directory->details->call_when_ready_list; node != NULL; node = node->next) { callback = node->data; if (callback->active && REQUEST_WANTS_TYPE (callback->request, request_type_wanted)) { if (callback->file == file) { return TRUE; } if (callback->file == NULL && file != directory->details->as_file) { return TRUE; } } } } if (directory->details->monitor_counters[request_type_wanted] > 0) { for (node = directory->details->monitor_list; node != NULL; node = node->next) { monitor = node->data; if (REQUEST_WANTS_TYPE (monitor->request, request_type_wanted)) { if (monitor_includes_file (monitor, file)) { return TRUE; } } } } return FALSE; } static void directory_count_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->count_in_progress != NULL) { file = directory->details->count_in_progress->count_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, should_get_directory_count_now, REQUEST_DIRECTORY_COUNT)) { return; } } /* The count is not wanted, so stop it. */ directory_count_cancel (directory); } } static guint count_non_skipped_files (GList *list) { guint count; GList *node; GFileInfo *info; count = 0; for (node = list; node != NULL; node = node->next) { info = node->data; if (!should_skip_file (NULL, info)) { count += 1; } } return count; } static void count_children_done (NemoDirectory *directory, NemoFile *count_file, gboolean succeeded, int count) { g_assert (NEMO_IS_FILE (count_file)); count_file->details->directory_count_is_up_to_date = TRUE; /* Record either a failure or success. */ if (!succeeded) { count_file->details->directory_count_failed = TRUE; count_file->details->got_directory_count = FALSE; count_file->details->directory_count = 0; } else { count_file->details->directory_count_failed = FALSE; count_file->details->got_directory_count = TRUE; count_file->details->directory_count = count; } directory->details->count_in_progress = NULL; /* Send file-changed even if count failed, so interested parties can * distinguish between unknowable and not-yet-known cases. */ nemo_file_changed (count_file); /* Start up the next one. */ async_job_end (directory, "directory count"); nemo_directory_async_state_changed (directory); } static void directory_count_state_free (DirectoryCountState *state) { if (state->enumerator) { if (!g_file_enumerator_is_closed (state->enumerator)) { g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); } g_object_unref (state->enumerator); } g_object_unref (state->cancellable); nemo_directory_unref (state->directory); g_free (state); } static void count_more_files_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DirectoryCountState *state; NemoDirectory *directory; GError *error; GList *files; state = user_data; directory = state->directory; if (g_cancellable_is_cancelled (state->cancellable)) { /* Operation was cancelled. Bail out */ directory->details->count_in_progress = NULL; async_job_end (directory, "directory count"); nemo_directory_async_state_changed (directory); directory_count_state_free (state); return; } g_assert (directory->details->count_in_progress != NULL); g_assert (directory->details->count_in_progress == state); error = NULL; files = g_file_enumerator_next_files_finish (state->enumerator, res, &error); state->file_count += count_non_skipped_files (files); if (files == NULL) { count_children_done (directory, state->count_file, TRUE, state->file_count); directory_count_state_free (state); } else { g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, count_more_files_callback, state); } g_list_free_full (files, g_object_unref); if (error) { g_error_free (error); } } static void count_children_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DirectoryCountState *state; GFileEnumerator *enumerator; NemoDirectory *directory; GError *error; state = user_data; if (g_cancellable_is_cancelled (state->cancellable)) { /* Operation was cancelled. Bail out */ directory = state->directory; directory->details->count_in_progress = NULL; async_job_end (directory, "directory count"); nemo_directory_async_state_changed (directory); directory_count_state_free (state); return; } error = NULL; enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, &error); if (enumerator == NULL) { count_children_done (state->directory, state->count_file, FALSE, 0); g_error_free (error); directory_count_state_free (state); return; } else { state->enumerator = enumerator; g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, count_more_files_callback, state); } } static void directory_count_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { DirectoryCountState *state; GFile *location; if (directory->details->count_in_progress != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, should_get_directory_count_now, REQUEST_DIRECTORY_COUNT)) { return; } *doing_io = TRUE; if (!nemo_file_is_directory (file)) { file->details->directory_count_is_up_to_date = TRUE; file->details->directory_count_failed = FALSE; file->details->got_directory_count = FALSE; nemo_directory_async_state_changed (directory); return; } if (!async_job_start (directory, "directory count")) { return; } /* Start counting. */ state = g_new0 (DirectoryCountState, 1); state->count_file = file; state->directory = nemo_directory_ref (directory); state->cancellable = g_cancellable_new (); directory->details->count_in_progress = state; location = nemo_file_get_location (file); #ifdef DEBUG_LOAD_DIRECTORY { char *uri; uri = g_file_get_uri (location); g_message ("load_directory called to get shallow file count for %s", uri); g_free (uri); } #endif g_file_enumerate_children_async (location, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */ G_PRIORITY_DEFAULT, /* prio */ state->cancellable, count_children_callback, state); g_object_unref (location); } static inline gboolean seen_inode (DeepCountState *state, GFileInfo *info) { guint64 inode, inode2; guint i; inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE); if (inode != 0) { for (i = 0; i < state->seen_deep_count_inodes->len; i++) { inode2 = g_array_index (state->seen_deep_count_inodes, guint64, i); if (inode == inode2) { return TRUE; } } } return FALSE; } static inline void mark_inode_as_seen (DeepCountState *state, GFileInfo *info) { guint64 inode; inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE); if (inode != 0) { g_array_append_val (state->seen_deep_count_inodes, inode); } } static void deep_count_one (DeepCountState *state, GFileInfo *info) { NemoFile *file; GFile *subdir; gboolean is_seen_inode; const char *id; gboolean hidden; is_seen_inode = seen_inode (state, info); if (!is_seen_inode) { mark_inode_as_seen (state, info); } file = state->directory->details->deep_count_file; hidden = should_skip_file (NULL, info); if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { /* Count the directory. */ if (hidden) { file->details->deep_hidden_count += 1; } else { file->details->deep_directory_count += 1; } /* Record the fact that we have to descend into this directory. */ id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if (g_strcmp0 (id, state->fs_id) == 0) { /* only if it is on the same filesystem */ subdir = g_file_get_child (state->deep_count_location, g_file_info_get_name (info)); state->deep_count_subdirectories = g_list_prepend (state->deep_count_subdirectories, subdir); } } else { /* Even non-regular files count as files. */ if (hidden) { file->details->deep_hidden_count += 1; } else { file->details->deep_file_count += 1; } } /* Count the size, hidden or not */ if (!is_seen_inode && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) { file->details->deep_size += g_file_info_get_size (info); } } static void deep_count_state_free (DeepCountState *state) { if (state->enumerator) { if (!g_file_enumerator_is_closed (state->enumerator)) { g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); } g_object_unref (state->enumerator); } g_object_unref (state->cancellable); if (state->deep_count_location) { g_object_unref (state->deep_count_location); } g_list_free_full (state->deep_count_subdirectories, g_object_unref); g_array_free (state->seen_deep_count_inodes, TRUE); g_free (state->fs_id); g_free (state); } static void deep_count_next_dir (DeepCountState *state) { GFile *location; NemoFile *file; NemoDirectory *directory; gboolean done; directory = state->directory; g_object_unref (state->deep_count_location); state->deep_count_location = NULL; done = FALSE; file = directory->details->deep_count_file; if (state->deep_count_subdirectories != NULL) { /* Work on a new directory. */ location = state->deep_count_subdirectories->data; state->deep_count_subdirectories = g_list_remove (state->deep_count_subdirectories, location); deep_count_load (state, location); g_object_unref (location); } else { file->details->deep_counts_status = NEMO_REQUEST_DONE; directory->details->deep_count_file = NULL; directory->details->deep_count_in_progress = NULL; deep_count_state_free (state); done = TRUE; } nemo_file_updated_deep_count_in_progress (file); if (done) { nemo_file_changed (file); async_job_end (directory, "deep count"); nemo_directory_async_state_changed (directory); } } static void deep_count_more_files_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DeepCountState *state; NemoDirectory *directory; GList *files, *l; GFileInfo *info; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ deep_count_state_free (state); return; } directory = nemo_directory_ref (state->directory); g_assert (directory->details->deep_count_in_progress != NULL); g_assert (directory->details->deep_count_in_progress == state); files = g_file_enumerator_next_files_finish (state->enumerator, res, NULL); for (l = files; l != NULL; l = l->next) { info = l->data; deep_count_one (state, info); g_object_unref (info); } if (files == NULL) { g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); g_object_unref (state->enumerator); state->enumerator = NULL; deep_count_next_dir (state); } else { g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_LOW, state->cancellable, deep_count_more_files_callback, state); } g_list_free (files); nemo_directory_unref (directory); } static void deep_count_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { DeepCountState *state; GFileEnumerator *enumerator; NemoFile *file; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ deep_count_state_free (state); return; } file = state->directory->details->deep_count_file; enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, NULL); if (enumerator == NULL) { file->details->deep_unreadable_count += 1; deep_count_next_dir (state); } else { state->enumerator = enumerator; g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_LOW, state->cancellable, deep_count_more_files_callback, state); } } static void deep_count_load (DeepCountState *state, GFile *location) { state->deep_count_location = g_object_ref (location); #ifdef DEBUG_LOAD_DIRECTORY g_message ("load_directory called to get deep file count for %p", location); #endif g_file_enumerate_children_async (state->deep_count_location, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP "," G_FILE_ATTRIBUTE_ID_FILESYSTEM "," G_FILE_ATTRIBUTE_UNIX_INODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */ G_PRIORITY_LOW, /* prio */ state->cancellable, deep_count_callback, state); } static void deep_count_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->deep_count_in_progress != NULL) { file = directory->details->deep_count_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_deep_count, REQUEST_DEEP_COUNT)) { return; } } /* The count is not wanted, so stop it. */ deep_count_cancel (directory); } } static void deep_count_got_info (GObject *source_object, GAsyncResult *res, gpointer user_data) { GFileInfo *info; const char *id; GFile *file = (GFile *)source_object; DeepCountState *state = (DeepCountState *)user_data; info = g_file_query_info_finish (file, res, NULL); if (info) { id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); state->fs_id = g_strdup (id); g_object_unref (info); } deep_count_load (state, file); } static void deep_count_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; DeepCountState *state; if (directory->details->deep_count_in_progress != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_deep_count, REQUEST_DEEP_COUNT)) { return; } *doing_io = TRUE; if (!nemo_file_is_directory (file)) { file->details->deep_counts_status = NEMO_REQUEST_DONE; nemo_directory_async_state_changed (directory); return; } if (!async_job_start (directory, "deep count")) { return; } /* Start counting. */ file->details->deep_counts_status = NEMO_REQUEST_IN_PROGRESS; file->details->deep_directory_count = 0; file->details->deep_file_count = 0; file->details->deep_unreadable_count = 0; file->details->deep_hidden_count = 0; file->details->deep_size = 0; directory->details->deep_count_file = file; state = g_new0 (DeepCountState, 1); state->directory = directory; state->cancellable = g_cancellable_new (); state->seen_deep_count_inodes = g_array_new (FALSE, TRUE, sizeof (guint64)); directory->details->deep_count_in_progress = state; location = nemo_file_get_location (file); state->fs_id = NULL; g_file_query_info_async (location, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_DEFAULT, NULL, deep_count_got_info, state); g_object_unref (location); } static void mime_list_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->mime_list_in_progress != NULL) { file = directory->details->mime_list_in_progress->mime_list_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, should_get_mime_list, REQUEST_MIME_LIST)) { return; } } /* The count is not wanted, so stop it. */ mime_list_cancel (directory); } } static void mime_list_state_free (MimeListState *state) { if (state->enumerator) { if (!g_file_enumerator_is_closed (state->enumerator)) { g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); } g_object_unref (state->enumerator); } g_object_unref (state->cancellable); istr_set_destroy (state->mime_list_hash); nemo_directory_unref (state->directory); g_free (state); } static void mime_list_done (MimeListState *state, gboolean success) { NemoFile *file; NemoDirectory *directory; directory = state->directory; g_assert (directory != NULL); file = state->mime_list_file; file->details->mime_list_is_up_to_date = TRUE; g_list_free_full (file->details->mime_list, g_free); if (success) { file->details->mime_list_failed = TRUE; file->details->mime_list = NULL; } else { file->details->got_mime_list = TRUE; file->details->mime_list = istr_set_get_as_list (state->mime_list_hash); } directory->details->mime_list_in_progress = NULL; /* Send file-changed even if getting the item type list * failed, so interested parties can distinguish between * unknowable and not-yet-known cases. */ nemo_file_changed (file); /* Start up the next one. */ async_job_end (directory, "MIME list"); nemo_directory_async_state_changed (directory); } static void mime_list_one (MimeListState *state, GFileInfo *info) { const char *mime_type; if (should_skip_file (NULL, info)) { g_object_unref (info); return; } mime_type = g_file_info_get_content_type (info); if (mime_type != NULL) { istr_set_insert (state->mime_list_hash, mime_type); } } static void mime_list_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { MimeListState *state; NemoDirectory *directory; GError *error; GList *files, *l; GFileInfo *info; state = user_data; directory = state->directory; if (g_cancellable_is_cancelled (state->cancellable)) { /* Operation was cancelled. Bail out */ directory->details->mime_list_in_progress = NULL; async_job_end (directory, "MIME list"); nemo_directory_async_state_changed (directory); mime_list_state_free (state); return; } g_assert (directory->details->mime_list_in_progress != NULL); g_assert (directory->details->mime_list_in_progress == state); error = NULL; files = g_file_enumerator_next_files_finish (state->enumerator, res, &error); for (l = files; l != NULL; l = l->next) { info = l->data; mime_list_one (state, info); g_object_unref (info); } if (files == NULL) { mime_list_done (state, error != NULL); mime_list_state_free (state); } else { g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, mime_list_callback, state); } g_list_free (files); if (error) { g_error_free (error); } } static void list_mime_enum_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { MimeListState *state; GFileEnumerator *enumerator; NemoDirectory *directory; GError *error; state = user_data; if (g_cancellable_is_cancelled (state->cancellable)) { /* Operation was cancelled. Bail out */ directory = state->directory; directory->details->mime_list_in_progress = NULL; async_job_end (directory, "MIME list"); nemo_directory_async_state_changed (directory); mime_list_state_free (state); return; } error = NULL; enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, &error); if (enumerator == NULL) { mime_list_done (state, FALSE); g_error_free (error); mime_list_state_free (state); return; } else { state->enumerator = enumerator; g_file_enumerator_next_files_async (state->enumerator, DIRECTORY_LOAD_ITEMS_PER_CALLBACK, G_PRIORITY_DEFAULT, state->cancellable, mime_list_callback, state); } } static void mime_list_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { MimeListState *state; GFile *location; mime_list_stop (directory); if (directory->details->mime_list_in_progress != NULL) { *doing_io = TRUE; return; } /* Figure out which file to get a mime list for. */ if (!is_needy (file, should_get_mime_list, REQUEST_MIME_LIST)) { return; } *doing_io = TRUE; if (!nemo_file_is_directory (file)) { g_list_free (file->details->mime_list); file->details->mime_list_failed = FALSE; file->details->got_mime_list = FALSE; file->details->mime_list_is_up_to_date = TRUE; nemo_directory_async_state_changed (directory); return; } if (!async_job_start (directory, "MIME list")) { return; } state = g_new0 (MimeListState, 1); state->mime_list_file = file; state->directory = nemo_directory_ref (directory); state->cancellable = g_cancellable_new (); state->mime_list_hash = istr_set_new (); directory->details->mime_list_in_progress = state; location = nemo_file_get_location (file); #ifdef DEBUG_LOAD_DIRECTORY { char *uri; uri = g_file_get_uri (location); g_message ("load_directory called to get MIME list of %s", uri); g_free (uri); } #endif g_file_enumerate_children_async (location, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, /* flags */ G_PRIORITY_LOW, /* prio */ state->cancellable, list_mime_enum_callback, state); g_object_unref (location); } static void get_info_state_free (GetInfoState *state) { g_object_unref (state->cancellable); g_free (state); } static void query_info_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoDirectory *directory; NemoFile *get_info_file; GFileInfo *info; GetInfoState *state; GError *error; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ get_info_state_free (state); return; } directory = nemo_directory_ref (state->directory); get_info_file = directory->details->get_info_file; g_assert (NEMO_IS_FILE (get_info_file)); directory->details->get_info_file = NULL; directory->details->get_info_in_progress = NULL; /* ref here because we might be removing the last ref when we * mark the file gone below, but we need to keep a ref at * least long enough to send the change notification. */ nemo_file_ref (get_info_file); error = NULL; info = g_file_query_info_finish (G_FILE (source_object), res, &error); if (info == NULL) { if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) { /* mark file as gone */ nemo_file_mark_gone (get_info_file); } get_info_file->details->file_info_is_up_to_date = TRUE; nemo_file_clear_info (get_info_file); get_info_file->details->get_info_failed = TRUE; get_info_file->details->get_info_error = error; } else { nemo_file_update_info (get_info_file, info); g_object_unref (info); } nemo_file_changed (get_info_file); nemo_file_unref (get_info_file); async_job_end (directory, "file info"); nemo_directory_async_state_changed (directory); nemo_directory_unref (directory); get_info_state_free (state); } static void file_info_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->get_info_in_progress != NULL) { file = directory->details->get_info_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_info, REQUEST_FILE_INFO)) { return; } } /* The info is not wanted, so stop it. */ file_info_cancel (directory); } } static void file_info_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; GetInfoState *state; file_info_stop (directory); if (directory->details->get_info_in_progress != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_info, REQUEST_FILE_INFO)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "file info")) { return; } directory->details->get_info_file = file; file->details->get_info_failed = FALSE; if (file->details->get_info_error) { g_error_free (file->details->get_info_error); file->details->get_info_error = NULL; } state = g_new (GetInfoState, 1); state->directory = directory; state->cancellable = g_cancellable_new (); directory->details->get_info_in_progress = state; location = nemo_file_get_location (file); g_file_query_info_async (location, NEMO_FILE_DEFAULT_ATTRIBUTES, 0, G_PRIORITY_DEFAULT, state->cancellable, query_info_callback, state); g_object_unref (location); } static void get_btime_state_free (GetBTimeState *state) { g_object_unref (state->cancellable); g_free (state); } static void query_btime_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoDirectory *directory; NemoFile *get_btime_file; GetBTimeState *state; GError *error; time_t btime; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ get_btime_state_free (state); return; } directory = nemo_directory_ref (state->directory); get_btime_file = directory->details->get_btime_file; g_assert (NEMO_IS_FILE (get_btime_file)); directory->details->get_btime_file = NULL; directory->details->get_btime_in_progress = NULL; /* ref here because we might be removing the last ref when we * mark the file gone below, but we need to keep a ref at * least long enough to send the change notification. */ nemo_file_ref (get_btime_file); error = NULL; btime = nemo_query_btime_finish (G_FILE (source_object), res, &error); if (btime == -1) { get_btime_file->details->btime_is_up_to_date = TRUE; get_btime_file->details->get_btime_failed = TRUE; if (error) { g_clear_error (&error); } } else { get_btime_file->details->btime = btime; get_btime_file->details->btime_is_up_to_date = TRUE; get_btime_file->details->get_btime_failed = FALSE; } nemo_file_changed (get_btime_file); nemo_file_unref (get_btime_file); async_job_end (directory, "get btime"); nemo_directory_async_state_changed (directory); nemo_directory_unref (directory); get_btime_state_free (state); } static void btime_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->get_btime_in_progress != NULL) { file = directory->details->get_btime_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_btime, REQUEST_BTIME)) { return; } } /* The info is not wanted, so stop it. */ btime_cancel (directory); } } static void btime_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; GetBTimeState *state; btime_stop (directory); if (directory->details->get_btime_in_progress != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_btime, REQUEST_BTIME)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "get btime")) { return; } directory->details->get_btime_file = file; file->details->get_btime_failed = FALSE; state = g_new (GetBTimeState, 1); state->directory = directory; state->cancellable = g_cancellable_new (); directory->details->get_btime_in_progress = state; location = nemo_file_get_location (file); nemo_query_btime_async (location, state->cancellable, query_btime_callback, state); g_object_unref (location); } static gboolean is_link_trusted (NemoFile *file, gboolean is_launcher) { GFile *location; gboolean res; if (!is_launcher) { return TRUE; } if (nemo_file_can_execute (file)) { return TRUE; } res = FALSE; if (nemo_file_is_local (file)) { location = nemo_file_get_location (file); res = nemo_is_in_system_dir (location); g_object_unref (location); } return res; } static void link_info_done (NemoDirectory *directory, NemoFile *file, const char *uri, const char *name, GIcon *icon, gboolean is_launcher, gboolean is_foreign) { gboolean is_trusted; file->details->link_info_is_up_to_date = TRUE; is_trusted = is_link_trusted (file, is_launcher); if (is_trusted) { nemo_file_set_display_name (file, name, name, TRUE); } else { nemo_file_set_display_name (file, NULL, NULL, TRUE); } file->details->got_link_info = TRUE; g_clear_object (&file->details->custom_icon); if (uri) { g_free (file->details->activation_uri); file->details->activation_uri = NULL; file->details->got_custom_activation_uri = TRUE; file->details->activation_uri = g_strdup (uri); } if (is_trusted && (icon != NULL)) { file->details->custom_icon = g_object_ref (icon); } file->details->is_launcher = is_launcher; file->details->is_foreign_link = is_foreign; file->details->is_trusted_link = is_trusted; nemo_directory_async_state_changed (directory); } static void link_info_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->link_info_read_state != NULL) { file = directory->details->link_info_read_state->file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_link_info, REQUEST_LINK_INFO)) { return; } } /* The link info is not wanted, so stop it. */ link_info_cancel (directory); } } static void link_info_got_data (NemoDirectory *directory, NemoFile *file, gboolean result, goffset bytes_read, char *file_contents) { char *link_uri, *uri, *name; GIcon *icon; gboolean is_launcher; gboolean is_foreign; nemo_directory_ref (directory); uri = NULL; name = NULL; icon = NULL; is_launcher = FALSE; is_foreign = FALSE; /* Handle the case where we read the Nemo link. */ if (result) { link_uri = nemo_file_get_uri (file); nemo_link_get_link_info_given_file_contents (file_contents, bytes_read, link_uri, &uri, &name, &icon, &is_launcher, &is_foreign); g_free (link_uri); } else { /* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */ } nemo_file_ref (file); link_info_done (directory, file, uri, name, icon, is_launcher, is_foreign); nemo_file_changed (file); nemo_file_unref (file); g_free (uri); g_free (name); if (icon != NULL) { g_object_unref (icon); } nemo_directory_unref (directory); } static void link_info_read_state_free (LinkInfoReadState *state) { g_object_unref (state->cancellable); g_free (state); } static void link_info_nemo_link_read_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { LinkInfoReadState *state; gsize file_size; char *file_contents; gboolean result; NemoDirectory *directory; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ link_info_read_state_free (state); return; } directory = nemo_directory_ref (state->directory); result = g_file_load_contents_finish (G_FILE (source_object), res, &file_contents, &file_size, NULL, NULL); state->directory->details->link_info_read_state = NULL; async_job_end (state->directory, "link info"); link_info_got_data (state->directory, state->file, result, file_size, file_contents); if (result) { g_free (file_contents); } link_info_read_state_free (state); nemo_directory_unref (directory); } static void link_info_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; gboolean nemo_style_link; LinkInfoReadState *state; if (directory->details->link_info_read_state != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_link_info, REQUEST_LINK_INFO)) { return; } *doing_io = TRUE; /* Figure out if it is a link. */ nemo_style_link = nemo_file_is_nemo_link (file); location = nemo_file_get_location (file); /* If it's not a link we are done. If it is, we need to read it. */ if (!nemo_style_link) { link_info_done (directory, file, NULL, NULL, NULL, FALSE, FALSE); } else { if (!async_job_start (directory, "link info")) { g_object_unref (location); return; } state = g_new0 (LinkInfoReadState, 1); state->directory = directory; state->file = file; state->cancellable = g_cancellable_new (); directory->details->link_info_read_state = state; g_file_load_contents_async (location, state->cancellable, link_info_nemo_link_read_callback, state); } g_object_unref (location); } static void thumbnail_done (NemoDirectory *directory, NemoFile *file, GdkPixbuf *pixbuf, gboolean tried_original) { const char *thumb_mtime_str; time_t thumb_mtime = 0; file->details->thumbnail_is_up_to_date = TRUE; file->details->thumbnail_tried_original = tried_original; if (file->details->thumbnail) { g_object_unref (file->details->thumbnail); file->details->thumbnail = NULL; } if (pixbuf) { if (tried_original) { thumb_mtime = file->details->mtime; } else { thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime"); if (thumb_mtime_str) { thumb_mtime = atol (thumb_mtime_str); } } if (thumb_mtime == 0 || thumb_mtime == file->details->mtime) { file->details->thumbnail = g_object_ref (pixbuf); file->details->thumbnail_mtime = thumb_mtime; file->details->thumbnail_throttle_count = 1; } else { g_free (file->details->thumbnail_path); file->details->thumbnail_path = NULL; } } nemo_directory_async_state_changed (directory); } static void thumbnail_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->thumbnail_state != NULL) { file = directory->details->thumbnail_state->file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_thumbnail, REQUEST_THUMBNAIL)) { return; } } /* The link info is not wanted, so stop it. */ thumbnail_cancel (directory); } } static void thumbnail_got_pixbuf (NemoDirectory *directory, NemoFile *file, GdkPixbuf *pixbuf, gboolean tried_original) { nemo_directory_ref (directory); nemo_file_ref (file); thumbnail_done (directory, file, pixbuf, tried_original); nemo_file_changed (file); nemo_file_unref (file); if (pixbuf) { g_object_unref (pixbuf); } nemo_directory_unref (directory); } static void thumbnail_state_free (ThumbnailState *state) { g_object_unref (state->cancellable); g_free (state); } extern int cached_thumbnail_size; /* scale very large images down to the max. size we need */ static void thumbnail_loader_size_prepared (GdkPixbufLoader *loader, int width, int height, gpointer user_data) { int max_thumbnail_size; double aspect_ratio; aspect_ratio = ((double) width) / height; /* cf. nemo_file_get_icon() */ max_thumbnail_size = NEMO_ICON_SIZE_LARGEST * cached_thumbnail_size / NEMO_ICON_SIZE_STANDARD; if (MAX (width, height) > max_thumbnail_size) { if (width > height) { width = max_thumbnail_size; height = width / aspect_ratio; } else { height = max_thumbnail_size; width = height * aspect_ratio; } gdk_pixbuf_loader_set_size (loader, width, height); } } static GdkPixbuf * get_pixbuf_for_content (goffset file_len, char *file_contents) { gboolean res; GdkPixbuf *pixbuf, *pixbuf2; GdkPixbufLoader *loader; gsize chunk_len; pixbuf = NULL; loader = gdk_pixbuf_loader_new (); g_signal_connect (loader, "size-prepared", G_CALLBACK (thumbnail_loader_size_prepared), NULL); /* For some reason we have to write in chunks, or gdk-pixbuf fails */ res = TRUE; while (res && file_len > 0) { chunk_len = file_len; res = gdk_pixbuf_loader_write (loader, (guchar *) file_contents, chunk_len, NULL); file_contents += chunk_len; file_len -= chunk_len; } if (res) { res = gdk_pixbuf_loader_close (loader, NULL); } if (res) { pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); } g_object_unref (G_OBJECT (loader)); if (pixbuf) { pixbuf2 = gdk_pixbuf_apply_embedded_orientation (pixbuf); g_object_unref (pixbuf); pixbuf = pixbuf2; } return pixbuf; } static void thumbnail_read_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { ThumbnailState *state; gsize file_size; char *file_contents; gboolean result; NemoDirectory *directory; GdkPixbuf *pixbuf; GFile *location; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ thumbnail_state_free (state); return; } directory = nemo_directory_ref (state->directory); result = g_file_load_contents_finish (G_FILE (source_object), res, &file_contents, &file_size, NULL, NULL); pixbuf = NULL; if (result) { pixbuf = get_pixbuf_for_content (file_size, file_contents); g_free (file_contents); } if (pixbuf == NULL && state->trying_original) { state->trying_original = FALSE; location = g_file_new_for_path (state->file->details->thumbnail_path); g_file_load_contents_async (location, state->cancellable, thumbnail_read_callback, state); g_object_unref (location); } else { state->directory->details->thumbnail_state = NULL; async_job_end (state->directory, "thumbnail"); thumbnail_got_pixbuf (state->directory, state->file, pixbuf, state->tried_original); thumbnail_state_free (state); } nemo_directory_unref (directory); } static void thumbnail_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; ThumbnailState *state; if (directory->details->thumbnail_state != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_thumbnail, REQUEST_THUMBNAIL)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "thumbnail")) { return; } state = g_new0 (ThumbnailState, 1); state->directory = directory; state->file = file; state->cancellable = g_cancellable_new (); if (file->details->thumbnail_wants_original) { state->tried_original = TRUE; state->trying_original = TRUE; location = nemo_file_get_location (file); } else { location = g_file_new_for_path (file->details->thumbnail_path); } directory->details->thumbnail_state = state; g_file_load_contents_async (location, state->cancellable, thumbnail_read_callback, state); g_object_unref (location); } static void mount_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->mount_state != NULL) { file = directory->details->mount_state->file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_mount, REQUEST_MOUNT)) { return; } } /* The link info is not wanted, so stop it. */ mount_cancel (directory); } } static void mount_state_free (MountState *state) { g_object_unref (state->cancellable); g_free (state); } static void got_mount (MountState *state, GMount *mount) { NemoDirectory *directory; NemoFile *file; directory = nemo_directory_ref (state->directory); state->directory->details->mount_state = NULL; async_job_end (state->directory, "mount"); file = nemo_file_ref (state->file); file->details->mount_is_up_to_date = TRUE; nemo_file_set_mount (file, mount); nemo_directory_async_state_changed (directory); nemo_file_changed (file); nemo_file_unref (file); nemo_directory_unref (directory); mount_state_free (state); } static void find_enclosing_mount_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GMount *mount; MountState *state; GFile *location, *root; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ mount_state_free (state); return; } mount = g_file_find_enclosing_mount_finish (G_FILE (source_object), res, NULL); if (mount) { root = g_mount_get_root (mount); location = nemo_file_get_location (state->file); if (!g_file_equal (location, root)) { g_object_unref (mount); mount = NULL; } g_object_unref (root); g_object_unref (location); } got_mount (state, mount); if (mount) { g_object_unref (mount); } } static GMount * get_mount_at (GFile *target) { GVolumeMonitor *monitor; GFile *root; GList *mounts, *l; GMount *found; monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (monitor); found = NULL; for (l = mounts; l != NULL; l = l->next) { GMount *mount = G_MOUNT (l->data); if (g_mount_is_shadowed (mount)) continue; root = g_mount_get_root (mount); if (g_file_equal (target, root)) { found = g_object_ref (mount); break; } g_object_unref (root); } g_list_free_full (mounts, g_object_unref); g_object_unref (monitor); return found; } static void mount_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; MountState *state; if (directory->details->mount_state != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_mount, REQUEST_MOUNT)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "mount")) { return; } state = g_new0 (MountState, 1); state->directory = directory; state->file = file; state->cancellable = g_cancellable_new (); location = nemo_file_get_location (file); directory->details->mount_state = state; if (file->details->type == G_FILE_TYPE_MOUNTABLE) { GFile *target; GMount *mount; mount = NULL; target = nemo_file_get_activation_location (file); if (target != NULL) { mount = get_mount_at (target); g_object_unref (target); } got_mount (state, mount); if (mount) { g_object_unref (mount); } } else { g_file_find_enclosing_mount_async (location, G_PRIORITY_DEFAULT, state->cancellable, find_enclosing_mount_callback, state); } g_object_unref (location); } static void filesystem_info_cancel (NemoDirectory *directory) { if (directory->details->filesystem_info_state != NULL) { g_cancellable_cancel (directory->details->filesystem_info_state->cancellable); directory->details->filesystem_info_state->directory = NULL; directory->details->filesystem_info_state = NULL; async_job_end (directory, "filesystem info"); } } static void filesystem_info_stop (NemoDirectory *directory) { NemoFile *file; if (directory->details->filesystem_info_state != NULL) { file = directory->details->filesystem_info_state->file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_filesystem_info, REQUEST_FILESYSTEM_INFO)) { return; } } /* The filesystem info is not wanted, so stop it. */ filesystem_info_cancel (directory); } } static void filesystem_info_state_free (FilesystemInfoState *state) { g_object_unref (state->cancellable); g_free (state); } static void got_filesystem_info (FilesystemInfoState *state, GFileInfo *info) { NemoDirectory *directory; NemoFile *file; /* careful here, info may be NULL */ directory = nemo_directory_ref (state->directory); state->directory->details->filesystem_info_state = NULL; async_job_end (state->directory, "filesystem info"); file = nemo_file_ref (state->file); file->details->filesystem_info_is_up_to_date = TRUE; if (info != NULL) { file->details->filesystem_use_preview = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW); file->details->filesystem_readonly = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY); } nemo_directory_async_state_changed (directory); nemo_file_changed (file); nemo_file_unref (file); nemo_directory_unref (directory); filesystem_info_state_free (state); } static void query_filesystem_info_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GFileInfo *info; FilesystemInfoState *state; state = user_data; if (state->directory == NULL) { /* Operation was cancelled. Bail out */ filesystem_info_state_free (state); return; } info = g_file_query_filesystem_info_finish (G_FILE (source_object), res, NULL); got_filesystem_info (state, info); if (info != NULL) { g_object_unref (info); } } static void filesystem_info_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { GFile *location; FilesystemInfoState *state; if (directory->details->filesystem_info_state != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_filesystem_info, REQUEST_FILESYSTEM_INFO)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "filesystem info")) { return; } state = g_new0 (FilesystemInfoState, 1); state->directory = directory; state->file = file; state->cancellable = g_cancellable_new (); location = nemo_file_get_location (file); directory->details->filesystem_info_state = state; g_file_query_filesystem_info_async (location, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY "," G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_PRIORITY_DEFAULT, state->cancellable, query_filesystem_info_callback, state); g_object_unref (location); } static void extension_info_cancel (NemoDirectory *directory) { if (directory->details->extension_info_in_progress != NULL) { if (directory->details->extension_info_idle > 0) { g_source_remove (directory->details->extension_info_idle); directory->details->extension_info_idle = 0; } else { nemo_info_provider_cancel_update (directory->details->extension_info_provider, directory->details->extension_info_in_progress); g_closure_invalidate (directory->details->extension_info_closure); } directory->details->extension_info_in_progress = NULL; directory->details->extension_info_file = NULL; directory->details->extension_info_provider = NULL; g_closure_unref (directory->details->extension_info_closure); directory->details->extension_info_closure = NULL; async_job_end (directory, "extension info"); } } static void extension_info_stop (NemoDirectory *directory) { if (directory->details->extension_info_in_progress != NULL) { NemoFile *file; file = directory->details->extension_info_file; if (file != NULL) { g_assert (NEMO_IS_FILE (file)); g_assert (file->details->directory == directory); if (is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) { return; } } /* The info is not wanted, so stop it. */ extension_info_cancel (directory); nemo_directory_unref (directory); } } static void finish_info_provider (NemoDirectory *directory, NemoFile *file, NemoInfoProvider *provider) { file->details->pending_info_providers = g_list_remove (file->details->pending_info_providers, provider); g_object_unref (provider); if (file->details->pending_info_providers == NULL) { nemo_file_info_providers_done (file); } nemo_directory_unref (directory); nemo_directory_async_state_changed (directory); } static gboolean info_provider_idle_callback (gpointer user_data) { InfoProviderResponse *response; NemoDirectory *directory; response = user_data; directory = response->directory; if (response->handle != directory->details->extension_info_in_progress || response->provider != directory->details->extension_info_provider) { g_warning ("Unexpected plugin response. This probably indicates a bug in a Nemo extension: handle=%p", response->handle); } else { NemoFile *file; async_job_end (directory, "extension info"); file = directory->details->extension_info_file; directory->details->extension_info_file = NULL; directory->details->extension_info_provider = NULL; directory->details->extension_info_in_progress = NULL; directory->details->extension_info_idle = 0; g_closure_unref (directory->details->extension_info_closure); directory->details->extension_info_closure = NULL; finish_info_provider (directory, file, response->provider); } return FALSE; } static void info_provider_callback (NemoInfoProvider *provider, NemoOperationHandle *handle, NemoOperationResult result, gpointer user_data) { InfoProviderResponse *response; response = g_new0 (InfoProviderResponse, 1); response->provider = provider; response->handle = handle; response->result = result; response->directory = NEMO_DIRECTORY (user_data); response->directory->details->extension_info_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, info_provider_idle_callback, response, g_free); } static void extension_info_start (NemoDirectory *directory, NemoFile *file, gboolean *doing_io) { NemoInfoProvider *provider; NemoOperationResult result; NemoOperationHandle *handle; GClosure *update_complete; if (directory->details->extension_info_in_progress != NULL) { *doing_io = TRUE; return; } if (!is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) { return; } *doing_io = TRUE; if (!async_job_start (directory, "extension info")) { return; } provider = file->details->pending_info_providers->data; /* If the user navigates out of the current directory while this job is * running, cleanup will occur before a progress-type callback can complete, * potentially causing a segfault as directory->details->extension_info_could * be NULL during finish_info_provider. */ nemo_directory_ref (directory); handle = NULL; update_complete = g_cclosure_new (G_CALLBACK (info_provider_callback), directory, NULL); g_closure_set_marshal (update_complete, g_cclosure_marshal_generic); result = nemo_info_provider_update_file_info (provider, NEMO_FILE_INFO (file), update_complete, &handle); if (result == NEMO_OPERATION_COMPLETE || result == NEMO_OPERATION_FAILED) { g_closure_unref (update_complete); finish_info_provider (directory, file, provider); async_job_end (directory, "extension info"); } else { directory->details->extension_info_in_progress = handle; directory->details->extension_info_provider = provider; directory->details->extension_info_file = file; directory->details->extension_info_closure = update_complete; } } static void start_or_stop_io (NemoDirectory *directory) { NemoFile *file; gboolean doing_io; /* Start or stop reading files. */ file_list_start_or_stop (directory); /* Stop any no longer wanted attribute fetches. */ file_info_stop (directory); btime_stop (directory); directory_count_stop (directory); deep_count_stop (directory); mime_list_stop (directory); link_info_stop (directory); extension_info_stop (directory); mount_stop (directory); thumbnail_stop (directory); filesystem_info_stop (directory); doing_io = FALSE; /* Take files that are all done off the queue. */ while (!nemo_file_queue_is_empty (directory->details->high_priority_queue)) { file = nemo_file_queue_head (directory->details->high_priority_queue); /* Start getting attributes if possible */ file_info_start (directory, file, &doing_io); link_info_start (directory, file, &doing_io); if (doing_io) { return; } move_file_to_low_priority_queue (directory, file); } /* High priority queue must be empty */ while (!nemo_file_queue_is_empty (directory->details->low_priority_queue)) { file = nemo_file_queue_head (directory->details->low_priority_queue); /* Start getting attributes if possible */ btime_start (directory, file, &doing_io); mount_start (directory, file, &doing_io); directory_count_start (directory, file, &doing_io); deep_count_start (directory, file, &doing_io); mime_list_start (directory, file, &doing_io); thumbnail_start (directory, file, &doing_io); filesystem_info_start (directory, file, &doing_io); if (doing_io) { return; } move_file_to_extension_queue (directory, file); } /* Low priority queue must be empty */ while (!nemo_file_queue_is_empty (directory->details->extension_queue)) { file = nemo_file_queue_head (directory->details->extension_queue); /* Start getting attributes if possible */ extension_info_start (directory, file, &doing_io); if (doing_io) { return; } nemo_directory_remove_file_from_work_queue (directory, file); } } /* Call this when the monitor or call when ready list changes, * or when some I/O is completed. */ void nemo_directory_async_state_changed (NemoDirectory *directory) { /* Check if any callbacks are satisfied and call them if they * are. Do this last so that any changes done in start or stop * I/O functions immediately (not in callbacks) are taken into * consideration. If any callbacks are called, consider the * I/O state again so that we can release or cancel I/O that * is not longer needed once the callbacks are satisfied. */ if (directory->details->in_async_service_loop) { directory->details->state_changed = TRUE; return; } directory->details->in_async_service_loop = TRUE; nemo_directory_ref (directory); do { directory->details->state_changed = FALSE; start_or_stop_io (directory); if (call_ready_callbacks (directory)) { directory->details->state_changed = TRUE; } } while (directory->details->state_changed); directory->details->in_async_service_loop = FALSE; nemo_directory_unref (directory); /* Check if any directories should wake up. */ async_job_wake_up (); } void nemo_directory_cancel (NemoDirectory *directory) { /* Arbitrary order (kept alphabetical). */ deep_count_cancel (directory); directory_count_cancel (directory); file_info_cancel (directory); file_list_cancel (directory); link_info_cancel (directory); mime_list_cancel (directory); new_files_cancel (directory); extension_info_cancel (directory); thumbnail_cancel (directory); mount_cancel (directory); filesystem_info_cancel (directory); /* We aren't waiting for anything any more. */ if (waiting_directories != NULL) { g_hash_table_remove (waiting_directories, directory); } /* Check if any directories should wake up. */ async_job_wake_up (); } static void cancel_directory_count_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->count_in_progress != NULL && directory->details->count_in_progress->count_file == file) { directory_count_cancel (directory); } } static void cancel_deep_counts_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->deep_count_file == file) { deep_count_cancel (directory); } } static void cancel_mime_list_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->mime_list_in_progress != NULL && directory->details->mime_list_in_progress->mime_list_file == file) { mime_list_cancel (directory); } } static void cancel_file_info_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->get_info_file == file) { file_info_cancel (directory); } } static void cancel_btime_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->get_btime_file == file) { btime_cancel (directory); } } static void cancel_thumbnail_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->thumbnail_state != NULL && directory->details->thumbnail_state->file == file) { thumbnail_cancel (directory); } } static void cancel_mount_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->mount_state != NULL && directory->details->mount_state->file == file) { mount_cancel (directory); } } static void cancel_filesystem_info_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->filesystem_info_state != NULL && directory->details->filesystem_info_state->file == file) { filesystem_info_cancel (directory); } } static void cancel_link_info_for_file (NemoDirectory *directory, NemoFile *file) { if (directory->details->link_info_read_state != NULL && directory->details->link_info_read_state->file == file) { link_info_cancel (directory); } } static void cancel_loading_attributes (NemoDirectory *directory, NemoFileAttributes file_attributes) { Request request; request = nemo_directory_set_up_request (file_attributes); if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) { directory_count_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) { deep_count_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) { mime_list_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) { file_info_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) { btime_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) { filesystem_info_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) { link_info_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) { extension_info_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) { thumbnail_cancel (directory); } if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) { mount_cancel (directory); } nemo_directory_async_state_changed (directory); } void nemo_directory_cancel_loading_file_attributes (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes) { Request request; nemo_directory_remove_file_from_work_queue (directory, file); request = nemo_directory_set_up_request (file_attributes); if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) { cancel_directory_count_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) { cancel_deep_counts_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) { cancel_mime_list_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) { cancel_file_info_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) { cancel_btime_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) { cancel_filesystem_info_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) { cancel_link_info_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) { cancel_thumbnail_for_file (directory, file); } if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) { cancel_mount_for_file (directory, file); } nemo_directory_async_state_changed (directory); } void nemo_directory_add_file_to_work_queue (NemoDirectory *directory, NemoFile *file) { g_return_if_fail (file->details->directory == directory); nemo_file_queue_enqueue (directory->details->high_priority_queue, file); } static void add_all_files_to_work_queue (NemoDirectory *directory) { GList *node; NemoFile *file; for (node = directory->details->file_list; node != NULL; node = node->next) { file = NEMO_FILE (node->data); nemo_directory_add_file_to_work_queue (directory, file); } } void nemo_directory_remove_file_from_work_queue (NemoDirectory *directory, NemoFile *file) { nemo_file_queue_remove (directory->details->high_priority_queue, file); nemo_file_queue_remove (directory->details->low_priority_queue, file); nemo_file_queue_remove (directory->details->extension_queue, file); } static void move_file_to_low_priority_queue (NemoDirectory *directory, NemoFile *file) { /* Must add before removing to avoid ref underflow */ nemo_file_queue_enqueue (directory->details->low_priority_queue, file); nemo_file_queue_remove (directory->details->high_priority_queue, file); } static void move_file_to_extension_queue (NemoDirectory *directory, NemoFile *file) { /* Must add before removing to avoid ref underflow */ nemo_file_queue_enqueue (directory->details->extension_queue, file); nemo_file_queue_remove (directory->details->low_priority_queue, file); } nemo-4.4.2/libnemo-private/nemo-directory-notify.h000066400000000000000000000052311357442400300221760ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-directory-notify.h: Nemo directory notify calls. Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include typedef struct { char *from_uri; char *to_uri; } URIPair; typedef struct { GFile *from; GFile *to; } GFilePair; typedef struct { GFile *location; gboolean set; GdkPoint point; int screen; int monitor; } NemoFileChangesQueuePosition; /* Almost-public change notification calls */ void nemo_directory_notify_files_added (GList *files); void nemo_directory_notify_files_moved (GList *file_pairs); void nemo_directory_notify_files_changed (GList *files); void nemo_directory_notify_files_removed (GList *files); void nemo_directory_schedule_metadata_copy (GList *file_pairs); void nemo_directory_schedule_metadata_move (GList *file_pairs); void nemo_directory_schedule_metadata_remove (GList *files); /* Deprecated URI versions: to be converted */ void nemo_directory_notify_files_added_by_uri (GList *uris); void nemo_directory_notify_files_changed_by_uri (GList *uris); void nemo_directory_notify_files_moved_by_uri (GList *uri_pairs); void nemo_directory_notify_files_removed_by_uri (GList *uris); void nemo_directory_schedule_metadata_copy_by_uri (GList *uri_pairs); void nemo_directory_schedule_metadata_move_by_uri (GList *uri_pairs); void nemo_directory_schedule_metadata_remove_by_uri (GList *uris); void nemo_directory_schedule_position_set (GList *position_setting_list); /* Change notification hack. * This is called when code modifies the file and it needs to trigger * a notification. Eventually this should become private, but for now * it needs to be used for code like the thumbnail generation. */ void nemo_file_changed (NemoFile *file); nemo-4.4.2/libnemo-private/nemo-directory-private.h000066400000000000000000000256651357442400300223550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-directory-private.h: Nemo directory model. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include #include #include #include #include #include #include typedef struct LinkInfoReadState LinkInfoReadState; typedef struct FileMonitors FileMonitors; typedef struct DirectoryLoadState DirectoryLoadState; typedef struct DirectoryCountState DirectoryCountState; typedef struct DeepCountState DeepCountState; typedef struct GetInfoState GetInfoState; typedef struct GetBTimeState GetBTimeState; typedef struct NewFilesState NewFilesState; typedef struct MimeListState MimeListState; typedef struct ThumbnailState ThumbnailState; typedef struct MountState MountState; typedef struct FilesystemInfoState FilesystemInfoState; typedef enum { REQUEST_LINK_INFO, REQUEST_DEEP_COUNT, REQUEST_DIRECTORY_COUNT, REQUEST_FILE_INFO, REQUEST_FILE_LIST, /* always FALSE if file != NULL */ REQUEST_MIME_LIST, REQUEST_EXTENSION_INFO, REQUEST_THUMBNAIL, REQUEST_MOUNT, REQUEST_FILESYSTEM_INFO, REQUEST_BTIME, REQUEST_TYPE_LAST } RequestType; /* A request for information about one or more files. */ typedef guint32 Request; typedef gint32 RequestCounter[REQUEST_TYPE_LAST]; #define REQUEST_WANTS_TYPE(request, type) ((request) & (1<<(type))) #define REQUEST_SET_TYPE(request, type) (request) |= (1<<(type)) struct NemoDirectoryDetails { /* The location. */ GFile *location; /* The file objects. */ NemoFile *as_file; GList *file_list; GHashTable *file_hash; /* Queues of files needing some I/O done. */ NemoFileQueue *high_priority_queue; NemoFileQueue *low_priority_queue; NemoFileQueue *extension_queue; /* These lists are going to be pretty short. If we think they * are going to get big, we can use hash tables instead. */ GList *call_when_ready_list; RequestCounter call_when_ready_counters; GList *monitor_list; RequestCounter monitor_counters; guint call_ready_idle_id; NemoMonitor *monitor; gulong mime_db_monitor; gboolean in_async_service_loop; gboolean state_changed; gboolean file_list_monitored; gboolean directory_loaded; gboolean directory_loaded_sent_notification; DirectoryLoadState *directory_load_in_progress; GList *pending_file_info; /* list of GnomeVFSFileInfo's that are pending */ int confirmed_file_count; guint dequeue_pending_idle_id; GList *new_files_in_progress; /* list of NewFilesState * */ /* List of GFile's that received CHANGE events while new files were being added in * that same folder. We will process this CHANGE events after new_files_in_progress * list is finished. See Bug 703179 for a case when this happens. */ GList *new_files_in_progress_changes; DirectoryCountState *count_in_progress; NemoFile *deep_count_file; DeepCountState *deep_count_in_progress; MimeListState *mime_list_in_progress; NemoFile *get_info_file; GetInfoState *get_info_in_progress; NemoFile *get_btime_file; GetBTimeState *get_btime_in_progress; NemoFile *extension_info_file; NemoInfoProvider *extension_info_provider; NemoOperationHandle *extension_info_in_progress; guint extension_info_idle; GClosure * extension_info_closure; ThumbnailState *thumbnail_state; MountState *mount_state; FilesystemInfoState *filesystem_info_state; LinkInfoReadState *link_info_read_state; GList *file_operations_in_progress; /* list of FileOperation * */ GHashTable *hidden_file_hash; }; NemoDirectory *nemo_directory_get_existing (GFile *location); /* async. interface */ void nemo_directory_async_state_changed (NemoDirectory *directory); void nemo_directory_call_when_ready_internal (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback directory_callback, NemoFileCallback file_callback, gpointer callback_data); gboolean nemo_directory_check_if_ready_internal (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes); void nemo_directory_cancel_callback_internal (NemoDirectory *directory, NemoFile *file, NemoDirectoryCallback directory_callback, NemoFileCallback file_callback, gpointer callback_data); void nemo_directory_monitor_add_internal (NemoDirectory *directory, NemoFile *file, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes attributes, NemoDirectoryCallback callback, gpointer callback_data); void nemo_directory_monitor_remove_internal (NemoDirectory *directory, NemoFile *file, gconstpointer client); void nemo_directory_get_info_for_new_files (NemoDirectory *directory, GList *vfs_uris); NemoFile * nemo_directory_get_existing_corresponding_file (NemoDirectory *directory); void nemo_directory_invalidate_count_and_mime_list (NemoDirectory *directory); gboolean nemo_directory_is_file_list_monitored (NemoDirectory *directory); gboolean nemo_directory_is_anyone_monitoring_file_list (NemoDirectory *directory); gboolean nemo_directory_has_active_request_for_file (NemoDirectory *directory, NemoFile *file); void nemo_directory_remove_file_monitor_link (NemoDirectory *directory, GList *link); void nemo_directory_schedule_dequeue_pending (NemoDirectory *directory); void nemo_directory_stop_monitoring_file_list (NemoDirectory *directory); void nemo_directory_cancel (NemoDirectory *directory); void nemo_async_destroying_file (NemoFile *file); void nemo_directory_force_reload_internal (NemoDirectory *directory, NemoFileAttributes file_attributes); void nemo_directory_cancel_loading_file_attributes (NemoDirectory *directory, NemoFile *file, NemoFileAttributes file_attributes); /* Calls shared between directory, file, and async. code. */ void nemo_directory_emit_files_added (NemoDirectory *directory, GList *added_files); void nemo_directory_emit_files_changed (NemoDirectory *directory, GList *changed_files); void nemo_directory_emit_change_signals (NemoDirectory *directory, GList *changed_files); void emit_change_signals_for_all_files (NemoDirectory *directory); void emit_change_signals_for_all_files_in_all_directories (void); void nemo_directory_emit_done_loading (NemoDirectory *directory); void nemo_directory_emit_load_error (NemoDirectory *directory, GError *error); NemoDirectory *nemo_directory_get_internal (GFile *location, gboolean create); char * nemo_directory_get_name_for_self_as_new_file (NemoDirectory *directory); Request nemo_directory_set_up_request (NemoFileAttributes file_attributes); /* Interface to the file list. */ NemoFile * nemo_directory_find_file_by_name (NemoDirectory *directory, const char *filename); NemoFile * nemo_directory_find_file_by_internal_filename (NemoDirectory *directory, const char *internal_filename); void nemo_directory_remove_file (NemoDirectory *directory, NemoFile *file); FileMonitors * nemo_directory_remove_file_monitors (NemoDirectory *directory, NemoFile *file); void nemo_directory_add_file_monitors (NemoDirectory *directory, NemoFile *file, FileMonitors *monitors); void nemo_directory_add_file (NemoDirectory *directory, NemoFile *file); GList * nemo_directory_begin_file_name_change (NemoDirectory *directory, NemoFile *file); void nemo_directory_end_file_name_change (NemoDirectory *directory, NemoFile *file, GList *node); void nemo_directory_moved (const char *from_uri, const char *to_uri); /* Interface to the work queue. */ void nemo_directory_add_file_to_work_queue (NemoDirectory *directory, NemoFile *file); void nemo_directory_remove_file_from_work_queue (NemoDirectory *directory, NemoFile *file); /* KDE compatibility hacks */ void nemo_set_kde_trash_name (const char *trash_dir); /* debugging functions */ int nemo_directory_number_outstanding (void); nemo-4.4.2/libnemo-private/nemo-directory.c000066400000000000000000001375461357442400300207020ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-directory.c: Nemo directory model. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-directory-private.h" #include "nemo-directory-notify.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include "nemo-search-directory.h" #include "nemo-global-preferences.h" #include "nemo-lib-self-check-functions.h" #include "nemo-metadata.h" #include "nemo-desktop-directory.h" #include "nemo-vfs-directory.h" #include #include #include enum { FILES_ADDED, FILES_CHANGED, DONE_LOADING, LOAD_ERROR, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static GHashTable *directories; static void nemo_directory_finalize (GObject *object); static NemoDirectory *nemo_directory_new (GFile *location); static GList * real_get_file_list (NemoDirectory *directory); static gboolean real_is_editable (NemoDirectory *directory); static void set_directory_location (NemoDirectory *directory, GFile *location); G_DEFINE_TYPE (NemoDirectory, nemo_directory, G_TYPE_OBJECT); static void nemo_directory_class_init (NemoDirectoryClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = nemo_directory_finalize; signals[FILES_ADDED] = g_signal_new ("files_added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoDirectoryClass, files_added), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[FILES_CHANGED] = g_signal_new ("files_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoDirectoryClass, files_changed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[DONE_LOADING] = g_signal_new ("done_loading", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoDirectoryClass, done_loading), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[LOAD_ERROR] = g_signal_new ("load_error", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoDirectoryClass, load_error), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); klass->get_file_list = real_get_file_list; klass->is_editable = real_is_editable; g_type_class_add_private (klass, sizeof (NemoDirectoryDetails)); } static void nemo_directory_init (NemoDirectory *directory) { directory->details = G_TYPE_INSTANCE_GET_PRIVATE ((directory), NEMO_TYPE_DIRECTORY, NemoDirectoryDetails); directory->details->file_hash = g_hash_table_new (g_str_hash, g_str_equal); directory->details->high_priority_queue = nemo_file_queue_new (); directory->details->low_priority_queue = nemo_file_queue_new (); directory->details->extension_queue = nemo_file_queue_new (); } NemoDirectory * nemo_directory_ref (NemoDirectory *directory) { if (directory == NULL) { return directory; } g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); g_object_ref (directory); return directory; } void nemo_directory_unref (NemoDirectory *directory) { if (directory == NULL) { return; } g_return_if_fail (NEMO_IS_DIRECTORY (directory)); g_object_unref (directory); } static void nemo_directory_finalize (GObject *object) { NemoDirectory *directory; directory = NEMO_DIRECTORY (object); g_hash_table_remove (directories, directory->details->location); nemo_directory_cancel (directory); g_assert (directory->details->count_in_progress == NULL); if (directory->details->monitor_list != NULL) { g_warning ("destroying a NemoDirectory while it's being monitored"); g_list_free_full (directory->details->monitor_list, g_free); } if (directory->details->monitor != NULL) { nemo_monitor_cancel (directory->details->monitor); } if (directory->details->dequeue_pending_idle_id != 0) { g_source_remove (directory->details->dequeue_pending_idle_id); } if (directory->details->call_ready_idle_id != 0) { g_source_remove (directory->details->call_ready_idle_id); } if (directory->details->location) { g_object_unref (directory->details->location); } g_assert (directory->details->file_list == NULL); g_hash_table_destroy (directory->details->file_hash); if (directory->details->hidden_file_hash) { g_hash_table_destroy (directory->details->hidden_file_hash); } nemo_file_queue_destroy (directory->details->high_priority_queue); nemo_file_queue_destroy (directory->details->low_priority_queue); nemo_file_queue_destroy (directory->details->extension_queue); g_assert (directory->details->directory_load_in_progress == NULL); g_assert (directory->details->count_in_progress == NULL); g_assert (directory->details->dequeue_pending_idle_id == 0); g_list_free_full (directory->details->pending_file_info, g_object_unref); G_OBJECT_CLASS (nemo_directory_parent_class)->finalize (object); } static void invalidate_one_count (gpointer key, gpointer value, gpointer user_data) { NemoDirectory *directory; g_assert (key != NULL); g_assert (NEMO_IS_DIRECTORY (value)); g_assert (user_data == NULL); directory = NEMO_DIRECTORY (value); nemo_directory_invalidate_count_and_mime_list (directory); } static void filtering_changed_callback (gpointer callback_data) { g_assert (callback_data == NULL); /* Preference about which items to show has changed, so we * can't trust any of our precomputed directory counts. */ g_hash_table_foreach (directories, invalidate_one_count, NULL); } void emit_change_signals_for_all_files (NemoDirectory *directory) { GList *files; files = g_list_copy (directory->details->file_list); if (directory->details->as_file != NULL) { files = g_list_prepend (files, directory->details->as_file); } nemo_file_list_ref (files); nemo_directory_emit_change_signals (directory, files); nemo_file_list_free (files); } static void collect_all_directories (gpointer key, gpointer value, gpointer callback_data) { NemoDirectory *directory; GList **dirs; directory = NEMO_DIRECTORY (value); dirs = callback_data; *dirs = g_list_prepend (*dirs, nemo_directory_ref (directory)); } void emit_change_signals_for_all_files_in_all_directories (void) { GList *dirs, *l; NemoDirectory *directory; dirs = NULL; g_hash_table_foreach (directories, collect_all_directories, &dirs); for (l = dirs; l != NULL; l = l->next) { directory = NEMO_DIRECTORY (l->data); emit_change_signals_for_all_files (directory); nemo_directory_unref (directory); } g_list_free (dirs); } static void async_state_changed_one (gpointer key, gpointer value, gpointer user_data) { NemoDirectory *directory; g_assert (key != NULL); g_assert (NEMO_IS_DIRECTORY (value)); g_assert (user_data == NULL); directory = NEMO_DIRECTORY (value); nemo_directory_async_state_changed (directory); emit_change_signals_for_all_files (directory); } static void async_data_preference_changed_callback (gpointer callback_data) { g_assert (callback_data == NULL); /* Preference involving fetched async data has changed, so * we have to kick off refetching all async data, and tell * each file that it (might have) changed. */ g_hash_table_foreach (directories, async_state_changed_one, NULL); } static void add_preferences_callbacks (void) { nemo_global_preferences_init (); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_HIDDEN_FILES, G_CALLBACK(filtering_changed_callback), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS, G_CALLBACK (async_data_preference_changed_callback), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DATE_FORMAT, G_CALLBACK(async_data_preference_changed_callback), NULL); } /** * nemo_directory_get_by_uri: * @uri: URI of directory to get. * * Get a directory given a uri. * Creates the appropriate subclass given the uri mappings. * Returns a referenced object, not a floating one. Unref when finished. * If two windows are viewing the same uri, the directory object is shared. */ NemoDirectory * nemo_directory_get_internal (GFile *location, gboolean create) { NemoDirectory *directory; /* Create the hash table first time through. */ if (directories == NULL) { directories = g_hash_table_new (g_file_hash, (GCompareFunc) g_file_equal); add_preferences_callbacks (); } /* If the object is already in the hash table, look it up. */ directory = g_hash_table_lookup (directories, location); if (directory != NULL) { nemo_directory_ref (directory); } else if (create) { /* Create a new directory object instead. */ directory = nemo_directory_new (location); if (directory == NULL) { return NULL; } /* Put it in the hash table. */ g_hash_table_insert (directories, directory->details->location, directory); } return directory; } NemoDirectory * nemo_directory_get (GFile *location) { if (location == NULL) { return NULL; } return nemo_directory_get_internal (location, TRUE); } NemoDirectory * nemo_directory_get_existing (GFile *location) { if (location == NULL) { return NULL; } return nemo_directory_get_internal (location, FALSE); } NemoDirectory * nemo_directory_get_by_uri (const char *uri) { NemoDirectory *directory; GFile *location; if (uri == NULL) { return NULL; } location = g_file_new_for_uri (uri); directory = nemo_directory_get_internal (location, TRUE); g_object_unref (location); return directory; } NemoDirectory * nemo_directory_get_for_file (NemoFile *file) { char *uri; NemoDirectory *directory; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); uri = nemo_file_get_uri (file); directory = nemo_directory_get_by_uri (uri); g_free (uri); return directory; } /* Returns a reffed NemoFile object for this directory. */ NemoFile * nemo_directory_get_corresponding_file (NemoDirectory *directory) { NemoFile *file; char *uri; file = nemo_directory_get_existing_corresponding_file (directory); if (file == NULL) { uri = nemo_directory_get_uri (directory); file = nemo_file_get_by_uri (uri); g_free (uri); } return file; } /* Returns a reffed NemoFile object for this directory, but only if the * NemoFile object has already been created. */ NemoFile * nemo_directory_get_existing_corresponding_file (NemoDirectory *directory) { NemoFile *file; char *uri; file = directory->details->as_file; if (file != NULL) { nemo_file_ref (file); return file; } uri = nemo_directory_get_uri (directory); file = nemo_file_get_existing_by_uri (uri); g_free (uri); return file; } /* nemo_directory_get_name_for_self_as_new_file: * * Get a name to display for the file representing this * directory. This is called only when there's no VFS * directory for this NemoDirectory. */ char * nemo_directory_get_name_for_self_as_new_file (NemoDirectory *directory) { char *directory_uri; char *name, *colon; directory_uri = nemo_directory_get_uri (directory); colon = strchr (directory_uri, ':'); if (colon == NULL || colon == directory_uri) { name = g_strdup (directory_uri); } else { name = g_strndup (directory_uri, colon - directory_uri); } g_free (directory_uri); return name; } char * nemo_directory_get_uri (NemoDirectory *directory) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); return g_file_get_uri (directory->details->location); } GFile * nemo_directory_get_location (NemoDirectory *directory) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); return g_object_ref (directory->details->location); } static NemoDirectory * nemo_directory_new (GFile *location) { NemoDirectory *directory; char *uri; uri = g_file_get_uri (location); if (eel_uri_is_desktop (uri)) { directory = NEMO_DIRECTORY (g_object_new (NEMO_TYPE_DESKTOP_DIRECTORY, NULL)); } else if (eel_uri_is_search (uri)) { directory = NEMO_DIRECTORY (g_object_new (NEMO_TYPE_SEARCH_DIRECTORY, NULL)); } else if (g_str_has_suffix (uri, NEMO_SAVED_SEARCH_EXTENSION)) { directory = NEMO_DIRECTORY (nemo_search_directory_new_from_saved_search (uri)); } else { directory = NEMO_DIRECTORY (g_object_new (NEMO_TYPE_VFS_DIRECTORY, NULL)); } set_directory_location (directory, location); g_free (uri); return directory; } gboolean nemo_directory_is_local (NemoDirectory *directory) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), FALSE); if (directory->details->location == NULL) { return TRUE; } return nemo_directory_is_in_trash (directory) || g_file_is_native (directory->details->location); } gboolean nemo_directory_is_in_trash (NemoDirectory *directory) { g_assert (NEMO_IS_DIRECTORY (directory)); if (directory->details->location == NULL) { return FALSE; } return g_file_has_uri_scheme (directory->details->location, "trash"); } gboolean nemo_directory_is_in_recent (NemoDirectory *directory) { g_assert (NEMO_IS_DIRECTORY (directory)); if (directory->details->location == NULL) { return FALSE; } return g_file_has_uri_scheme (directory->details->location, "recent"); } gboolean nemo_directory_is_in_admin (NemoDirectory *directory) { g_assert (NEMO_IS_DIRECTORY (directory)); if (directory->details->location == NULL) { return FALSE; } return g_file_has_uri_scheme (directory->details->location, "admin"); } gboolean nemo_directory_are_all_files_seen (NemoDirectory *directory) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), FALSE); return NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->are_all_files_seen (directory); } static void add_to_hash_table (NemoDirectory *directory, NemoFile *file, GList *node) { const char *name; name = eel_ref_str_peek (file->details->name); g_assert (node != NULL); g_assert (g_hash_table_lookup (directory->details->file_hash, name) == NULL); g_hash_table_insert (directory->details->file_hash, (char *) name, node); } static GList * extract_from_hash_table (NemoDirectory *directory, NemoFile *file) { const char *name; GList *node; name = eel_ref_str_peek (file->details->name); if (name == NULL) { return NULL; } /* Find the list node in the hash table. */ node = g_hash_table_lookup (directory->details->file_hash, name); g_hash_table_remove (directory->details->file_hash, name); return node; } void nemo_directory_add_file (NemoDirectory *directory, NemoFile *file) { GList *node; gboolean add_to_work_queue; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (NEMO_IS_FILE (file)); g_assert (file->details->name != NULL); /* Add to list. */ node = g_list_prepend (directory->details->file_list, file); directory->details->file_list = node; /* Add to hash table. */ add_to_hash_table (directory, file, node); directory->details->confirmed_file_count++; add_to_work_queue = FALSE; if (nemo_directory_is_file_list_monitored (directory)) { /* Ref if we are monitoring, since monitoring owns the file list. */ nemo_file_ref (file); add_to_work_queue = TRUE; } else if (nemo_directory_has_active_request_for_file (directory, file)) { /* We're waiting for the file in a call_when_ready. Make sure we add the file to the work queue so that said waiter won't wait forever for e.g. all files in the directory to be done */ add_to_work_queue = TRUE; } if (add_to_work_queue) { nemo_directory_add_file_to_work_queue (directory, file); } } void nemo_directory_remove_file (NemoDirectory *directory, NemoFile *file) { GList *node; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (NEMO_IS_FILE (file)); g_assert (file->details->name != NULL); /* Find the list node in the hash table. */ node = extract_from_hash_table (directory, file); g_assert (node != NULL); g_assert (node->data == file); /* Remove the item from the list. */ directory->details->file_list = g_list_remove_link (directory->details->file_list, node); g_list_free_1 (node); nemo_directory_remove_file_from_work_queue (directory, file); if (!file->details->unconfirmed) { directory->details->confirmed_file_count--; } /* Unref if we are monitoring. */ if (nemo_directory_is_file_list_monitored (directory)) { nemo_file_unref (file); } } GList * nemo_directory_begin_file_name_change (NemoDirectory *directory, NemoFile *file) { /* Find the list node in the hash table. */ return extract_from_hash_table (directory, file); } void nemo_directory_end_file_name_change (NemoDirectory *directory, NemoFile *file, GList *node) { /* Add the list node to the hash table. */ if (node != NULL) { add_to_hash_table (directory, file, node); } } NemoFile * nemo_directory_find_file_by_name (NemoDirectory *directory, const char *name) { GList *node; g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); g_return_val_if_fail (name != NULL, NULL); node = g_hash_table_lookup (directory->details->file_hash, name); return node == NULL ? NULL : NEMO_FILE (node->data); } /* "." for the directory-as-file, otherwise the filename */ NemoFile * nemo_directory_find_file_by_internal_filename (NemoDirectory *directory, const char *internal_filename) { NemoFile *result; if (g_strcmp0 (internal_filename, ".") == 0) { result = nemo_directory_get_existing_corresponding_file (directory); if (result != NULL) { nemo_file_unref (result); } } else { result = nemo_directory_find_file_by_name (directory, internal_filename); } return result; } void nemo_directory_emit_files_added (NemoDirectory *directory, GList *added_files) { if (added_files != NULL) { g_signal_emit (directory, signals[FILES_ADDED], 0, added_files); } } void nemo_directory_emit_files_changed (NemoDirectory *directory, GList *changed_files) { if (changed_files != NULL) { g_signal_emit (directory, signals[FILES_CHANGED], 0, changed_files); } } void nemo_directory_emit_change_signals (NemoDirectory *directory, GList *changed_files) { GList *p; for (p = changed_files; p != NULL; p = p->next) { nemo_file_emit_changed (p->data); } nemo_directory_emit_files_changed (directory, changed_files); } void nemo_directory_emit_done_loading (NemoDirectory *directory) { g_signal_emit (directory, signals[DONE_LOADING], 0); } void nemo_directory_emit_load_error (NemoDirectory *directory, GError *error) { g_signal_emit (directory, signals[LOAD_ERROR], 0, error); } /* Return a directory object for this one's parent. */ static NemoDirectory * get_parent_directory (GFile *location) { NemoDirectory *directory; GFile *parent; parent = g_file_get_parent (location); if (parent) { directory = nemo_directory_get_internal (parent, TRUE); g_object_unref (parent); return directory; } return NULL; } /* If a directory object exists for this one's parent, then * return it, otherwise return NULL. */ static NemoDirectory * get_parent_directory_if_exists (GFile *location) { NemoDirectory *directory; GFile *parent; parent = g_file_get_parent (location); if (parent) { directory = nemo_directory_get_internal (parent, FALSE); g_object_unref (parent); return directory; } return NULL; } static void hash_table_list_prepend (GHashTable *table, gconstpointer key, gpointer data) { GList *list; list = g_hash_table_lookup (table, key); list = g_list_prepend (list, data); g_hash_table_insert (table, (gpointer) key, list); } static void call_files_added_free_list (gpointer key, gpointer value, gpointer user_data) { g_assert (NEMO_IS_DIRECTORY (key)); g_assert (value != NULL); g_assert (user_data == NULL); g_signal_emit (key, signals[FILES_ADDED], 0, value); g_list_free (value); } static void call_files_changed_common (NemoDirectory *directory, GList *file_list) { GList *node; NemoFile *file; for (node = file_list; node != NULL; node = node->next) { file = node->data; if (file->details->directory == directory) { nemo_directory_add_file_to_work_queue (directory, file); } } nemo_directory_async_state_changed (directory); nemo_directory_emit_change_signals (directory, file_list); } static void call_files_changed_free_list (gpointer key, gpointer value, gpointer user_data) { g_assert (value != NULL); g_assert (user_data == NULL); call_files_changed_common (NEMO_DIRECTORY (key), value); g_list_free (value); } static void call_files_changed_unref_free_list (gpointer key, gpointer value, gpointer user_data) { g_assert (value != NULL); g_assert (user_data == NULL); call_files_changed_common (NEMO_DIRECTORY (key), value); nemo_file_list_free (value); } static void call_get_file_info_free_list (gpointer key, gpointer value, gpointer user_data) { NemoDirectory *directory; GList *files; g_assert (NEMO_IS_DIRECTORY (key)); g_assert (value != NULL); g_assert (user_data == NULL); directory = key; files = value; nemo_directory_get_info_for_new_files (directory, files); g_list_foreach (files, (GFunc) g_object_unref, NULL); g_list_free (files); } static void invalidate_count_and_unref (gpointer key, gpointer value, gpointer user_data) { g_assert (NEMO_IS_DIRECTORY (key)); g_assert (value == key); g_assert (user_data == NULL); nemo_directory_invalidate_count_and_mime_list (key); nemo_directory_unref (key); } static void collect_parent_directories (GHashTable *hash_table, NemoDirectory *directory) { g_assert (hash_table != NULL); g_assert (NEMO_IS_DIRECTORY (directory)); if (g_hash_table_lookup (hash_table, directory) == NULL) { nemo_directory_ref (directory); g_hash_table_insert (hash_table, directory, directory); } } void nemo_directory_notify_files_added (GList *files) { GHashTable *added_lists; GList *p; NemoDirectory *directory; GHashTable *parent_directories; NemoFile *file; GFile *location, *parent; /* Make a list of added files in each directory. */ added_lists = g_hash_table_new (NULL, NULL); /* Make a list of parent directories that will need their counts updated. */ parent_directories = g_hash_table_new (NULL, NULL); for (p = files; p != NULL; p = p->next) { location = p->data; /* See if the directory is already known. */ directory = get_parent_directory_if_exists (location); if (directory == NULL) { /* In case the directory is not being * monitored, but the corresponding file is, * we must invalidate it's item count. */ file = NULL; parent = g_file_get_parent (location); if (parent) { file = nemo_file_get_existing (parent); g_object_unref (parent); } if (file != NULL) { nemo_file_invalidate_count_and_mime_list (file); nemo_file_unref (file); } continue; } collect_parent_directories (parent_directories, directory); /* If no one is monitoring files in the directory, nothing to do. */ if (!nemo_directory_is_file_list_monitored (directory)) { nemo_directory_unref (directory); continue; } file = nemo_file_get_existing (location); /* We check is_added here, because the file could have been added * to the directory by a nemo_file_get() but not gotten * files_added emitted */ if (file && file->details->is_added) { /* A file already exists, it was probably renamed. * If it was renamed this could be ignored, but * queue a change just in case */ nemo_file_changed (file); nemo_file_unref (file); } else { hash_table_list_prepend (added_lists, directory, g_object_ref (location)); } nemo_directory_unref (directory); } /* Now get file info for the new files. This creates NemoFile * objects for the new files, and sends out a files_added signal. */ g_hash_table_foreach (added_lists, call_get_file_info_free_list, NULL); g_hash_table_destroy (added_lists); /* Invalidate count for each parent directory. */ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL); g_hash_table_destroy (parent_directories); } static void g_file_pair_free (GFilePair *pair) { g_object_unref (pair->to); g_object_unref (pair->from); g_free (pair); } static GList * uri_pairs_to_file_pairs (GList *uri_pairs) { GList *l, *file_pair_list; GFilePair *file_pair; URIPair *uri_pair; file_pair_list = NULL; for (l = uri_pairs; l != NULL; l = l->next) { uri_pair = l->data; file_pair = g_new (GFilePair, 1); file_pair->from = g_file_new_for_uri (uri_pair->from_uri); file_pair->to = g_file_new_for_uri (uri_pair->to_uri); file_pair_list = g_list_prepend (file_pair_list, file_pair); } return g_list_reverse (file_pair_list); } void nemo_directory_notify_files_added_by_uri (GList *uris) { GList *files; files = nemo_file_list_from_uris (uris); nemo_directory_notify_files_added (files); g_list_free_full (files, g_object_unref); } void nemo_directory_notify_files_changed (GList *files) { GHashTable *changed_lists; GList *node; GFile *location; GFile *parent; NemoDirectory *dir; NemoFile *file; /* Make a list of changed files in each directory. */ changed_lists = g_hash_table_new (NULL, NULL); /* Go through all the notifications. */ for (node = files; node != NULL; node = node->next) { location = node->data; /* Find the file. */ file = nemo_file_get_existing (location); if (file != NULL) { /* Tell it to re-get info now, and later emit * a changed signal. */ file->details->file_info_is_up_to_date = FALSE; file->details->link_info_is_up_to_date = FALSE; nemo_file_invalidate_extension_info_internal (file); hash_table_list_prepend (changed_lists, file->details->directory, file); } else { parent = g_file_get_parent (location); dir = nemo_directory_get_existing (parent); if (dir != NULL && dir->details->new_files_in_progress != NULL && files != dir->details->new_files_in_progress_changes) { dir->details->new_files_in_progress_changes = g_list_prepend (dir->details->new_files_in_progress_changes, g_object_ref (location)); } if (dir != NULL) { nemo_directory_unref (dir); } if (parent != NULL) { g_object_unref (parent); } } } /* Now send out the changed signals. */ g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL); g_hash_table_destroy (changed_lists); } void nemo_directory_notify_files_changed_by_uri (GList *uris) { GList *files; files = nemo_file_list_from_uris (uris); nemo_directory_notify_files_changed (files); g_list_free_full (files, g_object_unref); } void nemo_directory_notify_files_removed (GList *files) { GHashTable *changed_lists; GList *p; NemoDirectory *directory; GHashTable *parent_directories; NemoFile *file; GFile *location; /* Make a list of changed files in each directory. */ changed_lists = g_hash_table_new (NULL, NULL); /* Make a list of parent directories that will need their counts updated. */ parent_directories = g_hash_table_new (NULL, NULL); /* Go through all the notifications. */ for (p = files; p != NULL; p = p->next) { location = p->data; /* Update file count for parent directory if anyone might care. */ directory = get_parent_directory_if_exists (location); if (directory != NULL) { collect_parent_directories (parent_directories, directory); nemo_directory_unref (directory); } /* Find the file. */ file = nemo_file_get_existing (location); if (file != NULL && !nemo_file_rename_in_progress (file)) { /* Mark it gone and prepare to send the changed signal. */ nemo_file_mark_gone (file); hash_table_list_prepend (changed_lists, file->details->directory, nemo_file_ref (file)); } nemo_file_unref (file); } /* Now send out the changed signals. */ g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL); g_hash_table_destroy (changed_lists); /* Invalidate count for each parent directory. */ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL); g_hash_table_destroy (parent_directories); } void nemo_directory_notify_files_removed_by_uri (GList *uris) { GList *files; files = nemo_file_list_from_uris (uris); nemo_directory_notify_files_changed (files); g_list_free_full (files, g_object_unref); } static void set_directory_location (NemoDirectory *directory, GFile *location) { if (directory->details->location) { g_object_unref (directory->details->location); } directory->details->location = g_object_ref (location); } static void change_directory_location (NemoDirectory *directory, GFile *new_location) { /* I believe it's impossible for a self-owned file/directory * to be moved. But if that did somehow happen, this function * wouldn't do enough to handle it. */ g_assert (directory->details->as_file == NULL); g_hash_table_remove (directories, directory->details->location); set_directory_location (directory, new_location); g_hash_table_insert (directories, directory->details->location, directory); } typedef struct { GFile *container; GList *directories; } CollectData; static void collect_directories_by_container (gpointer key, gpointer value, gpointer callback_data) { NemoDirectory *directory; CollectData *collect_data; GFile *location; location = (GFile *) key; directory = NEMO_DIRECTORY (value); collect_data = (CollectData *) callback_data; if (g_file_has_prefix (location, collect_data->container) || g_file_equal (collect_data->container, location)) { nemo_directory_ref (directory); collect_data->directories = g_list_prepend (collect_data->directories, directory); } } static GList * nemo_directory_moved_internal (GFile *old_location, GFile *new_location) { CollectData collection; NemoDirectory *directory; GList *node, *affected_files; GFile *new_directory_location; char *relative_path; collection.container = old_location; collection.directories = NULL; g_hash_table_foreach (directories, collect_directories_by_container, &collection); affected_files = NULL; for (node = collection.directories; node != NULL; node = node->next) { directory = NEMO_DIRECTORY (node->data); new_directory_location = NULL; if (g_file_equal (directory->details->location, old_location)) { new_directory_location = g_object_ref (new_location); } else { relative_path = g_file_get_relative_path (old_location, directory->details->location); if (relative_path != NULL) { new_directory_location = g_file_resolve_relative_path (new_location, relative_path); g_free (relative_path); } } if (new_directory_location) { change_directory_location (directory, new_directory_location); g_object_unref (new_directory_location); /* Collect affected files. */ if (directory->details->as_file != NULL) { affected_files = g_list_prepend (affected_files, nemo_file_ref (directory->details->as_file)); } affected_files = g_list_concat (affected_files, nemo_file_list_copy (directory->details->file_list)); } nemo_directory_unref (directory); } g_list_free (collection.directories); return affected_files; } void nemo_directory_moved (const char *old_uri, const char *new_uri) { GList *list, *node; GHashTable *hash; NemoFile *file; GFile *old_location; GFile *new_location; hash = g_hash_table_new (NULL, NULL); old_location = g_file_new_for_uri (old_uri); new_location = g_file_new_for_uri (new_uri); list = nemo_directory_moved_internal (old_location, new_location); for (node = list; node != NULL; node = node->next) { file = NEMO_FILE (node->data); hash_table_list_prepend (hash, file->details->directory, nemo_file_ref (file)); } nemo_file_list_free (list); g_object_unref (old_location); g_object_unref (new_location); g_hash_table_foreach (hash, call_files_changed_unref_free_list, NULL); g_hash_table_destroy (hash); } void nemo_directory_notify_files_moved (GList *file_pairs) { GList *p, *affected_files, *node; GFilePair *pair; NemoFile *file; NemoDirectory *old_directory, *new_directory; GHashTable *parent_directories; GList *new_files_list, *unref_list; GHashTable *added_lists, *changed_lists; char *name; NemoFileAttributes cancel_attributes; GFile *to_location, *from_location; /* Make a list of added and changed files in each directory. */ new_files_list = NULL; added_lists = g_hash_table_new (NULL, NULL); changed_lists = g_hash_table_new (NULL, NULL); unref_list = NULL; /* Make a list of parent directories that will need their counts updated. */ parent_directories = g_hash_table_new (NULL, NULL); cancel_attributes = nemo_file_get_all_attributes (); for (p = file_pairs; p != NULL; p = p->next) { pair = p->data; from_location = pair->from; to_location = pair->to; /* Handle overwriting a file. */ file = nemo_file_get_existing (to_location); if (file != NULL) { /* Mark it gone and prepare to send the changed signal. */ nemo_file_mark_gone (file); new_directory = file->details->directory; hash_table_list_prepend (changed_lists, new_directory, file); collect_parent_directories (parent_directories, new_directory); } /* Update any directory objects that are affected. */ affected_files = nemo_directory_moved_internal (from_location, to_location); for (node = affected_files; node != NULL; node = node->next) { file = NEMO_FILE (node->data); hash_table_list_prepend (changed_lists, file->details->directory, file); } unref_list = g_list_concat (unref_list, affected_files); /* Move an existing file. */ file = nemo_file_get_existing (from_location); if (file == NULL) { /* Handle this as if it was a new file. */ new_files_list = g_list_prepend (new_files_list, to_location); } else { /* Handle notification in the old directory. */ old_directory = file->details->directory; collect_parent_directories (parent_directories, old_directory); /* Cancel loading of attributes in the old directory */ nemo_directory_cancel_loading_file_attributes (old_directory, file, cancel_attributes); /* Locate the new directory. */ new_directory = get_parent_directory (to_location); collect_parent_directories (parent_directories, new_directory); /* We can unref now -- new_directory is in the * parent directories list so it will be * around until the end of this function * anyway. */ nemo_directory_unref (new_directory); /* Update the file's name and directory. */ name = g_file_get_basename (to_location); nemo_file_update_name_and_directory (file, name, new_directory); g_free (name); /* Update file attributes */ nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO); hash_table_list_prepend (changed_lists, old_directory, file); if (old_directory != new_directory) { hash_table_list_prepend (added_lists, new_directory, file); } /* Unref each file once to balance out nemo_file_get_by_uri. */ unref_list = g_list_prepend (unref_list, file); } } /* Now send out the changed and added signals for existing file objects. */ g_hash_table_foreach (changed_lists, call_files_changed_free_list, NULL); g_hash_table_destroy (changed_lists); g_hash_table_foreach (added_lists, call_files_added_free_list, NULL); g_hash_table_destroy (added_lists); /* Let the file objects go. */ nemo_file_list_free (unref_list); /* Invalidate count for each parent directory. */ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL); g_hash_table_destroy (parent_directories); /* Separate handling for brand new file objects. */ nemo_directory_notify_files_added (new_files_list); g_list_free (new_files_list); } void nemo_directory_notify_files_moved_by_uri (GList *uri_pairs) { GList *file_pairs; file_pairs = uri_pairs_to_file_pairs (uri_pairs); nemo_directory_notify_files_moved (file_pairs); g_list_foreach (file_pairs, (GFunc)g_file_pair_free, NULL); g_list_free (file_pairs); } void nemo_directory_schedule_position_set (GList *position_setting_list) { GList *p; const NemoFileChangesQueuePosition *item; NemoFile *file; time_t now; time (&now); for (p = position_setting_list; p != NULL; p = p->next) { item = (NemoFileChangesQueuePosition *) p->data; file = nemo_file_get (item->location); if (item->set) { nemo_file_set_position (file, item->point.x, item->point.y); } else { nemo_file_set_position (file, -1, -1); } if (item->set) { nemo_file_set_monitor_number (file, item->monitor); } else { nemo_file_set_monitor_number (file, -1); } nemo_file_set_time_metadata (file, NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP, UNDEFINED_TIME); nemo_file_unref (file); } } gboolean nemo_directory_contains_file (NemoDirectory *directory, NemoFile *file) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), FALSE); g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (nemo_file_is_gone (file)) { return FALSE; } return NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->contains_file (directory, file); } char * nemo_directory_get_file_uri (NemoDirectory *directory, const char *file_name) { GFile *child; char *result; g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); g_return_val_if_fail (file_name != NULL, NULL); result = NULL; child = g_file_get_child (directory->details->location, file_name); result = g_file_get_uri (child); g_object_unref (child); return result; } void nemo_directory_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_all_files, NemoDirectoryCallback callback, gpointer callback_data) { g_return_if_fail (NEMO_IS_DIRECTORY (directory)); g_return_if_fail (callback != NULL); NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->call_when_ready (directory, file_attributes, wait_for_all_files, callback, callback_data); } void nemo_directory_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data) { g_return_if_fail (NEMO_IS_DIRECTORY (directory)); g_return_if_fail (callback != NULL); NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->cancel_callback (directory, callback, callback_data); } void nemo_directory_file_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { g_return_if_fail (NEMO_IS_DIRECTORY (directory)); g_return_if_fail (client != NULL); NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->file_monitor_add (directory, client, monitor_hidden_files, file_attributes, callback, callback_data); } void nemo_directory_file_monitor_remove (NemoDirectory *directory, gconstpointer client) { g_return_if_fail (NEMO_IS_DIRECTORY (directory)); g_return_if_fail (client != NULL); NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->file_monitor_remove (directory, client); } void nemo_directory_force_reload (NemoDirectory *directory) { g_return_if_fail (NEMO_IS_DIRECTORY (directory)); NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->force_reload (directory); } gboolean nemo_directory_is_not_empty (NemoDirectory *directory) { g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), FALSE); return NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->is_not_empty (directory); } static gboolean is_tentative (gpointer data, gpointer callback_data) { NemoFile *file; g_assert (callback_data == NULL); file = NEMO_FILE (data); /* Avoid returning files with !is_added, because these * will later be sent with the files_added signal, and a * user doing get_file_list + files_added monitoring will * then see the file twice */ return !file->details->got_file_info || !file->details->is_added; } GList * nemo_directory_get_file_list (NemoDirectory *directory) { return NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->get_file_list (directory); } static GList * real_get_file_list (NemoDirectory *directory) { GList *tentative_files, *non_tentative_files; tentative_files = eel_g_list_partition (g_list_copy (directory->details->file_list), is_tentative, NULL, &non_tentative_files); g_list_free (tentative_files); nemo_file_list_ref (non_tentative_files); return non_tentative_files; } static gboolean real_is_editable (NemoDirectory *directory) { return TRUE; } gboolean nemo_directory_is_editable (NemoDirectory *directory) { return NEMO_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->is_editable (directory); } GList * nemo_directory_match_pattern (NemoDirectory *directory, const char *pattern) { GList *files, *l, *ret; GPatternSpec *spec; ret = NULL; spec = g_pattern_spec_new (pattern); files = nemo_directory_get_file_list (directory); for (l = files; l; l = l->next) { NemoFile *file; char *name; file = NEMO_FILE (l->data); name = nemo_file_get_display_name (file); if (g_pattern_match_string (spec, name)) { ret = g_list_prepend(ret, nemo_file_ref (file)); } g_free (name); } g_pattern_spec_free (spec); nemo_file_list_free (files); return ret; } /** * nemo_directory_list_ref * * Ref all the directories in a list. * @list: GList of directories. **/ GList * nemo_directory_list_ref (GList *list) { g_list_foreach (list, (GFunc) nemo_directory_ref, NULL); return list; } /** * nemo_directory_list_unref * * Unref all the directories in a list. * @list: GList of directories. **/ void nemo_directory_list_unref (GList *list) { g_list_foreach (list, (GFunc) nemo_directory_unref, NULL); } /** * nemo_directory_list_free * * Free a list of directories after unrefing them. * @list: GList of directories. **/ void nemo_directory_list_free (GList *list) { nemo_directory_list_unref (list); g_list_free (list); } /** * nemo_directory_list_copy * * Copy the list of directories, making a new ref of each, * @list: GList of directories. **/ GList * nemo_directory_list_copy (GList *list) { return g_list_copy (nemo_directory_list_ref (list)); } static int compare_by_uri (NemoDirectory *a, NemoDirectory *b) { char *uri_a, *uri_b; int res; uri_a = g_file_get_uri (a->details->location); uri_b = g_file_get_uri (b->details->location); res = strcmp (uri_a, uri_b); g_free (uri_a); g_free (uri_b); return res; } static int compare_by_uri_cover (gconstpointer a, gconstpointer b) { return compare_by_uri (NEMO_DIRECTORY (a), NEMO_DIRECTORY (b)); } /** * nemo_directory_list_sort_by_uri * * Sort the list of directories by directory uri. * @list: GList of directories. **/ GList * nemo_directory_list_sort_by_uri (GList *list) { return g_list_sort (list, compare_by_uri_cover); } gboolean nemo_directory_is_desktop_directory (NemoDirectory *directory) { if (directory->details->location == NULL) { return FALSE; } return nemo_is_desktop_directory (directory->details->location); } void nemo_directory_set_show_thumbnails (NemoDirectory *directory, gboolean show_thumbnails) { NemoFile *file; file = nemo_file_get(directory->details->location); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_SHOW_THUMBNAILS, FALSE, show_thumbnails); nemo_directory_force_reload (directory); } #if !defined (NEMO_OMIT_SELF_CHECK) #include #include "nemo-file-attributes.h" static int data_dummy; static gboolean got_files_flag; static void got_files_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (g_list_length (files) > 10); g_assert (callback_data == &data_dummy); got_files_flag = TRUE; } /* Return the number of extant NemoDirectories */ int nemo_directory_number_outstanding (void) { return directories ? g_hash_table_size (directories) : 0; } void nemo_self_check_directory (void) { NemoDirectory *directory; NemoFile *file; directory = nemo_directory_get_by_uri ("file:///etc"); file = nemo_file_get_by_uri ("file:///etc/passwd"); EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1); nemo_directory_file_monitor_add (directory, &data_dummy, TRUE, 0, NULL, NULL); /* FIXME: these need to be updated to the new metadata infrastructure * as make check doesn't pass. nemo_file_set_metadata (file, "test", "default", "value"); EEL_CHECK_STRING_RESULT (nemo_file_get_metadata (file, "test", "default"), "value"); nemo_file_set_boolean_metadata (file, "test_boolean", TRUE, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_boolean_metadata (file, "test_boolean", TRUE), TRUE); nemo_file_set_boolean_metadata (file, "test_boolean", TRUE, FALSE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_boolean_metadata (file, "test_boolean", TRUE), FALSE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_boolean_metadata (NULL, "test_boolean", TRUE), TRUE); nemo_file_set_integer_metadata (file, "test_integer", 0, 17); EEL_CHECK_INTEGER_RESULT (nemo_file_get_integer_metadata (file, "test_integer", 0), 17); nemo_file_set_integer_metadata (file, "test_integer", 0, -1); EEL_CHECK_INTEGER_RESULT (nemo_file_get_integer_metadata (file, "test_integer", 0), -1); nemo_file_set_integer_metadata (file, "test_integer", 42, 42); EEL_CHECK_INTEGER_RESULT (nemo_file_get_integer_metadata (file, "test_integer", 42), 42); EEL_CHECK_INTEGER_RESULT (nemo_file_get_integer_metadata (NULL, "test_integer", 42), 42); EEL_CHECK_INTEGER_RESULT (nemo_file_get_integer_metadata (file, "nonexistent_key", 42), 42); */ EEL_CHECK_BOOLEAN_RESULT (nemo_directory_get_by_uri ("file:///etc") == directory, TRUE); nemo_directory_unref (directory); EEL_CHECK_BOOLEAN_RESULT (nemo_directory_get_by_uri ("file:///etc/") == directory, TRUE); nemo_directory_unref (directory); EEL_CHECK_BOOLEAN_RESULT (nemo_directory_get_by_uri ("file:///etc////") == directory, TRUE); nemo_directory_unref (directory); nemo_file_unref (file); nemo_directory_file_monitor_remove (directory, &data_dummy); nemo_directory_unref (directory); while (g_hash_table_size (directories) != 0) { gtk_main_iteration (); } EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0); directory = nemo_directory_get_by_uri ("file:///etc"); got_files_flag = FALSE; nemo_directory_call_when_ready (directory, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_DEEP_COUNTS, TRUE, got_files_callback, &data_dummy); while (!got_files_flag) { gtk_main_iteration (); } EEL_CHECK_BOOLEAN_RESULT (directory->details->file_list == NULL, TRUE); EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1); file = nemo_file_get_by_uri ("file:///etc/passwd"); /* EEL_CHECK_STRING_RESULT (nemo_file_get_metadata (file, "test", "default"), "value"); */ nemo_file_unref (file); nemo_directory_unref (directory); EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0); } #endif /* !NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/libnemo-private/nemo-directory.h000066400000000000000000000255421357442400300206770ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-directory.h: Nemo directory model. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_DIRECTORY_H #define NEMO_DIRECTORY_H #include #include #include /* NemoDirectory is a class that manages the model for a directory, real or virtual, for Nemo, mainly the file-manager component. The directory is responsible for managing both real data and cached metadata. On top of the file system independence provided by gio, the directory object also provides: 1) A synchronization framework, which notifies via signals as the set of known files changes. 2) An abstract interface for getting attributes and performing operations on files. */ #define NEMO_TYPE_DIRECTORY nemo_directory_get_type() #define NEMO_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DIRECTORY, NemoDirectory)) #define NEMO_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DIRECTORY, NemoDirectoryClass)) #define NEMO_IS_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DIRECTORY)) #define NEMO_IS_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DIRECTORY)) #define NEMO_DIRECTORY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DIRECTORY, NemoDirectoryClass)) /* NemoFile is defined both here and in nemo-file.h. */ #ifndef NEMO_FILE_DEFINED #define NEMO_FILE_DEFINED typedef struct NemoFile NemoFile; #endif typedef struct NemoDirectoryDetails NemoDirectoryDetails; typedef struct { GObject object; NemoDirectoryDetails *details; } NemoDirectory; typedef void (*NemoDirectoryCallback) (NemoDirectory *directory, GList *files, gpointer callback_data); typedef struct { GObjectClass parent_class; /*** Notification signals for clients to connect to. ***/ /* The files_added signal is emitted as the directory model * discovers new files. */ void (* files_added) (NemoDirectory *directory, GList *added_files); /* The files_changed signal is emitted as changes occur to * existing files that are noticed by the synchronization framework, * including when an old file has been deleted. When an old file * has been deleted, this is the last chance to forget about these * file objects, which are about to be unref'd. Use a call to * nemo_file_is_gone () to test for this case. */ void (* files_changed) (NemoDirectory *directory, GList *changed_files); /* The done_loading signal is emitted when a directory load * request completes. This is needed because, at least in the * case where the directory is empty, the caller will receive * no kind of notification at all when a directory load * initiated by `nemo_directory_file_monitor_add' completes. */ void (* done_loading) (NemoDirectory *directory); void (* load_error) (NemoDirectory *directory, GError *error); /*** Virtual functions for subclasses to override. ***/ gboolean (* contains_file) (NemoDirectory *directory, NemoFile *file); void (* call_when_ready) (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback callback, gpointer callback_data); void (* cancel_callback) (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data); void (* file_monitor_add) (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes monitor_attributes, NemoDirectoryCallback initial_files_callback, gpointer callback_data); void (* file_monitor_remove) (NemoDirectory *directory, gconstpointer client); void (* force_reload) (NemoDirectory *directory); gboolean (* are_all_files_seen) (NemoDirectory *directory); gboolean (* is_not_empty) (NemoDirectory *directory); /* get_file_list is a function pointer that subclasses may override to * customize collecting the list of files in a directory. * For example, the NemoDesktopDirectory overrides this so that it can * merge together the list of files in the $HOME/Desktop directory with * the list of standard icons (Computer, Home, Trash) on the desktop. */ GList * (* get_file_list) (NemoDirectory *directory); /* Should return FALSE if the directory is read-only and doesn't * allow setting of metadata. * An example of this is the search directory. */ gboolean (* is_editable) (NemoDirectory *directory); } NemoDirectoryClass; /* Basic GObject requirements. */ GType nemo_directory_get_type (void); /* Get a directory given a uri. * Creates the appropriate subclass given the uri mappings. * Returns a referenced object, not a floating one. Unref when finished. * If two windows are viewing the same uri, the directory object is shared. */ NemoDirectory *nemo_directory_get (GFile *location); NemoDirectory *nemo_directory_get_by_uri (const char *uri); NemoDirectory *nemo_directory_get_for_file (NemoFile *file); /* Covers for g_object_ref and g_object_unref that provide two conveniences: * 1) Using these is type safe. * 2) You are allowed to call these with NULL, */ NemoDirectory *nemo_directory_ref (NemoDirectory *directory); void nemo_directory_unref (NemoDirectory *directory); /* Access to a URI. */ char * nemo_directory_get_uri (NemoDirectory *directory); GFile * nemo_directory_get_location (NemoDirectory *directory); /* Is this file still alive and in this directory? */ gboolean nemo_directory_contains_file (NemoDirectory *directory, NemoFile *file); /* Get the uri of the file in the directory, NULL if not found */ char * nemo_directory_get_file_uri (NemoDirectory *directory, const char *file_name); /* Get (and ref) a NemoFile object for this directory. */ NemoFile * nemo_directory_get_corresponding_file (NemoDirectory *directory); /* Waiting for data that's read asynchronously. * The file attribute and metadata keys are for files in the directory. */ void nemo_directory_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_all_files, NemoDirectoryCallback callback, gpointer callback_data); void nemo_directory_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data); /* Monitor the files in a directory. */ void nemo_directory_file_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes attributes, NemoDirectoryCallback initial_files_callback, gpointer callback_data); void nemo_directory_file_monitor_remove (NemoDirectory *directory, gconstpointer client); void nemo_directory_force_reload (NemoDirectory *directory); /* Get a list of all files currently known in the directory. */ GList * nemo_directory_get_file_list (NemoDirectory *directory); GList * nemo_directory_match_pattern (NemoDirectory *directory, const char *glob); /* Return true if the directory has information about all the files. * This will be false until the directory has been read at least once. */ gboolean nemo_directory_are_all_files_seen (NemoDirectory *directory); /* Return true if the directory is local. */ gboolean nemo_directory_is_local (NemoDirectory *directory); gboolean nemo_directory_is_in_trash (NemoDirectory *directory); gboolean nemo_directory_is_in_recent (NemoDirectory *directory); gboolean nemo_directory_is_in_admin (NemoDirectory *directory); /* Return false if directory contains anything besides a Nemo metafile. * Only valid if directory is monitored. Used by the Trash monitor. */ gboolean nemo_directory_is_not_empty (NemoDirectory *directory); /* Convenience functions for dealing with a list of NemoDirectory objects that each have a ref. * These are just convenient names for functions that work on lists of GtkObject *. */ GList * nemo_directory_list_ref (GList *directory_list); void nemo_directory_list_unref (GList *directory_list); void nemo_directory_list_free (GList *directory_list); GList * nemo_directory_list_copy (GList *directory_list); GList * nemo_directory_list_sort_by_uri (GList *directory_list); /* Fast way to check if a directory is the desktop directory */ gboolean nemo_directory_is_desktop_directory (NemoDirectory *directory); gboolean nemo_directory_is_editable (NemoDirectory *directory); void nemo_directory_set_show_thumbnails (NemoDirectory *directory, gboolean show_thumbnails); #endif /* NEMO_DIRECTORY_H */ nemo-4.4.2/libnemo-private/nemo-dnd.c000066400000000000000000000654151357442400300174360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-dnd.c - Common Drag & drop handling code shared by the icon container and the list view. Copyright (C) 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Pavel Cisler , Ettore Perazzoli */ #include #include "nemo-dnd.h" #include "nemo-program-choosing.h" #include "nemo-link.h" #include #include #include #include #include #include #include #include #include /* a set of defines stolen from the eel-icon-dnd.c file. * These are in microseconds. */ #define AUTOSCROLL_TIMEOUT_INTERVAL 100 #define AUTOSCROLL_INITIAL_DELAY 100000 /* drag this close to the view edge to start auto scroll*/ #define AUTO_SCROLL_MARGIN 30 /* the smallest amount of auto scroll used when we just enter the autoscroll * margin */ #define MIN_AUTOSCROLL_DELTA 5 /* the largest amount of auto scroll used when we are right over the view * edge */ #define MAX_AUTOSCROLL_DELTA 50 void nemo_drag_init (NemoDragInfo *drag_info, const GtkTargetEntry *drag_types, int drag_type_count, gboolean add_text_targets) { drag_info->target_list = gtk_target_list_new (drag_types, drag_type_count); if (add_text_targets) { gtk_target_list_add_text_targets (drag_info->target_list, NEMO_ICON_DND_TEXT); } drag_info->drop_occured = FALSE; drag_info->need_to_destroy = FALSE; drag_info->source_fs = NULL; drag_info->can_delete_source = FALSE; } void nemo_drag_finalize (NemoDragInfo *drag_info) { gtk_target_list_unref (drag_info->target_list); nemo_drag_destroy_selection_list (drag_info->selection_list); g_free (drag_info->source_fs); drag_info->can_delete_source = FALSE; g_free (drag_info); } /* Functions to deal with NemoDragSelectionItems. */ NemoDragSelectionItem * nemo_drag_selection_item_new (void) { return g_new0 (NemoDragSelectionItem, 1); } static void drag_selection_item_destroy (NemoDragSelectionItem *item) { g_free (item->uri); g_free (item); } void nemo_drag_destroy_selection_list (GList *list) { GList *p; if (list == NULL) return; for (p = list; p != NULL; p = p->next) drag_selection_item_destroy (p->data); g_list_free (list); } char ** nemo_drag_uri_array_from_selection_list (const GList *selection_list) { GList *uri_list; char **uris; uri_list = nemo_drag_uri_list_from_selection_list (selection_list); uris = nemo_drag_uri_array_from_list (uri_list); g_list_free_full (uri_list, g_free); return uris; } GList * nemo_drag_uri_list_from_selection_list (const GList *selection_list) { NemoDragSelectionItem *selection_item; GList *uri_list; const GList *l; uri_list = NULL; for (l = selection_list; l != NULL; l = l->next) { selection_item = (NemoDragSelectionItem *) l->data; if (selection_item->uri != NULL) { uri_list = g_list_prepend (uri_list, g_strdup (selection_item->uri)); } } return g_list_reverse (uri_list); } char ** nemo_drag_uri_array_from_list (const GList *uri_list) { const GList *l; char **uris; int i; if (uri_list == NULL) { return NULL; } uris = g_new0 (char *, g_list_length ((GList *) uri_list)); for (i = 0, l = uri_list; l != NULL; l = l->next) { uris[i++] = g_strdup ((char *) l->data); } uris[i] = NULL; return uris; } GList * nemo_drag_uri_list_from_array (const char **uris) { GList *uri_list; int i; if (uris == NULL) { return NULL; } uri_list = NULL; for (i = 0; uris[i] != NULL; i++) { uri_list = g_list_prepend (uri_list, g_strdup (uris[i])); } return g_list_reverse (uri_list); } GList * nemo_drag_build_selection_list (GtkSelectionData *data) { GList *result; const guchar *p, *oldp; int size; result = NULL; oldp = gtk_selection_data_get_data (data); size = gtk_selection_data_get_length (data); while (size > 0) { NemoDragSelectionItem *item; guint len; /* The list is in the form: name\rx:y:width:height\r\n The geometry information after the first \r is optional. */ /* 1: Decode name. */ p = memchr (oldp, '\r', size); if (p == NULL) { break; } item = nemo_drag_selection_item_new (); len = p - oldp; item->uri = g_malloc (len + 1); memcpy (item->uri, oldp, len); item->uri[len] = 0; p++; if (*p == '\n' || *p == '\0') { result = g_list_prepend (result, item); if (p == 0) { g_warning ("Invalid x-special/gnome-icon-list data received: " "missing newline character."); break; } else { oldp = p + 1; continue; } } size -= p - oldp; oldp = p; /* 2: Decode geometry information. */ item->got_icon_position = sscanf ((const gchar *) p, "%d:%d:%d:%d%*s", &item->icon_x, &item->icon_y, &item->icon_width, &item->icon_height) == 4; if (!item->got_icon_position) { g_warning ("Invalid x-special/gnome-icon-list data received: " "invalid icon position specification."); } result = g_list_prepend (result, item); p = memchr (p, '\r', size); if (p == NULL || p[1] != '\n') { g_warning ("Invalid x-special/gnome-icon-list data received: " "missing newline character."); if (p == NULL) { break; } } else { p += 2; } size -= p - oldp; oldp = p; } return g_list_reverse (result); } static gboolean nemo_drag_file_local_internal (const char *target_uri_string, const char *first_source_uri) { /* check if the first item on the list has target_uri_string as a parent * FIXME: * we should really test each item but that would be slow for large selections * and currently dropped items can only be from the same container */ GFile *target, *item, *parent; gboolean result; result = FALSE; target = g_file_new_for_uri (target_uri_string); /* get the parent URI of the first item in the selection */ item = g_file_new_for_uri (first_source_uri); parent = g_file_get_parent (item); g_object_unref (item); if (parent != NULL) { result = g_file_equal (parent, target); g_object_unref (parent); } g_object_unref (target); return result; } gboolean nemo_drag_uris_local (const char *target_uri, const GList *source_uri_list) { /* must have at least one item */ g_assert (source_uri_list); return nemo_drag_file_local_internal (target_uri, source_uri_list->data); } gboolean nemo_drag_items_local (const char *target_uri_string, const GList *selection_list) { /* must have at least one item */ g_assert (selection_list); return nemo_drag_file_local_internal (target_uri_string, ((NemoDragSelectionItem *)selection_list->data)->uri); } gboolean nemo_drag_items_in_trash (const GList *selection_list) { /* check if the first item on the list is in trash. * FIXME: * we should really test each item but that would be slow for large selections * and currently dropped items can only be from the same container */ return eel_uri_is_trash (((NemoDragSelectionItem *)selection_list->data)->uri); } gboolean nemo_drag_items_on_desktop (const GList *selection_list) { char *uri; GFile *desktop, *item, *parent; gboolean result; /* check if the first item on the list is in trash. * FIXME: * we should really test each item but that would be slow for large selections * and currently dropped items can only be from the same container */ uri = ((NemoDragSelectionItem *)selection_list->data)->uri; if (eel_uri_is_desktop (uri)) { return TRUE; } desktop = nemo_get_desktop_location (); item = g_file_new_for_uri (uri); parent = g_file_get_parent (item); g_object_unref (item); result = FALSE; if (parent) { result = g_file_equal (desktop, parent); g_object_unref (parent); } g_object_unref (desktop); return result; } GdkDragAction nemo_drag_default_drop_action_for_netscape_url (GdkDragContext *context) { /* Mozilla defaults to copy, but unless thats the only allowed thing (enforced by ctrl) we want to LINK */ if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY && gdk_drag_context_get_actions (context) != GDK_ACTION_COPY) { return GDK_ACTION_LINK; } else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE) { /* Don't support move */ return GDK_ACTION_COPY; } return gdk_drag_context_get_suggested_action (context); } static gboolean check_same_fs (NemoFile *target_file, NemoFile *source_file, const gchar *source_fs_for_desktop) { char *target_id, *source_id; gboolean result; result = FALSE; if (target_file != NULL && source_file != NULL) { source_id = nemo_file_get_filesystem_id (source_file); target_id = nemo_file_get_filesystem_id (target_file); if (source_id != NULL && target_id != NULL) { result = (strcmp (source_id, target_id) == 0); } g_free (source_id); g_free (target_id); } else if (target_file != NULL && source_fs_for_desktop != NULL) { target_id = nemo_file_get_filesystem_id (target_file); if (target_id != NULL) { result = (strcmp (source_fs_for_desktop, target_id) == 0); } g_free (target_id); } return result; } static gboolean source_is_deletable (GFile *file) { NemoFile *naut_file; gboolean ret; /* if there's no a cached NemoFile, it returns NULL */ naut_file = nemo_file_get_existing (file); if (naut_file == NULL) { return FALSE; } ret = nemo_file_can_delete (naut_file); nemo_file_unref (naut_file); return ret; } static gboolean uri_contains_desktop (const gchar *uri) { gchar *real_desktop_uri; if (eel_uri_is_desktop (uri)) { return TRUE; } real_desktop_uri = nemo_get_desktop_directory_uri (); if (g_str_has_prefix (uri, real_desktop_uri)) { g_free (real_desktop_uri); return TRUE; } return FALSE; } void nemo_drag_default_drop_action_for_icons (GdkDragContext *context, const char *target_uri_string, const GList *items, int *action, gchar **source_fs, gboolean *can_delete_source) { gboolean same_fs; gboolean target_is_source_parent; gboolean source_deletable; const char *dropped_uri; GFile *target, *dropped, *dropped_directory; GdkDragAction actions; NemoFile *dropped_file, *target_file; if (target_uri_string == NULL) { *action = 0; return; } actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_MOVE | GDK_ACTION_COPY); if (actions == 0) { /* We can't use copy or move, just go with the suggested action. */ *action = gdk_drag_context_get_suggested_action (context); return; } if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) { /* Don't override ask */ *action = gdk_drag_context_get_suggested_action (context); return; } dropped_uri = ((NemoDragSelectionItem *)items->data)->uri; dropped_file = nemo_file_get_existing_by_uri (dropped_uri); /* To/from desktop preparation - since we are separate processes, we don't have the full filesystem * info on the source and destination - we only have the destination info. Creating a NemoFile for it * is an async operation, so here we'll grab the source filesystem type and store it for the duration of * the drag. We can use it to compare below with the destination type to ensure a proper move action - * (we default to copy when we can't confirm source and destination fs types are the same.) */ if (dropped_file == NULL && (uri_contains_desktop (target_uri_string) || uri_contains_desktop (dropped_uri))) { if (*source_fs == NULL) { GFile *source_file; source_file = g_file_new_for_uri (dropped_uri); if (g_file_is_native (source_file)) { GFileInfo *fs_info; GError *error = NULL; fs_info = g_file_query_info (source_file, G_FILE_ATTRIBUTE_ID_FILESYSTEM "," G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, G_FILE_QUERY_INFO_NONE, NULL, &error); if (error != NULL) { g_warning ("Cannot fetch filesystem type for drag involving the desktop: %s", error->message); g_clear_error (&error); } else { if (g_file_info_has_attribute (fs_info, G_FILE_ATTRIBUTE_ID_FILESYSTEM)) { *source_fs = g_strdup (g_file_info_get_attribute_string (fs_info, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); } else { *source_fs = NULL; } if (g_file_info_has_attribute (fs_info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) { *can_delete_source = g_file_info_get_attribute_boolean (fs_info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE); } else { *can_delete_source = FALSE; } } g_object_unref (fs_info); } g_object_unref (source_file); } } target_file = nemo_file_get_existing_by_uri (target_uri_string); /* * Check for trash URI. We do a find_directory for any Trash directory. * Passing 0 permissions as gnome-vfs would override the permissions * passed with 700 while creating .Trash directory */ if (eel_uri_is_trash (target_uri_string)) { /* Only move to Trash */ if (actions & GDK_ACTION_MOVE) { *action = GDK_ACTION_MOVE; } nemo_file_unref (dropped_file); nemo_file_unref (target_file); return; } else if (dropped_file != NULL && nemo_file_is_launcher (dropped_file)) { if (actions & GDK_ACTION_MOVE) { *action = GDK_ACTION_MOVE; } nemo_file_unref (dropped_file); nemo_file_unref (target_file); return; } else if (eel_uri_is_desktop (target_uri_string)) { target = nemo_get_desktop_location (); nemo_file_unref (target_file); target_file = nemo_file_get (target); if (eel_uri_is_desktop (dropped_uri)) { /* Only move to Desktop icons */ if (actions & GDK_ACTION_MOVE) { *action = GDK_ACTION_MOVE; } g_object_unref (target); nemo_file_unref (dropped_file); nemo_file_unref (target_file); return; } } else if (target_file != NULL && nemo_file_is_archive (target_file)) { *action = GDK_ACTION_COPY; nemo_file_unref (dropped_file); nemo_file_unref (target_file); return; } else { target = g_file_new_for_uri (target_uri_string); } same_fs = check_same_fs (target_file, dropped_file, *source_fs); nemo_file_unref (dropped_file); nemo_file_unref (target_file); /* Compare the first dropped uri with the target uri for same fs match. */ dropped = g_file_new_for_uri (dropped_uri); dropped_directory = g_file_get_parent (dropped); target_is_source_parent = FALSE; if (dropped_directory != NULL) { /* If the dropped file is already in the same directory but is in another filesystem we still want to move, not copy as this is then just a move of a mountpoint to another position in the dir */ target_is_source_parent = g_file_equal (dropped_directory, target); g_object_unref (dropped_directory); } source_deletable = source_is_deletable (dropped); if ((same_fs && (source_deletable || *can_delete_source)) || target_is_source_parent || g_file_has_uri_scheme (dropped, "trash")) { if (actions & GDK_ACTION_MOVE) { *action = GDK_ACTION_MOVE; } else { *action = gdk_drag_context_get_suggested_action (context); } } else { if (actions & GDK_ACTION_COPY) { *action = GDK_ACTION_COPY; } else { *action = gdk_drag_context_get_suggested_action (context); } } g_object_unref (target); g_object_unref (dropped); } GdkDragAction nemo_drag_default_drop_action_for_uri_list (GdkDragContext *context, const char *target_uri_string) { if (eel_uri_is_trash (target_uri_string) && (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)) { /* Only move to Trash */ return GDK_ACTION_MOVE; } else { return gdk_drag_context_get_suggested_action (context); } } /* Encode a "x-special/gnome-icon-list" selection. Along with the URIs of the dragged files, this encodes the location and size of each icon relative to the cursor. */ static void add_one_gnome_icon (const char *uri, int x, int y, int w, int h, gpointer data) { GString *result; result = (GString *) data; g_string_append_printf (result, "%s\r%d:%d:%hu:%hu\r\n", uri, x, y, w, h); } /* * Cf. #48423 */ #ifdef THIS_WAS_REALLY_BROKEN static gboolean is_path_that_gnome_uri_list_extract_filenames_can_parse (const char *path) { if (path == NULL || path [0] == '\0') { return FALSE; } /* It strips leading and trailing spaces. So it can't handle * file names with leading and trailing spaces. */ if (g_ascii_isspace (path [0])) { return FALSE; } if (g_ascii_isspace (path [strlen (path) - 1])) { return FALSE; } /* # works as a comment delimiter, and \r and \n are used to * separate the lines, so it can't handle file names with any * of these. */ if (strchr (path, '#') != NULL || strchr (path, '\r') != NULL || strchr (path, '\n') != NULL) { return FALSE; } return TRUE; } /* Encode a "text/plain" selection; this is a broken URL -- just * "file:" with a path after it (no escaping or anything). We are * trying to make the old gnome_uri_list_extract_filenames function * happy, so this is coded to its idiosyncrasises. */ static void add_one_compatible_uri (const char *uri, int x, int y, int w, int h, gpointer data) { GString *result; char *local_path; result = (GString *) data; /* For URLs that do not have a file: scheme, there's no harm * in passing the real URL. But for URLs that do have a file: * scheme, we have to send a URL that will work with the old * gnome-libs function or nothing will be able to understand * it. */ if (!g_str_has_prefix (uri, "file:")) { g_string_append (result, uri); g_string_append (result, "\r\n"); } else { local_path = g_filename_from_uri (uri, NULL, NULL); /* Check for characters that confuse the old * gnome_uri_list_extract_filenames implementation, and just leave * out any paths with those in them. */ if (is_path_that_gnome_uri_list_extract_filenames_can_parse (local_path)) { g_string_append (result, "file:"); g_string_append (result, local_path); g_string_append (result, "\r\n"); } g_free (local_path); } } #endif static void add_one_uri (const char *uri, int x, int y, int w, int h, gpointer data) { GString *result; result = (GString *) data; g_string_append (result, uri); g_string_append (result, "\r\n"); } /* Common function for drag_data_get_callback calls. * Returns FALSE if it doesn't handle drag data */ gboolean nemo_drag_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, gpointer container_context, NemoDragEachSelectedItemIterator each_selected_item_iterator) { GString *result; switch (info) { case NEMO_ICON_DND_GNOME_ICON_LIST: result = g_string_new (NULL); (* each_selected_item_iterator) (add_one_gnome_icon, container_context, result); break; case NEMO_ICON_DND_URI_LIST: case NEMO_ICON_DND_TEXT: result = g_string_new (NULL); (* each_selected_item_iterator) (add_one_uri, container_context, result); break; default: return FALSE; } gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) result->str, result->len); g_string_free (result, TRUE); return TRUE; } typedef struct { GMainLoop *loop; GdkDragAction chosen; } DropActionMenuData; static void menu_deactivate_callback (GtkWidget *menu, gpointer data) { DropActionMenuData *damd; damd = data; if (g_main_loop_is_running (damd->loop)) g_main_loop_quit (damd->loop); } static void drop_action_activated_callback (GtkWidget *menu_item, gpointer data) { DropActionMenuData *damd; damd = data; damd->chosen = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "action")); if (g_main_loop_is_running (damd->loop)) g_main_loop_quit (damd->loop); } static void append_drop_action_menu_item (GtkWidget *menu, const char *text, GdkDragAction action, gboolean sensitive, DropActionMenuData *damd) { GtkWidget *menu_item; menu_item = gtk_menu_item_new_with_mnemonic (text); gtk_widget_set_sensitive (menu_item, sensitive); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); g_object_set_data (G_OBJECT (menu_item), "action", GINT_TO_POINTER (action)); g_signal_connect (menu_item, "activate", G_CALLBACK (drop_action_activated_callback), damd); gtk_widget_show (menu_item); } /* Pops up a menu of actions to perform on dropped files */ GdkDragAction nemo_drag_drop_action_ask (GtkWidget *widget, GdkDragAction actions) { GtkWidget *menu; GtkWidget *menu_item; DropActionMenuData damd; /* Create the menu and set the sensitivity of the items based on the * allowed actions. */ menu = gtk_menu_new (); gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget)); append_drop_action_menu_item (menu, _("_Move Here"), GDK_ACTION_MOVE, (actions & GDK_ACTION_MOVE) != 0, &damd); append_drop_action_menu_item (menu, _("_Copy Here"), GDK_ACTION_COPY, (actions & GDK_ACTION_COPY) != 0, &damd); append_drop_action_menu_item (menu, _("_Link Here"), GDK_ACTION_LINK, (actions & GDK_ACTION_LINK) != 0, &damd); eel_gtk_menu_append_separator (GTK_MENU (menu)); menu_item = gtk_menu_item_new_with_mnemonic (_("Cancel")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_widget_show (menu_item); damd.chosen = 0; damd.loop = g_main_loop_new (NULL, FALSE); g_signal_connect (menu, "deactivate", G_CALLBACK (menu_deactivate_callback), &damd); gtk_grab_add (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); g_main_loop_run (damd.loop); gtk_grab_remove (menu); g_main_loop_unref (damd.loop); g_object_ref_sink (menu); g_object_unref (menu); return damd.chosen; } gboolean nemo_drag_autoscroll_in_scroll_region (GtkWidget *widget) { float x_scroll_delta, y_scroll_delta; nemo_drag_autoscroll_calculate_delta (widget, &x_scroll_delta, &y_scroll_delta); return x_scroll_delta != 0 || y_scroll_delta != 0; } void nemo_drag_autoscroll_calculate_delta (GtkWidget *widget, float *x_scroll_delta, float *y_scroll_delta) { GtkAllocation allocation; GdkDeviceManager *manager; GdkDevice *pointer; int x, y; g_assert (GTK_IS_WIDGET (widget)); manager = gdk_display_get_device_manager (gtk_widget_get_display (widget)); pointer = gdk_device_manager_get_client_pointer (manager); gdk_window_get_device_position (gtk_widget_get_window (widget), pointer, &x, &y, NULL); /* Find out if we are anywhere close to the tree view edges * to see if we need to autoscroll. */ *x_scroll_delta = 0; *y_scroll_delta = 0; if (x < AUTO_SCROLL_MARGIN) { *x_scroll_delta = (float)(x - AUTO_SCROLL_MARGIN); } gtk_widget_get_allocation (widget, &allocation); if (x > allocation.width - AUTO_SCROLL_MARGIN) { if (*x_scroll_delta != 0) { /* Already trying to scroll because of being too close to * the top edge -- must be the window is really short, * don't autoscroll. */ return; } *x_scroll_delta = (float)(x - (allocation.width - AUTO_SCROLL_MARGIN)); } if (y < AUTO_SCROLL_MARGIN) { *y_scroll_delta = (float)(y - AUTO_SCROLL_MARGIN); } if (y > allocation.height - AUTO_SCROLL_MARGIN) { if (*y_scroll_delta != 0) { /* Already trying to scroll because of being too close to * the top edge -- must be the window is really narrow, * don't autoscroll. */ return; } *y_scroll_delta = (float)(y - (allocation.height - AUTO_SCROLL_MARGIN)); } if (*x_scroll_delta == 0 && *y_scroll_delta == 0) { /* no work */ return; } /* Adjust the scroll delta to the proper acceleration values depending on how far * into the sroll margins we are. * FIXME bugzilla.eazel.com 2486: * we could use an exponential acceleration factor here for better feel */ if (*x_scroll_delta != 0) { *x_scroll_delta /= AUTO_SCROLL_MARGIN; *x_scroll_delta *= (MAX_AUTOSCROLL_DELTA - MIN_AUTOSCROLL_DELTA); *x_scroll_delta += MIN_AUTOSCROLL_DELTA; } if (*y_scroll_delta != 0) { *y_scroll_delta /= AUTO_SCROLL_MARGIN; *y_scroll_delta *= (MAX_AUTOSCROLL_DELTA - MIN_AUTOSCROLL_DELTA); *y_scroll_delta += MIN_AUTOSCROLL_DELTA; } } void nemo_drag_autoscroll_start (NemoDragInfo *drag_info, GtkWidget *widget, GSourceFunc callback, gpointer user_data) { if (nemo_drag_autoscroll_in_scroll_region (widget)) { if (drag_info->auto_scroll_timeout_id == 0) { drag_info->waiting_to_autoscroll = TRUE; drag_info->start_auto_scroll_in = g_get_monotonic_time () + AUTOSCROLL_INITIAL_DELAY; drag_info->auto_scroll_timeout_id = g_timeout_add (AUTOSCROLL_TIMEOUT_INTERVAL, callback, user_data); } } else { if (drag_info->auto_scroll_timeout_id != 0) { g_source_remove (drag_info->auto_scroll_timeout_id); drag_info->auto_scroll_timeout_id = 0; } } } void nemo_drag_autoscroll_stop (NemoDragInfo *drag_info) { if (drag_info->auto_scroll_timeout_id != 0) { g_source_remove (drag_info->auto_scroll_timeout_id); drag_info->auto_scroll_timeout_id = 0; } } gboolean nemo_drag_selection_includes_special_link (GList *selection_list) { GList *node; char *uri; for (node = selection_list; node != NULL; node = node->next) { uri = ((NemoDragSelectionItem *) node->data)->uri; if (eel_uri_is_desktop (uri)) { return TRUE; } } return FALSE; } nemo-4.4.2/libnemo-private/nemo-dnd.h000066400000000000000000000150721357442400300174350ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-dnd.h - Common Drag & drop handling code shared by the icon container and the list view. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Pavel Cisler , Ettore Perazzoli */ #ifndef NEMO_DND_H #define NEMO_DND_H #include /* Drag & Drop target names. */ #define NEMO_ICON_DND_GNOME_ICON_LIST_TYPE "x-special/gnome-icon-list" #define NEMO_ICON_DND_URI_LIST_TYPE "text/uri-list" #define NEMO_ICON_DND_NETSCAPE_URL_TYPE "_NETSCAPE_URL" #define NEMO_ICON_DND_BGIMAGE_TYPE "property/bgimage" #define NEMO_ICON_DND_ROOTWINDOW_DROP_TYPE "application/x-rootwindow-drop" #define NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE "XdndDirectSave0" /* XDS Protocol Type */ #define NEMO_ICON_DND_RAW_TYPE "application/octet-stream" /* Item of the drag selection list */ typedef struct { char *uri; gboolean got_icon_position; int icon_x, icon_y; int icon_width, icon_height; } NemoDragSelectionItem; /* Standard Drag & Drop types. */ typedef enum { NEMO_ICON_DND_GNOME_ICON_LIST, NEMO_ICON_DND_URI_LIST, NEMO_ICON_DND_NETSCAPE_URL, NEMO_ICON_DND_TEXT, NEMO_ICON_DND_XDNDDIRECTSAVE, NEMO_ICON_DND_RAW, NEMO_ICON_DND_ROOTWINDOW_DROP } NemoIconDndTargetType; typedef enum { NEMO_DND_ACTION_FIRST = GDK_ACTION_ASK << 1, NEMO_DND_ACTION_SET_AS_BACKGROUND = NEMO_DND_ACTION_FIRST << 0, NEMO_DND_ACTION_SET_AS_FOLDER_BACKGROUND = NEMO_DND_ACTION_FIRST << 1, NEMO_DND_ACTION_SET_AS_GLOBAL_BACKGROUND = NEMO_DND_ACTION_FIRST << 2 } NemoDndAction; /* drag&drop-related information. */ typedef struct { GtkTargetList *target_list; gchar *source_fs; gboolean can_delete_source; /* Stuff saved at "receive data" time needed later in the drag. */ gboolean got_drop_data_type; NemoIconDndTargetType data_type; GtkSelectionData *selection_data; char *direct_save_uri; /* Start of the drag, in window coordinates. */ int start_x, start_y; /* List of NemoDragSelectionItems, representing items being dragged, or NULL * if data about them has not been received from the source yet. */ GList *selection_list; /* has the drop occured ? */ gboolean drop_occured; /* whether or not need to clean up the previous dnd data */ gboolean need_to_destroy; /* autoscrolling during dragging */ int auto_scroll_timeout_id; gboolean waiting_to_autoscroll; gint64 start_auto_scroll_in; } NemoDragInfo; typedef void (* NemoDragEachSelectedItemDataGet) (const char *url, int x, int y, int w, int h, gpointer data); typedef void (* NemoDragEachSelectedItemIterator) (NemoDragEachSelectedItemDataGet iteratee, gpointer iterator_context, gpointer data); void nemo_drag_init (NemoDragInfo *drag_info, const GtkTargetEntry *drag_types, int drag_type_count, gboolean add_text_targets); void nemo_drag_finalize (NemoDragInfo *drag_info); NemoDragSelectionItem *nemo_drag_selection_item_new (void); void nemo_drag_destroy_selection_list (GList *selection_list); GList *nemo_drag_build_selection_list (GtkSelectionData *data); char ** nemo_drag_uri_array_from_selection_list (const GList *selection_list); GList * nemo_drag_uri_list_from_selection_list (const GList *selection_list); char ** nemo_drag_uri_array_from_list (const GList *uri_list); GList * nemo_drag_uri_list_from_array (const char **uris); gboolean nemo_drag_items_local (const char *target_uri, const GList *selection_list); gboolean nemo_drag_uris_local (const char *target_uri, const GList *source_uri_list); gboolean nemo_drag_items_in_trash (const GList *selection_list); gboolean nemo_drag_items_on_desktop (const GList *selection_list); void nemo_drag_default_drop_action_for_icons (GdkDragContext *context, const char *target_uri_string, const GList *items, int *action, gchar **source_fs, gboolean *can_delete_source); GdkDragAction nemo_drag_default_drop_action_for_netscape_url (GdkDragContext *context); GdkDragAction nemo_drag_default_drop_action_for_uri_list (GdkDragContext *context, const char *target_uri_string); gboolean nemo_drag_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, gpointer container_context, NemoDragEachSelectedItemIterator each_selected_item_iterator); int nemo_drag_modifier_based_action (int default_action, int non_default_action); GdkDragAction nemo_drag_drop_action_ask (GtkWidget *widget, GdkDragAction possible_actions); gboolean nemo_drag_autoscroll_in_scroll_region (GtkWidget *widget); void nemo_drag_autoscroll_calculate_delta (GtkWidget *widget, float *x_scroll_delta, float *y_scroll_delta); void nemo_drag_autoscroll_start (NemoDragInfo *drag_info, GtkWidget *widget, GSourceFunc callback, gpointer user_data); void nemo_drag_autoscroll_stop (NemoDragInfo *drag_info); gboolean nemo_drag_selection_includes_special_link (GList *selection_list); #endif nemo-4.4.2/libnemo-private/nemo-entry.c000066400000000000000000000251131357442400300200210ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoEntry: one-line text editing widget. This consists of bug fixes * and other improvements to GtkEntry, and all the changes could be rolled * into GtkEntry some day. * * Copyright (C) 2000 Eazel, Inc. * * Author: John Sullivan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include "nemo-entry.h" #include #include "nemo-global-preferences.h" #include "nemo-undo-signal-handlers.h" #include #include #include struct NemoEntryDetails { gboolean user_edit; gboolean special_tab_handling; guint select_idle_id; }; enum { USER_CHANGED, SELECTION_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void nemo_entry_editable_init (GtkEditableInterface *iface); G_DEFINE_TYPE_WITH_CODE (NemoEntry, nemo_entry, GTK_TYPE_ENTRY, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, nemo_entry_editable_init)); static GtkEditableInterface *parent_editable_interface = NULL; static void nemo_entry_init (NemoEntry *entry) { entry->details = g_new0 (NemoEntryDetails, 1); entry->details->user_edit = TRUE; nemo_undo_set_up_nemo_entry_for_undo (entry); } GtkWidget * nemo_entry_new (void) { return gtk_widget_new (NEMO_TYPE_ENTRY, NULL); } GtkWidget * nemo_entry_new_with_max_length (guint16 max) { GtkWidget *widget; widget = gtk_widget_new (NEMO_TYPE_ENTRY, NULL); gtk_entry_set_max_length (GTK_ENTRY (widget), max); return widget; } static void nemo_entry_finalize (GObject *object) { NemoEntry *entry; entry = NEMO_ENTRY (object); if (entry->details->select_idle_id != 0) { g_source_remove (entry->details->select_idle_id); } g_free (entry->details); G_OBJECT_CLASS (nemo_entry_parent_class)->finalize (object); } static gboolean nemo_entry_key_press (GtkWidget *widget, GdkEventKey *event) { NemoEntry *entry; GtkEditable *editable; int position; gboolean old_has, new_has; gboolean result; entry = NEMO_ENTRY (widget); editable = GTK_EDITABLE (widget); if (!gtk_editable_get_editable (editable)) { return FALSE; } switch (event->keyval) { case GDK_KEY_Tab: /* The location bar entry wants TAB to work kind of * like it does in the shell for command completion, * so if we get a tab and there's a selection, we * should position the insertion point at the end of * the selection. */ if (entry->details->special_tab_handling && gtk_editable_get_selection_bounds (editable, NULL, NULL)) { position = strlen (gtk_entry_get_text (GTK_ENTRY (editable))); gtk_editable_select_region (editable, position, position); return TRUE; } break; default: break; } old_has = gtk_editable_get_selection_bounds (editable, NULL, NULL); result = GTK_WIDGET_CLASS (nemo_entry_parent_class)->key_press_event (widget, event); /* Pressing a key usually changes the selection if there is a selection. * If there is not selection, we can save work by not emitting a signal. */ if (result) { new_has = gtk_editable_get_selection_bounds (editable, NULL, NULL); if (old_has || new_has) { g_signal_emit (widget, signals[SELECTION_CHANGED], 0); } } return result; } static gboolean nemo_entry_motion_notify (GtkWidget *widget, GdkEventMotion *event) { int result; gboolean old_had, new_had; int old_start, old_end, new_start, new_end; GtkEditable *editable; editable = GTK_EDITABLE (widget); old_had = gtk_editable_get_selection_bounds (editable, &old_start, &old_end); result = GTK_WIDGET_CLASS (nemo_entry_parent_class)->motion_notify_event (widget, event); /* Send a signal if dragging the mouse caused the selection to change. */ if (result) { new_had = gtk_editable_get_selection_bounds (editable, &new_start, &new_end); if (old_had != new_had || (old_had && (old_start != new_start || old_end != new_end))) { g_signal_emit (widget, signals[SELECTION_CHANGED], 0); } } return result; } /** * nemo_entry_select_all * * Select all text, leaving the text cursor position at the end. * * @entry: A NemoEntry **/ void nemo_entry_select_all (NemoEntry *entry) { g_return_if_fail (NEMO_IS_ENTRY (entry)); gtk_editable_set_position (GTK_EDITABLE (entry), -1); gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); } static gboolean select_all_at_idle (gpointer callback_data) { NemoEntry *entry; entry = NEMO_ENTRY (callback_data); nemo_entry_select_all (entry); entry->details->select_idle_id = 0; return FALSE; } /** * nemo_entry_select_all_at_idle * * Select all text at the next idle, not immediately. * This is useful when reacting to a key press, because * changing the selection and the text cursor position doesn't * work in a key_press signal handler. * * @entry: A NemoEntry **/ void nemo_entry_select_all_at_idle (NemoEntry *entry) { g_return_if_fail (NEMO_IS_ENTRY (entry)); /* If the text cursor position changes in this routine * then gtk_entry_key_press will unselect (and we want * to move the text cursor position to the end). */ if (entry->details->select_idle_id == 0) { entry->details->select_idle_id = g_idle_add (select_all_at_idle, entry); } } /** * nemo_entry_set_text * * This function wraps gtk_entry_set_text. It sets undo_registered * to TRUE and preserves the old value for a later restore. This is * done so the programmatic changes to the entry do not register * with the undo manager. * * @entry: A NemoEntry * @test: The text to set **/ void nemo_entry_set_text (NemoEntry *entry, const gchar *text) { g_return_if_fail (NEMO_IS_ENTRY (entry)); entry->details->user_edit = FALSE; gtk_entry_set_text (GTK_ENTRY (entry), text); entry->details->user_edit = TRUE; g_signal_emit (entry, signals[SELECTION_CHANGED], 0); } static void nemo_entry_set_selection_bounds (GtkEditable *editable, int start_pos, int end_pos) { parent_editable_interface->set_selection_bounds (editable, start_pos, end_pos); g_signal_emit (editable, signals[SELECTION_CHANGED], 0); } static gboolean nemo_entry_button_press (GtkWidget *widget, GdkEventButton *event) { gboolean result; result = GTK_WIDGET_CLASS (nemo_entry_parent_class)->button_press_event (widget, event); if (result) { g_signal_emit (widget, signals[SELECTION_CHANGED], 0); } return result; } static gboolean nemo_entry_button_release (GtkWidget *widget, GdkEventButton *event) { gboolean result; result = GTK_WIDGET_CLASS (nemo_entry_parent_class)->button_release_event (widget, event); if (result) { g_signal_emit (widget, signals[SELECTION_CHANGED], 0); } return result; } static void nemo_entry_insert_text (GtkEditable *editable, const gchar *text, int length, int *position) { NemoEntry *entry; entry = NEMO_ENTRY(editable); /* Fire off user changed signals */ if (entry->details->user_edit) { g_signal_emit (editable, signals[USER_CHANGED], 0); } parent_editable_interface->insert_text (editable, text, length, position); g_signal_emit (editable, signals[SELECTION_CHANGED], 0); } static void nemo_entry_delete_text (GtkEditable *editable, int start_pos, int end_pos) { NemoEntry *entry; entry = NEMO_ENTRY (editable); /* Fire off user changed signals */ if (entry->details->user_edit) { g_signal_emit (editable, signals[USER_CHANGED], 0); } parent_editable_interface->delete_text (editable, start_pos, end_pos); g_signal_emit (editable, signals[SELECTION_CHANGED], 0); } /* Overridden to work around GTK bug. The selection_clear_event is queued * when the selection changes. Changing the selection to NULL and then * back to the original selection owner still sends the event, so the * selection owner then gets the selection ripped away from it. We ran into * this with type-completion behavior in NemoLocationBar (see bug 5313). * There's a FIXME comment that seems to be about this same issue in * gtk+/gtkselection.c, gtk_selection_clear. */ static gboolean nemo_entry_selection_clear (GtkWidget *widget, GdkEventSelection *event) { g_assert (NEMO_IS_ENTRY (widget)); if (gdk_selection_owner_get (event->selection) == gtk_widget_get_window (widget)) { return FALSE; } return GTK_WIDGET_CLASS (nemo_entry_parent_class)->selection_clear_event (widget, event); } static void nemo_entry_editable_init (GtkEditableInterface *iface) { parent_editable_interface = g_type_interface_peek_parent (iface); iface->insert_text = nemo_entry_insert_text; iface->delete_text = nemo_entry_delete_text; iface->set_selection_bounds = nemo_entry_set_selection_bounds; /* Otherwise we might need some memcpy loving */ g_assert (iface->do_insert_text != NULL); g_assert (iface->get_position != NULL); g_assert (iface->get_chars != NULL); } static void nemo_entry_class_init (NemoEntryClass *class) { GtkWidgetClass *widget_class; GObjectClass *gobject_class; widget_class = GTK_WIDGET_CLASS (class); gobject_class = G_OBJECT_CLASS (class); widget_class->button_press_event = nemo_entry_button_press; widget_class->button_release_event = nemo_entry_button_release; widget_class->key_press_event = nemo_entry_key_press; widget_class->motion_notify_event = nemo_entry_motion_notify; widget_class->selection_clear_event = nemo_entry_selection_clear; gobject_class->finalize = nemo_entry_finalize; /* Set up signals */ signals[USER_CHANGED] = g_signal_new ("user_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoEntryClass, user_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoEntryClass, selection_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } void nemo_entry_set_special_tab_handling (NemoEntry *entry, gboolean special_tab_handling) { g_return_if_fail (NEMO_IS_ENTRY (entry)); entry->details->special_tab_handling = special_tab_handling; } nemo-4.4.2/libnemo-private/nemo-entry.h000066400000000000000000000047771357442400300200430ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoEntry: one-line text editing widget. This consists of bug fixes * and other improvements to GtkEntry, and all the changes could be rolled * into GtkEntry some day. * * Copyright (C) 2000 Eazel, Inc. * * Author: John Sullivan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_ENTRY_H #define NEMO_ENTRY_H #include G_BEGIN_DECLS #define NEMO_TYPE_ENTRY nemo_entry_get_type() #define NEMO_ENTRY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ENTRY, NemoEntry)) #define NEMO_ENTRY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ENTRY, NemoEntryClass)) #define NEMO_IS_ENTRY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ENTRY)) #define NEMO_IS_ENTRY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ENTRY)) #define NEMO_ENTRY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ENTRY, NemoEntryClass)) typedef struct NemoEntryDetails NemoEntryDetails; typedef struct { GtkEntry parent; NemoEntryDetails *details; } NemoEntry; typedef struct { GtkEntryClass parent_class; void (*user_changed) (NemoEntry *entry); void (*selection_changed) (NemoEntry *entry); } NemoEntryClass; GType nemo_entry_get_type (void); GtkWidget *nemo_entry_new (void); GtkWidget *nemo_entry_new_with_max_length (guint16 max); void nemo_entry_set_text (NemoEntry *entry, const char *text); void nemo_entry_select_all (NemoEntry *entry); void nemo_entry_select_all_at_idle (NemoEntry *entry); void nemo_entry_set_special_tab_handling (NemoEntry *entry, gboolean special_tab_handling); G_END_DECLS #endif /* NEMO_ENTRY_H */ nemo-4.4.2/libnemo-private/nemo-file-attributes.h000066400000000000000000000034421357442400300217710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-file-attributes.h: #defines and other file-attribute-related info Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_FILE_ATTRIBUTES_H #define NEMO_FILE_ATTRIBUTES_H /* Names for NemoFile attributes. These are used when registering * interest in changes to the attributes or when waiting for them. */ typedef enum { NEMO_FILE_ATTRIBUTE_INFO = 1 << 0, /* All standard info */ NEMO_FILE_ATTRIBUTE_LINK_INFO = 1 << 1, /* info from desktop links */ NEMO_FILE_ATTRIBUTE_DEEP_COUNTS = 1 << 2, NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT = 1 << 3, NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES = 1 << 4, NEMO_FILE_ATTRIBUTE_TOP_LEFT_TEXT = 1 << 5, NEMO_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT = 1 << 6, NEMO_FILE_ATTRIBUTE_EXTENSION_INFO = 1 << 7, NEMO_FILE_ATTRIBUTE_THUMBNAIL = 1 << 8, NEMO_FILE_ATTRIBUTE_MOUNT = 1 << 9, NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO = 1 << 10, NEMO_FILE_ATTRIBUTE_BTIME = 1 << 11, } NemoFileAttributes; #endif /* NEMO_FILE_ATTRIBUTES_H */ nemo-4.4.2/libnemo-private/nemo-file-changes-queue.c000066400000000000000000000235451357442400300223360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Pavel Cisler */ #include #include "nemo-file-changes-queue.h" #include "nemo-directory-notify.h" typedef enum { CHANGE_FILE_INITIAL, CHANGE_FILE_ADDED, CHANGE_FILE_CHANGED, CHANGE_FILE_REMOVED, CHANGE_FILE_MOVED, CHANGE_POSITION_SET, CHANGE_POSITION_REMOVE } NemoFileChangeKind; typedef struct { NemoFileChangeKind kind; GFile *from; GFile *to; GdkPoint point; int monitor; } NemoFileChange; typedef struct { GList *head; GList *tail; GMutex mutex; } NemoFileChangesQueue; static NemoFileChangesQueue * nemo_file_changes_queue_new (void) { NemoFileChangesQueue *result; result = g_new0 (NemoFileChangesQueue, 1); g_mutex_init (&result->mutex); return result; } static NemoFileChangesQueue * nemo_file_changes_queue_get (void) { static NemoFileChangesQueue *file_changes_queue; if (file_changes_queue == NULL) { file_changes_queue = nemo_file_changes_queue_new (); } return file_changes_queue; } static void nemo_file_changes_queue_add_common (NemoFileChangesQueue *queue, NemoFileChange *new_item) { /* enqueue the new queue item while locking down the list */ g_mutex_lock (&queue->mutex); queue->head = g_list_prepend (queue->head, new_item); if (queue->tail == NULL) queue->tail = queue->head; g_mutex_unlock (&queue->mutex); } void nemo_file_changes_queue_file_added (GFile *location) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get(); new_item = g_new0 (NemoFileChange, 1); new_item->kind = CHANGE_FILE_ADDED; new_item->from = g_object_ref (location); nemo_file_changes_queue_add_common (queue, new_item); } void nemo_file_changes_queue_file_changed (GFile *location) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get(); new_item = g_new0 (NemoFileChange, 1); new_item->kind = CHANGE_FILE_CHANGED; new_item->from = g_object_ref (location); nemo_file_changes_queue_add_common (queue, new_item); } void nemo_file_changes_queue_file_removed (GFile *location) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get(); new_item = g_new0 (NemoFileChange, 1); new_item->kind = CHANGE_FILE_REMOVED; new_item->from = g_object_ref (location); nemo_file_changes_queue_add_common (queue, new_item); } void nemo_file_changes_queue_file_moved (GFile *from, GFile *to) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get (); new_item = g_new (NemoFileChange, 1); new_item->kind = CHANGE_FILE_MOVED; new_item->from = g_object_ref (from); new_item->to = g_object_ref (to); nemo_file_changes_queue_add_common (queue, new_item); } void nemo_file_changes_queue_schedule_position_set (GFile *location, GdkPoint point, int monitor) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get (); new_item = g_new (NemoFileChange, 1); new_item->kind = CHANGE_POSITION_SET; new_item->from = g_object_ref (location); new_item->point = point; new_item->monitor = monitor; nemo_file_changes_queue_add_common (queue, new_item); } void nemo_file_changes_queue_schedule_position_remove (GFile *location) { NemoFileChange *new_item; NemoFileChangesQueue *queue; queue = nemo_file_changes_queue_get (); new_item = g_new (NemoFileChange, 1); new_item->kind = CHANGE_POSITION_REMOVE; new_item->from = g_object_ref (location); nemo_file_changes_queue_add_common (queue, new_item); } static NemoFileChange * nemo_file_changes_queue_get_change (NemoFileChangesQueue *queue) { GList *new_tail; NemoFileChange *result; g_assert (queue != NULL); /* dequeue the tail item while locking down the list */ g_mutex_lock (&queue->mutex); if (queue->tail == NULL) { result = NULL; } else { new_tail = queue->tail->prev; result = queue->tail->data; queue->head = g_list_remove_link (queue->head, queue->tail); g_list_free_1 (queue->tail); queue->tail = new_tail; } g_mutex_unlock (&queue->mutex); return result; } enum { CONSUME_CHANGES_MAX_CHUNK = 20 }; static void pairs_list_free (GList *pairs) { GList *p; GFilePair *pair; /* deep delete the list of pairs */ for (p = pairs; p != NULL; p = p->next) { /* delete the strings in each pair */ pair = p->data; g_object_unref (pair->from); g_object_unref (pair->to); } /* delete the list and the now empty pair structs */ g_list_free_full (pairs, g_free); } static void position_set_list_free (GList *list) { GList *p; NemoFileChangesQueuePosition *item; for (p = list; p != NULL; p = p->next) { item = p->data; g_object_unref (item->location); } /* delete the list and the now empty structs */ g_list_free_full (list, g_free); } /* go through changes in the change queue, send ones with the same kind * in a list to the different nemo_directory_notify calls */ void nemo_file_changes_consume_changes (gboolean consume_all) { NemoFileChange *change; GList *additions, *changes, *deletions, *moves; GList *position_set_requests; GFilePair *pair; NemoFileChangesQueuePosition *position_set; guint chunk_count; NemoFileChangesQueue *queue; gboolean flush_needed; additions = NULL; changes = NULL; deletions = NULL; moves = NULL; position_set_requests = NULL; queue = nemo_file_changes_queue_get(); /* Consume changes from the queue, stuffing them into one of three lists, * keep doing it while the changes are of the same kind, then send them off. * This is to ensure that the changes get sent off in the same order that they * arrived. */ for (chunk_count = 0; ; chunk_count++) { change = nemo_file_changes_queue_get_change (queue); /* figure out if we need to flush the pending changes that we collected sofar */ if (change == NULL) { flush_needed = TRUE; /* no changes left, flush everything */ } else { flush_needed = additions != NULL && change->kind != CHANGE_FILE_ADDED && change->kind != CHANGE_POSITION_SET && change->kind != CHANGE_POSITION_REMOVE; flush_needed |= changes != NULL && change->kind != CHANGE_FILE_CHANGED; flush_needed |= moves != NULL && change->kind != CHANGE_FILE_MOVED && change->kind != CHANGE_POSITION_SET && change->kind != CHANGE_POSITION_REMOVE; flush_needed |= deletions != NULL && change->kind != CHANGE_FILE_REMOVED; flush_needed |= position_set_requests != NULL && change->kind != CHANGE_POSITION_SET && change->kind != CHANGE_POSITION_REMOVE && change->kind != CHANGE_FILE_ADDED && change->kind != CHANGE_FILE_MOVED; flush_needed |= !consume_all && chunk_count >= CONSUME_CHANGES_MAX_CHUNK; /* we have reached the chunk maximum */ } if (flush_needed) { /* Send changes we collected off. * At one time we may only have one of the lists * contain changes. */ if (deletions != NULL) { deletions = g_list_reverse (deletions); nemo_directory_notify_files_removed (deletions); g_list_free_full (deletions, g_object_unref); deletions = NULL; } if (moves != NULL) { moves = g_list_reverse (moves); nemo_directory_notify_files_moved (moves); pairs_list_free (moves); moves = NULL; } if (additions != NULL) { additions = g_list_reverse (additions); nemo_directory_notify_files_added (additions); g_list_free_full (additions, g_object_unref); additions = NULL; } if (changes != NULL) { changes = g_list_reverse (changes); nemo_directory_notify_files_changed (changes); g_list_free_full (changes, g_object_unref); changes = NULL; } if (position_set_requests != NULL) { position_set_requests = g_list_reverse (position_set_requests); nemo_directory_schedule_position_set (position_set_requests); position_set_list_free (position_set_requests); position_set_requests = NULL; } } if (change == NULL) { /* we are done */ return; } /* add the new change to the list */ switch (change->kind) { case CHANGE_FILE_ADDED: additions = g_list_prepend (additions, change->from); break; case CHANGE_FILE_CHANGED: changes = g_list_prepend (changes, change->from); break; case CHANGE_FILE_REMOVED: deletions = g_list_prepend (deletions, change->from); break; case CHANGE_FILE_MOVED: pair = g_new (GFilePair, 1); pair->from = change->from; pair->to = change->to; moves = g_list_prepend (moves, pair); break; case CHANGE_POSITION_SET: position_set = g_new (NemoFileChangesQueuePosition, 1); position_set->location = change->from; position_set->set = TRUE; position_set->point = change->point; position_set->monitor = change->monitor; position_set_requests = g_list_prepend (position_set_requests, position_set); break; case CHANGE_POSITION_REMOVE: position_set = g_new (NemoFileChangesQueuePosition, 1); position_set->location = change->from; position_set->set = FALSE; position_set_requests = g_list_prepend (position_set_requests, position_set); break; case CHANGE_FILE_INITIAL: default: g_assert_not_reached (); break; } g_free (change); } } nemo-4.4.2/libnemo-private/nemo-file-changes-queue.h000066400000000000000000000033261357442400300223360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Pavel Cisler */ #ifndef NEMO_FILE_CHANGES_QUEUE_H #define NEMO_FILE_CHANGES_QUEUE_H #include #include void nemo_file_changes_queue_file_added (GFile *location); void nemo_file_changes_queue_file_changed (GFile *location); void nemo_file_changes_queue_file_removed (GFile *location); void nemo_file_changes_queue_file_moved (GFile *from, GFile *to); void nemo_file_changes_queue_schedule_position_set (GFile *location, GdkPoint point, int monitor); void nemo_file_changes_queue_schedule_position_remove (GFile *location); void nemo_file_changes_consume_changes (gboolean consume_all); #endif /* NEMO_FILE_CHANGES_QUEUE_H */ nemo-4.4.2/libnemo-private/nemo-file-conflict-dialog.c000066400000000000000000000456651357442400300226510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-file-conflict-dialog: dialog that handles file conflicts during transfer operations. Copyright (C) 2008-2010 Cosimo Cecchi 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Cosimo Cecchi */ #include #include "nemo-file-conflict-dialog.h" #include #include #include #include #include #include #include "nemo-file.h" #include "nemo-icon-info.h" struct _NemoFileConflictDialogDetails { /* conflicting objects */ NemoFile *source; NemoFile *destination; NemoFile *dest_dir; gchar *conflict_name; NemoFileListHandle *handle; gulong src_handler_id; gulong dest_handler_id; /* UI objects */ GtkWidget *titles_vbox; GtkWidget *first_hbox; GtkWidget *second_hbox; GtkWidget *expander; GtkWidget *entry; GtkWidget *checkbox; GtkWidget *rename_button; GtkWidget *replace_button; GtkWidget *dest_image; GtkWidget *src_image; }; G_DEFINE_TYPE (NemoFileConflictDialog, nemo_file_conflict_dialog, GTK_TYPE_DIALOG); #define NEMO_FILE_CONFLICT_DIALOG_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), NEMO_TYPE_FILE_CONFLICT_DIALOG, \ NemoFileConflictDialogDetails)) static void file_icons_changed (NemoFile *file, NemoFileConflictDialog *fcd) { GdkPixbuf *pixbuf; pixbuf = nemo_file_get_icon_pixbuf (fcd->details->destination, NEMO_ICON_SIZE_LARGE, TRUE, gtk_widget_get_scale_factor (fcd->details->dest_image), NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS); gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->dest_image), pixbuf); g_object_unref (pixbuf); pixbuf = nemo_file_get_icon_pixbuf (fcd->details->source, NEMO_ICON_SIZE_LARGE, TRUE, gtk_widget_get_scale_factor (fcd->details->src_image), NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS); gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->src_image), pixbuf); g_object_unref (pixbuf); } static void file_list_ready_cb (GList *files, gpointer user_data) { NemoFileConflictDialog *fcd = user_data; NemoFile *src, *dest, *dest_dir; time_t src_mtime, dest_mtime; gboolean source_is_dir, dest_is_dir, should_show_type; NemoFileConflictDialogDetails *details; char *primary_text, *message, *secondary_text; const gchar *message_extra; char *dest_name, *dest_dir_name, *edit_name; char *label_text; char *size, *date, *type = NULL; GdkPixbuf *pixbuf; GtkWidget *label; GString *str; PangoAttrList *attr_list; details = fcd->details; details->handle = NULL; dest_dir = g_list_nth_data (files, 0); dest = g_list_nth_data (files, 1); src = g_list_nth_data (files, 2); src_mtime = nemo_file_get_mtime (src); dest_mtime = nemo_file_get_mtime (dest); dest_name = nemo_file_get_display_name (dest); dest_dir_name = nemo_file_get_display_name (dest_dir); source_is_dir = nemo_file_is_directory (src); dest_is_dir = nemo_file_is_directory (dest); type = nemo_file_get_mime_type (dest); should_show_type = !nemo_file_is_mime_type (src, type); g_clear_pointer (&type, g_free); /* Set up the right labels */ if (dest_is_dir) { if (source_is_dir) { primary_text = g_strdup_printf (_("Merge folder \"%s\"?"), dest_name); message_extra = _("Merging will ask for confirmation before replacing any files in " "the folder that conflict with the files being copied."); if (src_mtime > dest_mtime) { message = g_strdup_printf ( _("An older folder with the same name already exists in \"%s\"."), dest_dir_name); } else if (src_mtime < dest_mtime) { message = g_strdup_printf ( _("A newer folder with the same name already exists in \"%s\"."), dest_dir_name); } else { message = g_strdup_printf ( _("Another folder with the same name already exists in \"%s\"."), dest_dir_name); } } else { message_extra = _("Replacing it will remove all files in the folder."); primary_text = g_strdup_printf (_("Replace folder \"%s\"?"), dest_name); message = g_strdup_printf (_("A folder with the same name already exists in \"%s\"."), dest_dir_name); } } else { primary_text = g_strdup_printf (_("Replace file \"%s\"?"), dest_name); message_extra = _("Replacing it will overwrite its content."); if (src_mtime > dest_mtime) { message = g_strdup_printf ( _("An older file with the same name already exists in \"%s\"."), dest_dir_name); } else if (src_mtime < dest_mtime) { message = g_strdup_printf ( _("A newer file with the same name already exists in \"%s\"."), dest_dir_name); } else { message = g_strdup_printf ( _("Another file with the same name already exists in \"%s\"."), dest_dir_name); } } secondary_text = g_strdup_printf ("%s\n%s", message, message_extra); g_clear_pointer (&message, g_free); label = gtk_label_new (primary_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (details->titles_vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); attr_list = pango_attr_list_new (); pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE)); g_object_set (label, "attributes", attr_list, NULL); pango_attr_list_unref (attr_list); label = gtk_label_new (secondary_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (details->titles_vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); g_free (primary_text); g_free (secondary_text); /* Set up file icons */ pixbuf = nemo_file_get_icon_pixbuf (dest, NEMO_ICON_SIZE_LARGE, TRUE, gtk_widget_get_scale_factor (fcd->details->titles_vbox), NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS); details->dest_image = gtk_image_new_from_pixbuf (pixbuf); gtk_box_pack_start (GTK_BOX (details->first_hbox), details->dest_image, FALSE, FALSE, 0); gtk_widget_show (details->dest_image); g_object_unref (pixbuf); pixbuf = nemo_file_get_icon_pixbuf (src, NEMO_ICON_SIZE_LARGE, TRUE, gtk_widget_get_scale_factor (fcd->details->titles_vbox), NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS); details->src_image = gtk_image_new_from_pixbuf (pixbuf); gtk_box_pack_start (GTK_BOX (details->second_hbox), details->src_image, FALSE, FALSE, 0); gtk_widget_show (details->src_image); g_object_unref (pixbuf); /* Set up labels */ label = gtk_label_new (NULL); date = nemo_file_get_string_attribute (dest, "date_modified"); size = nemo_file_get_string_attribute (dest, "size"); if (should_show_type) { type = nemo_file_get_string_attribute (dest, "type"); } str = g_string_new (NULL); g_string_append_printf (str, "%s\n", _("Original file")); g_string_append_printf (str, "%s %s\n", _("Size:"), size); if (should_show_type) { g_string_append_printf (str, "%s %s\n", _("Type:"), type); } g_string_append_printf (str, "%s %s", _("Last modified:"), date); label_text = str->str; gtk_label_set_markup (GTK_LABEL (label), label_text); gtk_box_pack_start (GTK_BOX (details->first_hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); g_clear_pointer (&size, g_free); g_clear_pointer (&type, g_free); g_clear_pointer (&date, g_free); g_string_erase (str, 0, -1); /* Second label */ label = gtk_label_new (NULL); date = nemo_file_get_string_attribute (src, "date_modified"); size = nemo_file_get_string_attribute (src, "size"); if (should_show_type) { type = nemo_file_get_string_attribute (src, "type"); } g_string_append_printf (str, "%s\n", _("Replace with")); g_string_append_printf (str, "%s %s\n", _("Size:"), size); if (should_show_type) { g_string_append_printf (str, "%s %s\n", _("Type:"), type); } g_string_append_printf (str, "%s %s", _("Last modified:"), date); label_text = g_string_free (str, FALSE); gtk_label_set_markup (GTK_LABEL (label), label_text); gtk_box_pack_start (GTK_BOX (details->second_hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); g_clear_pointer (&size, g_free); g_clear_pointer (&type, g_free); g_clear_pointer (&date, g_free); g_clear_pointer (&label_text, g_free); /* Populate the entry */ edit_name = nemo_file_get_edit_name (dest); details->conflict_name = edit_name; gtk_entry_set_text (GTK_ENTRY (details->entry), edit_name); if (source_is_dir && dest_is_dir) { gtk_button_set_label (GTK_BUTTON (details->replace_button), _("Merge")); } nemo_file_monitor_add (src, fcd, NEMO_FILE_ATTRIBUTES_FOR_ICON); nemo_file_monitor_add (dest, fcd, NEMO_FILE_ATTRIBUTES_FOR_ICON); details->src_handler_id = g_signal_connect (src, "changed", G_CALLBACK (file_icons_changed), fcd); details->dest_handler_id = g_signal_connect (dest, "changed", G_CALLBACK (file_icons_changed), fcd); } static void build_dialog_appearance (NemoFileConflictDialog *fcd) { GList *files = NULL; NemoFileConflictDialogDetails *details = fcd->details; files = g_list_prepend (files, details->source); files = g_list_prepend (files, details->destination); files = g_list_prepend (files, details->dest_dir); nemo_file_list_call_when_ready (files, NEMO_FILE_ATTRIBUTES_FOR_ICON, &details->handle, file_list_ready_cb, fcd); g_list_free (files); } static void set_source_and_destination (GtkWidget *w, GFile *source, GFile *destination, GFile *dest_dir) { NemoFileConflictDialog *dialog; NemoFileConflictDialogDetails *details; dialog = NEMO_FILE_CONFLICT_DIALOG (w); details = dialog->details; details->source = nemo_file_get (source); details->destination = nemo_file_get (destination); details->dest_dir = nemo_file_get (dest_dir); build_dialog_appearance (dialog); } static void entry_text_changed_cb (GtkEditable *entry, NemoFileConflictDialog *dialog) { NemoFileConflictDialogDetails *details; details = dialog->details; /* The rename button is visible only if there's text * in the entry. */ if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), "") != 0 && g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), details->conflict_name) != 0) { gtk_widget_hide (details->replace_button); gtk_widget_show (details->rename_button); gtk_widget_set_sensitive (details->checkbox, FALSE); gtk_dialog_set_default_response (GTK_DIALOG (dialog), CONFLICT_RESPONSE_RENAME); } else { gtk_widget_hide (details->rename_button); gtk_widget_show (details->replace_button); gtk_widget_set_sensitive (details->checkbox, TRUE); gtk_dialog_set_default_response (GTK_DIALOG (dialog), CONFLICT_RESPONSE_REPLACE); } } static void expander_activated_cb (GtkExpander *w, NemoFileConflictDialog *dialog) { NemoFileConflictDialogDetails *details; int start_pos, end_pos; details = dialog->details; if (!gtk_expander_get_expanded (w)) { if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)), details->conflict_name) == 0) { gtk_widget_grab_focus (details->entry); eel_filename_get_rename_region (details->conflict_name, &start_pos, &end_pos); gtk_editable_select_region (GTK_EDITABLE (details->entry), start_pos, end_pos); } } } static void checkbox_toggled_cb (GtkToggleButton *t, NemoFileConflictDialog *dialog) { NemoFileConflictDialogDetails *details; details = dialog->details; gtk_widget_set_sensitive (details->expander, !gtk_toggle_button_get_active (t)); gtk_widget_set_sensitive (details->rename_button, !gtk_toggle_button_get_active (t)); if (!gtk_toggle_button_get_active (t) && g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)), "") != 0 && g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)), details->conflict_name) != 0) { gtk_widget_hide (details->replace_button); gtk_widget_show (details->rename_button); } else { gtk_widget_hide (details->rename_button); gtk_widget_show (details->replace_button); } } static void reset_button_clicked_cb (GtkButton *w, NemoFileConflictDialog *dialog) { NemoFileConflictDialogDetails *details; int start_pos, end_pos; details = dialog->details; gtk_entry_set_text (GTK_ENTRY (details->entry), details->conflict_name); gtk_widget_grab_focus (details->entry); eel_filename_get_rename_region (details->conflict_name, &start_pos, &end_pos); gtk_editable_select_region (GTK_EDITABLE (details->entry), start_pos, end_pos); } static void nemo_file_conflict_dialog_init (NemoFileConflictDialog *fcd) { GtkWidget *hbox, *vbox, *vbox2, *alignment; GtkWidget *widget, *dialog_area; NemoFileConflictDialogDetails *details; GtkDialog *dialog; details = fcd->details = NEMO_FILE_CONFLICT_DIALOG_GET_PRIVATE (fcd); dialog = GTK_DIALOG (fcd); /* Setup the main hbox */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); dialog_area = gtk_dialog_get_content_area (dialog); gtk_box_pack_start (GTK_BOX (dialog_area), hbox, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); /* Setup the dialog image */ widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.0); /* Setup the vbox containing the dialog body */ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); /* Setup the vbox for the dialog labels */ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); details->titles_vbox = widget; /* Setup the hboxes to pack file infos into */ alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); g_object_set (alignment, "left-padding", 12, NULL); vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_add (GTK_CONTAINER (alignment), vbox2); gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0); details->first_hbox = hbox; hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0); details->second_hbox = hbox; /* Setup the expander for the rename action */ details->expander = gtk_expander_new_with_mnemonic (_("_Select a new name for the destination")); gtk_box_pack_start (GTK_BOX (vbox2), details->expander, FALSE, FALSE, 0); g_signal_connect (details->expander, "activate", G_CALLBACK (expander_activated_cb), dialog); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_add (GTK_CONTAINER (details->expander), hbox); widget = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 6); details->entry = widget; g_signal_connect (widget, "changed", G_CALLBACK (entry_text_changed_cb), dialog); widget = gtk_button_new_with_label (_("Reset")); gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new_from_stock (GTK_STOCK_UNDO, GTK_ICON_SIZE_MENU)); gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6); g_signal_connect (widget, "clicked", G_CALLBACK (reset_button_clicked_cb), dialog); gtk_widget_show_all (alignment); /* Setup the checkbox to apply the action to all files */ widget = gtk_check_button_new_with_mnemonic (_("Apply this action to all files")); gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); details->checkbox = widget; g_signal_connect (widget, "toggled", G_CALLBACK (checkbox_toggled_cb), dialog); /* Add buttons */ gtk_dialog_add_buttons (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Skip"), CONFLICT_RESPONSE_SKIP, NULL); details->rename_button = gtk_dialog_add_button (dialog, _("Re_name"), CONFLICT_RESPONSE_RENAME); gtk_widget_hide (details->rename_button); details->replace_button = gtk_dialog_add_button (dialog, _("Replace"), CONFLICT_RESPONSE_REPLACE); gtk_widget_grab_focus (details->replace_button); /* Setup HIG properties */ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (dialog)), 14); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_widget_show_all (dialog_area); } static void do_finalize (GObject *self) { NemoFileConflictDialogDetails *details = NEMO_FILE_CONFLICT_DIALOG (self)->details; g_free (details->conflict_name); if (details->handle != NULL) { nemo_file_list_cancel_call_when_ready (details->handle); } if (details->src_handler_id) { g_signal_handler_disconnect (details->source, details->src_handler_id); nemo_file_monitor_remove (details->source, self); } if (details->dest_handler_id) { g_signal_handler_disconnect (details->destination, details->dest_handler_id); nemo_file_monitor_remove (details->destination, self); } nemo_file_unref (details->source); nemo_file_unref (details->destination); nemo_file_unref (details->dest_dir); G_OBJECT_CLASS (nemo_file_conflict_dialog_parent_class)->finalize (self); } static void nemo_file_conflict_dialog_class_init (NemoFileConflictDialogClass *klass) { G_OBJECT_CLASS (klass)->finalize = do_finalize; g_type_class_add_private (klass, sizeof (NemoFileConflictDialogDetails)); } char * nemo_file_conflict_dialog_get_new_name (NemoFileConflictDialog *dialog) { return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->details->entry))); } gboolean nemo_file_conflict_dialog_get_apply_to_all (NemoFileConflictDialog *dialog) { return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->details->checkbox)); } GtkWidget * nemo_file_conflict_dialog_new (GtkWindow *parent, GFile *source, GFile *destination, GFile *dest_dir) { GtkWidget *dialog; dialog = GTK_WIDGET (g_object_new (NEMO_TYPE_FILE_CONFLICT_DIALOG, "title", _("File conflict"), NULL)); set_source_and_destination (dialog, source, destination, dest_dir); gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); return dialog; } nemo-4.4.2/libnemo-private/nemo-file-conflict-dialog.h000066400000000000000000000053671357442400300226510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-conflict-dialog: dialog that handles file conflicts during transfer operations. Copyright (C) 2008, Cosimo Cecchi 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Cosimo Cecchi */ #ifndef NEMO_FILE_CONFLICT_DIALOG_H #define NEMO_FILE_CONFLICT_DIALOG_H #include #include #include #define NEMO_TYPE_FILE_CONFLICT_DIALOG \ (nemo_file_conflict_dialog_get_type ()) #define NEMO_FILE_CONFLICT_DIALOG(o) \ (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_CONFLICT_DIALOG,\ NemoFileConflictDialog)) #define NEMO_FILE_CONFLICT_DIALOG_CLASS(k) \ (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_CONFLICT_DIALOG,\ NemoFileConflictDialogClass)) #define NEMO_IS_FILE_CONFLICT_DIALOG(o) \ (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_CONFLICT_DIALOG)) #define NEMO_IS_FILE_CONFLICT_DIALOG_CLASS(k) \ (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_CONFLICT_DIALOG)) #define NEMO_FILE_CONFLICT_DIALOG_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_CONFLICT_DIALOG,\ NemoFileConflictDialogClass)) typedef struct _NemoFileConflictDialog NemoFileConflictDialog; typedef struct _NemoFileConflictDialogClass NemoFileConflictDialogClass; typedef struct _NemoFileConflictDialogDetails NemoFileConflictDialogDetails; struct _NemoFileConflictDialog { GtkDialog parent; NemoFileConflictDialogDetails *details; }; struct _NemoFileConflictDialogClass { GtkDialogClass parent_class; }; enum { CONFLICT_RESPONSE_SKIP = 1, CONFLICT_RESPONSE_REPLACE = 2, CONFLICT_RESPONSE_RENAME = 3, }; GType nemo_file_conflict_dialog_get_type (void) G_GNUC_CONST; GtkWidget* nemo_file_conflict_dialog_new (GtkWindow *parent, GFile *source, GFile *destination, GFile *dest_dir); char* nemo_file_conflict_dialog_get_new_name (NemoFileConflictDialog *dialog); gboolean nemo_file_conflict_dialog_get_apply_to_all (NemoFileConflictDialog *dialog); #endif /* NEMO_FILE_CONFLICT_DIALOG_H */ nemo-4.4.2/libnemo-private/nemo-file-dnd.c000066400000000000000000000066261357442400300203520ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-drag.c - Drag & drop handling code that operated on NemoFile objects. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Pavel Cisler , */ #include #include "nemo-file-dnd.h" #include "nemo-desktop-icon-file.h" #include "nemo-dnd.h" #include "nemo-directory.h" #include "nemo-file-utilities.h" #include static gboolean nemo_drag_can_accept_files (NemoFile *drop_target_item) { NemoDirectory *directory; if (nemo_file_is_directory (drop_target_item)) { gboolean res; /* target is a directory, accept if editable */ directory = nemo_directory_get_for_file (drop_target_item); res = nemo_directory_is_editable (directory); nemo_directory_unref (directory); return res; } if (NEMO_IS_DESKTOP_ICON_FILE (drop_target_item)) { return TRUE; } /* Launchers are an acceptable drop target */ if (nemo_file_is_launcher (drop_target_item)) { return TRUE; } if (nemo_is_file_roller_installed () && nemo_file_is_archive (drop_target_item)) { return TRUE; } return FALSE; } gboolean nemo_drag_can_accept_item (NemoFile *drop_target_item, const char *item_uri) { if (nemo_file_matches_uri (drop_target_item, item_uri)) { /* can't accept itself */ return FALSE; } return nemo_drag_can_accept_files (drop_target_item); } gboolean nemo_drag_can_accept_items (NemoFile *drop_target_item, const GList *items) { int max; if (drop_target_item == NULL) return FALSE; g_assert (NEMO_IS_FILE (drop_target_item)); /* Iterate through selection checking if item will get accepted by the * drop target. If more than 100 items selected, return an over-optimisic * result */ for (max = 100; items != NULL && max >= 0; items = items->next, max--) { if (!nemo_drag_can_accept_item (drop_target_item, ((NemoDragSelectionItem *)items->data)->uri)) { return FALSE; } } return TRUE; } gboolean nemo_drag_can_accept_info (NemoFile *drop_target_item, NemoIconDndTargetType drag_type, const GList *items) { switch (drag_type) { case NEMO_ICON_DND_GNOME_ICON_LIST: return nemo_drag_can_accept_items (drop_target_item, items); case NEMO_ICON_DND_URI_LIST: case NEMO_ICON_DND_NETSCAPE_URL: case NEMO_ICON_DND_TEXT: return nemo_drag_can_accept_files (drop_target_item); case NEMO_ICON_DND_XDNDDIRECTSAVE: case NEMO_ICON_DND_RAW: return nemo_drag_can_accept_files (drop_target_item); /* Check if we can accept files at this location */ case NEMO_ICON_DND_ROOTWINDOW_DROP: return FALSE; default: g_assert_not_reached (); return FALSE; } } nemo-4.4.2/libnemo-private/nemo-file-dnd.h000066400000000000000000000031111357442400300203410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-drag.h - Drag & drop handling code that operated on NemoFile objects. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Pavel Cisler , */ #ifndef NEMO_FILE_DND_H #define NEMO_FILE_DND_H #include #include #define NEMO_FILE_DND_ERASE_KEYWORD "erase" gboolean nemo_drag_can_accept_item (NemoFile *drop_target_item, const char *item_uri); gboolean nemo_drag_can_accept_items (NemoFile *drop_target_item, const GList *items); gboolean nemo_drag_can_accept_info (NemoFile *drop_target_item, NemoIconDndTargetType drag_type, const GList *items); #endif /* NEMO_FILE_DND_H */ nemo-4.4.2/libnemo-private/nemo-file-operations.c000066400000000000000000005377201357442400300217740ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-file-operations.c - Nemo file operations. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000, 2001 Eazel, Inc. Copyright (C) 2007 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Alexander Larsson Ettore Perazzoli Pavel Cisler */ #include #include #include #include #include #include #include #include #include #include #include "nemo-file-operations.h" #include "nemo-file-changes-queue.h" #include "nemo-lib-self-check-functions.h" #include "nemo-progress-info.h" #include #include #include #include #include #include #include #include #include #include #include "nemo-file-changes-queue.h" #include "nemo-file-private.h" #include "nemo-desktop-icon-file.h" #include "nemo-desktop-link-monitor.h" #include "nemo-global-preferences.h" #include "nemo-link.h" #include "nemo-desktop-utils.h" #include "nemo-trash-monitor.h" #include "nemo-file-utilities.h" #include "nemo-file-conflict-dialog.h" #include "nemo-file-undo-operations.h" #include "nemo-file-undo-manager.h" #include "nemo-job-queue.h" /* TODO: TESTING!!! */ typedef enum { OP_KIND_COPY, OP_KIND_MOVE, OP_KIND_DELETE, OP_KIND_TRASH, OP_KIND_EMPTY_TRASH, OP_KIND_DUPE, OP_KIND_PERMISSIONS, OP_KIND_LINK, OP_KIND_CREATE, OP_KIND_TRUST } OpKind; typedef struct { GIOSchedulerJob *io_job; GTimer *time; GtkWindow *parent_window; int monitor_num; int inhibit_cookie; NemoProgressInfo *progress; GCancellable *cancellable; GHashTable *skip_files; GHashTable *skip_readdir_error; NemoFileUndoInfo *undo_info; gboolean skip_all_error; gboolean skip_all_conflict; gboolean merge_all; gboolean replace_all; gboolean delete_all; } CommonJob; typedef struct { CommonJob common; gboolean is_move; GList *files; GFile *destination; GFile *desktop_location; GFile *fake_display_source; GdkPoint *icon_positions; int n_icon_positions; GHashTable *debuting_files; gchar *target_name; NemoCopyCallback done_callback; gpointer done_callback_data; } CopyMoveJob; typedef struct { CommonJob common; GList *files; gboolean try_trash; gboolean user_cancel; NemoDeleteCallback done_callback; gpointer done_callback_data; } DeleteJob; typedef struct { CommonJob common; GFile *dest_dir; char *filename; gboolean make_dir; GFile *src; char *src_data; int length; GdkPoint position; gboolean has_position; GFile *created_file; NemoCreateCallback done_callback; gpointer done_callback_data; } CreateJob; typedef struct { CommonJob common; GList *trash_dirs; gboolean should_confirm; NemoOpCallback done_callback; gpointer done_callback_data; } EmptyTrashJob; typedef struct { CommonJob common; GFile *file; gboolean interactive; NemoOpCallback done_callback; gpointer done_callback_data; } MarkTrustedJob; typedef struct { CommonJob common; GFile *file; NemoOpCallback done_callback; gpointer done_callback_data; guint32 file_permissions; guint32 file_mask; guint32 dir_permissions; guint32 dir_mask; } SetPermissionsJob; typedef struct { int num_files; goffset num_bytes; int num_files_since_progress; OpKind op; } SourceInfo; typedef struct { int num_files; goffset num_bytes; OpKind op; guint64 last_report_time; int last_reported_files_left; } TransferInfo; #define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 8 #define US_PER_MS 1000 #define PROGRESS_UPDATE_THRESHOLD 250 #define MAXIMUM_DISPLAYED_FILE_NAME_LENGTH 50 #define IS_IO_ERROR(__error, KIND) (((__error)->domain == G_IO_ERROR && (__error)->code == G_IO_ERROR_ ## KIND)) #define SKIP _("_Skip") #define SKIP_ALL _("S_kip All") #define RETRY _("_Retry") #define DELETE_ALL _("Delete _All") #define REPLACE _("_Replace") #define REPLACE_ALL _("Replace _All") #define MERGE _("_Merge") #define MERGE_ALL _("Merge _All") #define COPY_FORCE _("Copy _Anyway") ; static void add_job_to_job_queue (GIOSchedulerJobFunc job_func, gpointer user_data, GCancellable *cancellable, NemoProgressInfo *info, OpKind kind); static void mark_desktop_file_trusted (CommonJob *common, GCancellable *cancellable, GFile *file, gboolean interactive); static gboolean is_all_button_text (const char *button_text) { g_assert (button_text != NULL); return !strcmp (button_text, SKIP_ALL) || !strcmp (button_text, REPLACE_ALL) || !strcmp (button_text, DELETE_ALL) || !strcmp (button_text, MERGE_ALL); } static void scan_sources (GList *files, SourceInfo *source_info, CommonJob *job, OpKind kind); static gboolean empty_trash_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data); static char * query_fs_type (GFile *file, GCancellable *cancellable); /* keep in time with format_time() * * This counts and outputs the number of “time units†* formatted and displayed by format_time(). * For instance, if format_time outputs “3 hours, 4 minutes†* it yields 7. */ static int seconds_count_format_time_units (int seconds) { int minutes; int hours; if (seconds < 0) { /* Just to make sure... */ seconds = 0; } if (seconds < 60) { /* seconds */ return seconds; } if (seconds < 60*60) { /* minutes */ minutes = seconds / 60; return minutes; } hours = seconds / (60*60); if (seconds < 60*60*4) { /* minutes + hours */ minutes = (seconds - hours * 60 * 60) / 60; return minutes + hours; } return hours; } static char * format_time (int seconds) { int minutes; int hours; char *res; if (seconds < 0) { /* Just to make sure... */ seconds = 0; } if (seconds < 60) { return g_strdup_printf (ngettext ("%'d second","%'d seconds", (int) seconds), (int) seconds); } if (seconds < 60*60) { minutes = seconds / 60; return g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes); } hours = seconds / (60*60); if (seconds < 60*60*4) { char *h, *m; minutes = (seconds - hours * 60 * 60) / 60; h = g_strdup_printf (ngettext ("%'d hour", "%'d hours", hours), hours); m = g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes); res = g_strconcat (h, ", ", m, NULL); g_free (h); g_free (m); return res; } return g_strdup_printf (ngettext ("approximately %'d hour", "approximately %'d hours", hours), hours); } static char * shorten_utf8_string (const char *base, int reduce_by_num_bytes) { int len; char *ret; const char *p; len = strlen (base); len -= reduce_by_num_bytes; if (len <= 0) { return NULL; } ret = g_new (char, len + 1); p = base; while (len) { char *next; next = g_utf8_next_char (p); if (next - p > len || *next == '\0') { break; } len -= next - p; p = next; } if (p - base == 0) { g_free (ret); return NULL; } else { memcpy (ret, base, p - base); ret[p - base] = '\0'; return ret; } } /* Note that we have these two separate functions with separate format * strings for ease of localization. */ static char * get_link_name (const char *name, int count, int max_length) { const char *format; char *result; int unshortened_length; gboolean use_count; g_assert (name != NULL); if (count < 0) { g_warning ("bad count in get_link_name"); count = 0; } if (count <= 2) { /* Handle special cases for low numbers. * Perhaps for some locales we will need to add more. */ switch (count) { default: g_assert_not_reached (); /* fall through */ case 0: /* duplicate original file name */ format = "%s"; break; case 1: /* appended to new link file */ format = _("Link to %s"); break; case 2: /* appended to new link file */ format = _("Another link to %s"); break; } use_count = FALSE; } else { /* Handle special cases for the first few numbers of each ten. * For locales where getting this exactly right is difficult, * these can just be made all the same as the general case below. */ switch (count % 10) { case 1: /* Localizers: Feel free to leave out the "st" suffix * if there's no way to do that nicely for a * particular language. */ format = _("%'dst link to %s"); break; case 2: /* appended to new link file */ format = _("%'dnd link to %s"); break; case 3: /* appended to new link file */ format = _("%'drd link to %s"); break; default: /* appended to new link file */ format = _("%'dth link to %s"); break; } use_count = TRUE; } if (use_count) result = g_strdup_printf (format, count, name); else result = g_strdup_printf (format, name); if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) { char *new_name; new_name = shorten_utf8_string (name, unshortened_length - max_length); if (new_name) { g_free (result); if (use_count) result = g_strdup_printf (format, count, new_name); else result = g_strdup_printf (format, new_name); g_assert ((int)strlen (result) <= max_length); g_free (new_name); } } return result; } /* Localizers: * Feel free to leave out the st, nd, rd and th suffix or * make some or all of them match. */ /* localizers: tag used to detect the first copy of a file */ static const char untranslated_copy_duplicate_tag[] = N_(" (copy)"); /* localizers: tag used to detect the second copy of a file */ static const char untranslated_another_copy_duplicate_tag[] = N_(" (another copy)"); /* localizers: tag used to detect the x11th copy of a file */ static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)"); /* localizers: tag used to detect the x12th copy of a file */ static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)"); /* localizers: tag used to detect the x13th copy of a file */ static const char untranslated_x13th_copy_duplicate_tag[] = N_("th copy)"); /* localizers: tag used to detect the x1st copy of a file */ static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)"); /* localizers: tag used to detect the x2nd copy of a file */ static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)"); /* localizers: tag used to detect the x3rd copy of a file */ static const char untranslated_rd_copy_duplicate_tag[] = N_("rd copy)"); /* localizers: tag used to detect the xxth copy of a file */ static const char untranslated_th_copy_duplicate_tag[] = N_("th copy)"); #define COPY_DUPLICATE_TAG _(untranslated_copy_duplicate_tag) #define ANOTHER_COPY_DUPLICATE_TAG _(untranslated_another_copy_duplicate_tag) #define X11TH_COPY_DUPLICATE_TAG _(untranslated_x11th_copy_duplicate_tag) #define X12TH_COPY_DUPLICATE_TAG _(untranslated_x12th_copy_duplicate_tag) #define X13TH_COPY_DUPLICATE_TAG _(untranslated_x13th_copy_duplicate_tag) #define ST_COPY_DUPLICATE_TAG _(untranslated_st_copy_duplicate_tag) #define ND_COPY_DUPLICATE_TAG _(untranslated_nd_copy_duplicate_tag) #define RD_COPY_DUPLICATE_TAG _(untranslated_rd_copy_duplicate_tag) #define TH_COPY_DUPLICATE_TAG _(untranslated_th_copy_duplicate_tag) /* localizers: appended to first file copy */ static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s"); /* localizers: appended to second file copy */ static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s"); /* localizers: appended to x11th file copy */ static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%'dth copy)%s"); /* localizers: appended to x12th file copy */ static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%'dth copy)%s"); /* localizers: appended to x13th file copy */ static const char untranslated_x13th_copy_duplicate_format[] = N_("%s (%'dth copy)%s"); /* localizers: if in your language there's no difference between 1st, 2nd, 3rd and nth * plurals, you can leave the st, nd, rd suffixes out and just make all the translated * strings look like "%s (copy %'d)%s". */ /* localizers: appended to x1st file copy */ static const char untranslated_st_copy_duplicate_format[] = N_("%s (%'dst copy)%s"); /* localizers: appended to x2nd file copy */ static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%'dnd copy)%s"); /* localizers: appended to x3rd file copy */ static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%'drd copy)%s"); /* localizers: appended to xxth file copy */ static const char untranslated_th_copy_duplicate_format[] = N_("%s (%'dth copy)%s"); #define FIRST_COPY_DUPLICATE_FORMAT _(untranslated_first_copy_duplicate_format) #define SECOND_COPY_DUPLICATE_FORMAT _(untranslated_second_copy_duplicate_format) #define X11TH_COPY_DUPLICATE_FORMAT _(untranslated_x11th_copy_duplicate_format) #define X12TH_COPY_DUPLICATE_FORMAT _(untranslated_x12th_copy_duplicate_format) #define X13TH_COPY_DUPLICATE_FORMAT _(untranslated_x13th_copy_duplicate_format) #define ST_COPY_DUPLICATE_FORMAT _(untranslated_st_copy_duplicate_format) #define ND_COPY_DUPLICATE_FORMAT _(untranslated_nd_copy_duplicate_format) #define RD_COPY_DUPLICATE_FORMAT _(untranslated_rd_copy_duplicate_format) #define TH_COPY_DUPLICATE_FORMAT _(untranslated_th_copy_duplicate_format) static char * extract_string_until (const char *original, const char *until_substring) { char *result; g_assert ((int) strlen (original) >= until_substring - original); g_assert (until_substring - original >= 0); result = g_malloc (until_substring - original + 1); strncpy (result, original, until_substring - original); result[until_substring - original] = '\0'; return result; } /* Dismantle a file name, separating the base name, the file suffix and removing any * (xxxcopy), etc. string. Figure out the count that corresponds to the given * (xxxcopy) substring. */ static void parse_previous_duplicate_name (const char *name, char **name_base, const char **suffix, int *count) { const char *tag; g_assert (name[0] != '\0'); *suffix = eel_filename_get_extension_offset (name + 1); if (*suffix == NULL || (*suffix)[1] == '\0') { /* no suffix */ *suffix = ""; } tag = strstr (name, COPY_DUPLICATE_TAG); if (tag != NULL) { if (tag > *suffix) { /* handle case "foo. (copy)" */ *suffix = ""; } *name_base = extract_string_until (name, tag); *count = 1; return; } tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAG); if (tag != NULL) { if (tag > *suffix) { /* handle case "foo. (another copy)" */ *suffix = ""; } *name_base = extract_string_until (name, tag); *count = 2; return; } /* Check to see if we got one of st, nd, rd, th. */ tag = strstr (name, X11TH_COPY_DUPLICATE_TAG); if (tag == NULL) { tag = strstr (name, X12TH_COPY_DUPLICATE_TAG); } if (tag == NULL) { tag = strstr (name, X13TH_COPY_DUPLICATE_TAG); } if (tag == NULL) { tag = strstr (name, ST_COPY_DUPLICATE_TAG); } if (tag == NULL) { tag = strstr (name, ND_COPY_DUPLICATE_TAG); } if (tag == NULL) { tag = strstr (name, RD_COPY_DUPLICATE_TAG); } if (tag == NULL) { tag = strstr (name, TH_COPY_DUPLICATE_TAG); } /* If we got one of st, nd, rd, th, fish out the duplicate number. */ if (tag != NULL) { /* localizers: opening parentheses to match the "th copy)" string */ tag = strstr (name, _(" (")); if (tag != NULL) { if (tag > *suffix) { /* handle case "foo. (22nd copy)" */ *suffix = ""; } *name_base = extract_string_until (name, tag); /* localizers: opening parentheses of the "th copy)" string */ if (sscanf (tag, _(" (%'d"), count) == 1) { if (*count < 1 || *count > 1000000) { /* keep the count within a reasonable range */ *count = 0; } return; } *count = 0; return; } } *count = 0; if (**suffix != '\0') { *name_base = extract_string_until (name, *suffix); } else { *name_base = g_strdup (name); } } static char * make_next_duplicate_name (const char *base, const char *suffix, int count, int max_length) { const char *format; char *result; int unshortened_length; gboolean use_count; if (count < 1) { g_warning ("bad count %d in get_duplicate_name", count); count = 1; } if (count <= 2) { /* Handle special cases for low numbers. * Perhaps for some locales we will need to add more. */ switch (count) { default: g_assert_not_reached (); /* fall through */ case 1: format = FIRST_COPY_DUPLICATE_FORMAT; break; case 2: format = SECOND_COPY_DUPLICATE_FORMAT; break; } use_count = FALSE; } else { /* Handle special cases for the first few numbers of each ten. * For locales where getting this exactly right is difficult, * these can just be made all the same as the general case below. */ /* Handle special cases for x11th - x20th. */ switch (count % 100) { case 11: format = X11TH_COPY_DUPLICATE_FORMAT; break; case 12: format = X12TH_COPY_DUPLICATE_FORMAT; break; case 13: format = X13TH_COPY_DUPLICATE_FORMAT; break; default: format = NULL; break; } if (format == NULL) { switch (count % 10) { case 1: format = ST_COPY_DUPLICATE_FORMAT; break; case 2: format = ND_COPY_DUPLICATE_FORMAT; break; case 3: format = RD_COPY_DUPLICATE_FORMAT; break; default: /* The general case. */ format = TH_COPY_DUPLICATE_FORMAT; break; } } use_count = TRUE; } if (use_count) result = g_strdup_printf (format, base, count, suffix); else result = g_strdup_printf (format, base, suffix); if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) { char *new_base; new_base = shorten_utf8_string (base, unshortened_length - max_length); if (new_base) { g_free (result); if (use_count) result = g_strdup_printf (format, new_base, count, suffix); else result = g_strdup_printf (format, new_base, suffix); g_assert ((int)strlen (result) <= max_length); g_free (new_base); } } return result; } static char * get_duplicate_name (const char *name, int count_increment, int max_length) { char *result; char *name_base; const char *suffix; int count; parse_previous_duplicate_name (name, &name_base, &suffix, &count); result = make_next_duplicate_name (name_base, suffix, count + count_increment, max_length); g_free (name_base); return result; } static gboolean has_invalid_xml_char (char *str) { gunichar c; while (*str != 0) { c = g_utf8_get_char (str); /* characters XML permits */ if (!(c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF))) { return TRUE; } str = g_utf8_next_char (str); } return FALSE; } static char * custom_full_name_to_string (char *format, va_list va) { GFile *file; file = va_arg (va, GFile *); return g_file_get_parse_name (file); } static void custom_full_name_skip (va_list *va) { (void) va_arg (*va, GFile *); } static char * custom_basename_to_string (char *format, va_list va) { GFile *file; GFileInfo *info; char *name, *basename, *tmp; file = va_arg (va, GFile *); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 0, g_cancellable_get_current (), NULL); name = NULL; if (info) { name = g_strdup (g_file_info_get_display_name (info)); g_object_unref (info); } if (name == NULL) { basename = g_file_get_basename (file); if (g_utf8_validate (basename, -1, NULL)) { name = basename; } else { name = g_uri_escape_string (basename, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); g_free (basename); } } /* Some chars can't be put in the markup we use for the dialogs... */ if (has_invalid_xml_char (name)) { tmp = name; name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); g_free (tmp); } /* Finally, if the string is too long, truncate it. */ if (name != NULL) { tmp = name; name = eel_str_middle_truncate (tmp, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH); g_free (tmp); } return name; } static void custom_basename_skip (va_list *va) { (void) va_arg (*va, GFile *); } static char * custom_size_to_string (char *format, va_list va) { goffset size; size = va_arg (va, goffset); int prefix; prefix = nemo_global_preferences_get_size_prefix_preference (); return g_format_size_full (size, prefix); } static void custom_size_skip (va_list *va) { (void) va_arg (*va, goffset); } static char * custom_time_to_string (char *format, va_list va) { int secs; secs = va_arg (va, int); return format_time (secs); } static void custom_time_skip (va_list *va) { (void) va_arg (*va, int); } static char * custom_mount_to_string (char *format, va_list va) { GMount *mount; mount = va_arg (va, GMount *); return g_mount_get_name (mount); } static void custom_mount_skip (va_list *va) { (void) va_arg (*va, GMount *); } static EelPrintfHandler handlers[] = { { 'F', custom_full_name_to_string, custom_full_name_skip }, { 'B', custom_basename_to_string, custom_basename_skip }, { 'S', custom_size_to_string, custom_size_skip }, { 'T', custom_time_to_string, custom_time_skip }, { 'V', custom_mount_to_string, custom_mount_skip }, { 0 } }; static char * f (const char *format, ...) { va_list va; char *res; va_start (va, format); res = eel_strdup_vprintf_with_custom (handlers, format, va); va_end (va); return res; } static void get_best_name (GFile *file, gchar **name) { gchar *out; if (g_file_is_native (file)) { gchar *path = g_file_get_path (file); if (g_str_has_prefix (path, g_get_home_dir ())) { GString *str = g_string_new (path); str = g_string_erase (str, 0, strlen (g_get_home_dir ())); str = g_string_prepend (str, "~"); out = g_string_free (str, FALSE); } else { out = g_strdup (path); } g_free (path); } else { out = g_file_get_basename (file); } *name = out; } static void get_parent_name (GFile *file, gchar **name) { GFile *parent = g_file_get_parent (file); if (!parent) return; gchar *get = NULL; get_best_name (parent, &get); g_object_unref (parent); *name = get; } /* adapted from gio/glocalfile.c */ static gboolean _g_local_file_delete (GFile *file, GCancellable *cancellable, GError **error) { gchar *path; path = g_file_get_path (file); if (g_remove (path) == -1) { int errsv = errno; /* Posix allows EEXIST too, but the more sane error is G_IO_ERROR_NOT_FOUND, and it's what nautilus expects */ if (errsv == EEXIST) { errsv = ENOTEMPTY; } g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error removing file: %s"), g_strerror (errsv)); g_free (path); return FALSE; } g_free (path); return TRUE; } static gboolean file_delete_wrapper (GFile *file, GCancellable *cancellable, GError **error) { gboolean ret; ret = FALSE; if (g_file_is_native (file)) { ret = _g_local_file_delete (file, cancellable, error); } else { ret = g_file_delete (file, cancellable, error); } return ret; } static void generate_initial_job_details (NemoProgressInfo *info, OpKind kind, GList *files, GFile *destination) { gchar *s = NULL; gchar *dest_name = NULL; gchar *src_name = NULL; if (destination != NULL) get_best_name (destination, &dest_name); if (files != NULL) get_parent_name (files->data, &src_name); switch (kind) { case OP_KIND_COPY: g_return_if_fail (files != NULL); g_return_if_fail (destination != NULL); s = f (ngettext("Waiting to copy a file from '%1$s' to '%2$s'", "Waiting to copy files from '%1$s' to '%2$s'", g_list_length (files)), src_name, dest_name); break; case OP_KIND_MOVE: g_return_if_fail (files != NULL); g_return_if_fail (destination != NULL); s = f (ngettext("Waiting to move a file from '%1$s' to '%2$s'", "Waiting to move files from '%1$s' to '%2$s'", g_list_length (files)), src_name, dest_name); break; case OP_KIND_DELETE: g_return_if_fail (files != NULL); s = f (ngettext("Waiting to permanently delete a file from '%s'", "Waiting to permanently delete files from '%s'", g_list_length (files)), src_name); break; case OP_KIND_TRASH: g_return_if_fail (files != NULL); s = f (ngettext("Waiting to trash a file in '%s'", "Waiting to trash files in '%s'", g_list_length (files)), src_name); break; case OP_KIND_EMPTY_TRASH: s = f (_("Waiting to empty the trash")); break; case OP_KIND_DUPE: g_return_if_fail (files != NULL); g_return_if_fail (destination != NULL); s = f (ngettext("Waiting to duplicate a file in '%s'", "Waiting to duplicate files in '%s'", g_list_length (files)), dest_name); break; case OP_KIND_PERMISSIONS: g_return_if_fail (destination != NULL); s = f (_("Waiting to change permissions of files in '%s'"), dest_name); break; case OP_KIND_LINK: g_return_if_fail (files != NULL); g_return_if_fail (destination != NULL); s = f (ngettext("Waiting to link a file from '%1$s' to '%2$s'", "Waiting to link files from '%1$s' to '%2$s'", g_list_length (files)), src_name, dest_name); break; case OP_KIND_TRUST: case OP_KIND_CREATE: default: break; } g_free (dest_name); g_free (src_name); nemo_progress_info_take_initial_details (info, s); } #define op_job_new(__type, parent_window) ((__type *)(init_common (sizeof(__type), parent_window))) static gpointer init_common (gsize job_size, GtkWindow *parent_window) { CommonJob *common; common = g_malloc0 (job_size); if (parent_window) { common->parent_window = parent_window; g_object_add_weak_pointer (G_OBJECT (common->parent_window), (gpointer *) &common->parent_window); } common->progress = nemo_progress_info_new (); common->cancellable = nemo_progress_info_get_cancellable (common->progress); common->time = g_timer_new (); common->inhibit_cookie = -1; common->monitor_num = 0; if (parent_window) { common->monitor_num = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (parent_window)); } return common; } static void finalize_common (CommonJob *common) { nemo_progress_info_finish (common->progress); if (common->inhibit_cookie != -1) { nemo_uninhibit_power_manager (common->inhibit_cookie); } common->inhibit_cookie = -1; g_timer_destroy (common->time); if (common->parent_window) { g_object_remove_weak_pointer (G_OBJECT (common->parent_window), (gpointer *) &common->parent_window); } if (common->skip_files) { g_hash_table_destroy (common->skip_files); } if (common->skip_readdir_error) { g_hash_table_destroy (common->skip_readdir_error); } if (common->undo_info != NULL) { nemo_file_undo_manager_set_action (common->undo_info); g_object_unref (common->undo_info); } g_object_unref (common->progress); g_object_unref (common->cancellable); g_free (common); } static void skip_file (CommonJob *common, GFile *file) { if (common->skip_files == NULL) { common->skip_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); } g_hash_table_insert (common->skip_files, g_object_ref (file), file); } static void skip_readdir_error (CommonJob *common, GFile *dir) { if (common->skip_readdir_error == NULL) { common->skip_readdir_error = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); } g_hash_table_insert (common->skip_readdir_error, g_object_ref (dir), dir); } static gboolean should_skip_file (CommonJob *common, GFile *file) { if (common->skip_files != NULL) { return g_hash_table_lookup (common->skip_files, file) != NULL; } return FALSE; } static gboolean should_skip_readdir_error (CommonJob *common, GFile *dir) { if (common->skip_readdir_error != NULL) { return g_hash_table_lookup (common->skip_readdir_error, dir) != NULL; } return FALSE; } static gboolean can_delete_without_confirm (GFile *file) { if (g_file_has_uri_scheme (file, "burn") || g_file_has_uri_scheme (file, "recent") || g_file_has_uri_scheme (file, "x-nemo-desktop")) { return TRUE; } return FALSE; } static gboolean can_delete_files_without_confirm (GList *files) { g_assert (files != NULL); while (files != NULL) { if (!can_delete_without_confirm (files->data)) { return FALSE; } files = files->next; } return TRUE; } typedef struct { GtkWindow **parent_window; gboolean ignore_close_box; GtkMessageType message_type; const char *primary_text; const char *secondary_text; const char *details_text; const char **button_titles; gboolean show_all; int result; } RunSimpleDialogData; static gboolean do_run_simple_dialog (gpointer _data) { RunSimpleDialogData *data = _data; const char *button_title; GtkWidget *dialog; int result; int response_id; /* Create the dialog. */ dialog = gtk_message_dialog_new (*data->parent_window, 0, data->message_type, GTK_BUTTONS_NONE, NULL); g_object_set (dialog, "text", data->primary_text, "secondary-text", data->secondary_text, NULL); for (response_id = 0; data->button_titles[response_id] != NULL; response_id++) { button_title = data->button_titles[response_id]; if (!data->show_all && is_all_button_text (button_title)) { continue; } gtk_dialog_add_button (GTK_DIALOG (dialog), button_title, response_id); } if (response_id > 1) { if (button_title == _("Empty _Trash")) { gtk_dialog_set_default_response (GTK_DIALOG (dialog), 0); } else { gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id - 1); } } if (data->details_text) { eel_gtk_message_dialog_set_details_label (GTK_MESSAGE_DIALOG (dialog), data->details_text); } /* Run it. */ result = gtk_dialog_run (GTK_DIALOG (dialog)); while ((result == GTK_RESPONSE_NONE || result == GTK_RESPONSE_DELETE_EVENT) && data->ignore_close_box) { result = gtk_dialog_run (GTK_DIALOG (dialog)); } gtk_widget_destroy (dialog); data->result = result; return FALSE; } /* NOTE: This frees the primary / secondary strings, in order to avoid doing that everywhere. So, make sure they are strduped */ static int run_simple_dialog_va (CommonJob *job, gboolean ignore_close_box, GtkMessageType message_type, char *primary_text, char *secondary_text, const char *details_text, gboolean show_all, va_list varargs) { RunSimpleDialogData *data; int res; const char *button_title; GPtrArray *ptr_array; g_timer_stop (job->time); data = g_new0 (RunSimpleDialogData, 1); data->parent_window = &job->parent_window; data->ignore_close_box = ignore_close_box; data->message_type = message_type; data->primary_text = primary_text; data->secondary_text = secondary_text; data->details_text = details_text; data->show_all = show_all; ptr_array = g_ptr_array_new (); while ((button_title = va_arg (varargs, const char *)) != NULL) { g_ptr_array_add (ptr_array, (char *)button_title); } g_ptr_array_add (ptr_array, NULL); data->button_titles = (const char **)g_ptr_array_free (ptr_array, FALSE); nemo_progress_info_pause (job->progress); g_io_scheduler_job_send_to_mainloop (job->io_job, do_run_simple_dialog, data, NULL); nemo_progress_info_resume (job->progress); res = data->result; g_free (data->button_titles); g_free (data); g_timer_continue (job->time); g_free (primary_text); g_free (secondary_text); return res; } #if 0 /* Not used at the moment */ static int run_simple_dialog (CommonJob *job, gboolean ignore_close_box, GtkMessageType message_type, char *primary_text, char *secondary_text, const char *details_text, ...) { va_list varargs; int res; va_start (varargs, details_text); res = run_simple_dialog_va (job, ignore_close_box, message_type, primary_text, secondary_text, details_text, varargs); va_end (varargs); return res; } #endif static int run_error (CommonJob *job, char *primary_text, char *secondary_text, const char *details_text, gboolean show_all, ...) { va_list varargs; int res; va_start (varargs, show_all); res = run_simple_dialog_va (job, FALSE, GTK_MESSAGE_ERROR, primary_text, secondary_text, details_text, show_all, varargs); va_end (varargs); return res; } static int run_warning (CommonJob *job, char *primary_text, char *secondary_text, const char *details_text, gboolean show_all, ...) { va_list varargs; int res; va_start (varargs, show_all); res = run_simple_dialog_va (job, FALSE, GTK_MESSAGE_WARNING, primary_text, secondary_text, details_text, show_all, varargs); va_end (varargs); return res; } static int run_question (CommonJob *job, char *primary_text, char *secondary_text, const char *details_text, gboolean show_all, ...) { va_list varargs; int res; va_start (varargs, show_all); res = run_simple_dialog_va (job, FALSE, GTK_MESSAGE_QUESTION, primary_text, secondary_text, details_text, show_all, varargs); va_end (varargs); return res; } static void inhibit_power_manager (CommonJob *job, const char *message) { job->inhibit_cookie = nemo_inhibit_power_manager (message); } static void abort_job (CommonJob *job) { /* destroy the undo action data too */ g_clear_object (&job->undo_info); g_cancellable_cancel (job->cancellable); } static gboolean job_aborted (CommonJob *job) { return g_cancellable_is_cancelled (job->cancellable); } /* Since this happens on a thread we can't use the global prefs object */ static gboolean should_confirm_move_to_trash (void) { gboolean confirm_move_to_trash; confirm_move_to_trash = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CONFIRM_MOVE_TO_TRASH); return confirm_move_to_trash; } static gboolean confirm_move_to_trash (CommonJob *job, GList *files) { char *prompt; int file_count; int response; /* Just Say Yes if the preference says not to confirm. */ if (!should_confirm_move_to_trash ()) { return TRUE; } file_count = g_list_length (files); g_assert (file_count > 0); if (file_count == 1) { prompt = f (_("Are you sure you want to move \"%B\" " "to the trash?"), files->data); } else { /* translators: the singular form here can be skipped. */ prompt = f (ngettext("unused %'d", "Are you sure you want to move " "the %'d selected items to the trash?", file_count), file_count); } response = run_warning (job, prompt, f (_("You can restore an item from the trash, if you later change your mind.")), NULL, FALSE, GTK_STOCK_CANCEL, _("Move to _Trash"), NULL); return (response == 1); } static gboolean should_confirm_trash (void) { gboolean confirm_trash; confirm_trash = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CONFIRM_TRASH); return confirm_trash; } static gboolean confirm_delete_from_trash (CommonJob *job, GList *files) { char *prompt; int file_count; int response; /* Just Say Yes if the preference says not to confirm. */ if (!should_confirm_trash ()) { return TRUE; } file_count = g_list_length (files); g_assert (file_count > 0); if (file_count == 1) { prompt = f (_("Are you sure you want to permanently delete \"%B\" " "from the trash?"), files->data); } else { prompt = f (ngettext("Are you sure you want to permanently delete " "the %'d selected item from the trash?", "Are you sure you want to permanently delete " "the %'d selected items from the trash?", file_count), file_count); } response = run_warning (job, prompt, f (_("If you delete an item, it will be permanently lost.")), NULL, FALSE, GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL); return (response == 1); } static gboolean confirm_empty_trash (CommonJob *job) { char *prompt; int response; /* Just Say Yes if the preference says not to confirm. */ if (!should_confirm_trash ()) { return TRUE; } prompt = f (_("Empty all items from Trash?")); response = run_warning (job, prompt, f(_("All items in the Trash will be permanently deleted.")), NULL, FALSE, GTK_STOCK_CANCEL, _("Empty _Trash"), NULL); return (response == 1); } static gboolean confirm_delete_directly (CommonJob *job, GList *files) { char *prompt; int file_count; int response; /* Just Say Yes if the preference says not to confirm. */ if (!should_confirm_trash ()) { return TRUE; } file_count = g_list_length (files); g_assert (file_count > 0); if (can_delete_files_without_confirm (files)) { return TRUE; } if (file_count == 1) { prompt = f (_("Are you sure you want to permanently delete \"%B\"?"), files->data); } else { prompt = f (ngettext("Are you sure you want to permanently delete " "the %'d selected item?", "Are you sure you want to permanently delete " "the %'d selected items?", file_count), file_count); } response = run_warning (job, prompt, f (_("If you delete an item, it will be permanently lost.")), NULL, FALSE, GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL); return response == 1; } static void report_delete_progress (CommonJob *job, SourceInfo *source_info, TransferInfo *transfer_info) { int files_left; double elapsed, transfer_rate; int remaining_time; gint64 now; char *files_left_s; now = g_get_monotonic_time (); if (transfer_info->last_report_time != 0 && ABS ((gint64)(transfer_info->last_report_time - now)) < PROGRESS_UPDATE_THRESHOLD * US_PER_MS) { return; } transfer_info->last_report_time = now; files_left = source_info->num_files - transfer_info->num_files; /* Races and whatnot could cause this to be negative... */ if (files_left < 0) { files_left = 1; } files_left_s = f (ngettext ("%'d file left to delete", "%'d files left to delete", files_left), files_left); nemo_progress_info_take_status (job->progress, f (_("Deleting files"))); elapsed = g_timer_elapsed (job->time, NULL); if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) { nemo_progress_info_set_details (job->progress, files_left_s); } else { char *details, *time_left_s; transfer_rate = transfer_info->num_files / elapsed; remaining_time = files_left / transfer_rate; /* To translators: %T will expand to a time like "2 minutes". * The singular/plural form will be used depending on the remaining time (i.e. the %T argument). */ time_left_s = f (ngettext ("%T left", "%T left", seconds_count_format_time_units (remaining_time)), remaining_time); details = g_strconcat (files_left_s, "\xE2\x80\x94", time_left_s, NULL); nemo_progress_info_take_details (job->progress, details); g_free (time_left_s); } g_free (files_left_s); if (source_info->num_files != 0) { nemo_progress_info_set_progress (job->progress, transfer_info->num_files, source_info->num_files); } } static void delete_file (CommonJob *job, GFile *file, gboolean *skipped_file, SourceInfo *source_info, TransferInfo *transfer_info, gboolean toplevel); static void delete_dir (CommonJob *job, GFile *dir, gboolean *skipped_file, SourceInfo *source_info, TransferInfo *transfer_info, gboolean toplevel) { GFileInfo *info; GError *error; GFile *file; GFileEnumerator *enumerator; char *primary, *secondary, *details; int response; gboolean skip_error; gboolean local_skipped_file; local_skipped_file = FALSE; skip_error = should_skip_readdir_error (job, dir); retry: error = NULL; enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, &error); if (enumerator) { error = NULL; while (!job_aborted (job) && (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) { file = g_file_get_child (dir, g_file_info_get_name (info)); delete_file (job, file, &local_skipped_file, source_info, transfer_info, FALSE); g_object_unref (file); g_object_unref (info); } g_file_enumerator_close (enumerator, job->cancellable, NULL); g_object_unref (enumerator); if (error && IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else if (error) { primary = f (_("Error while deleting.")); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("Files in the folder \"%B\" cannot be deleted because you do " "not have permissions to see them."), dir); } else { secondary = f (_("There was an error getting information about the files in the folder \"%B\"."), dir); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, _("_Skip files"), NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* Skip: Do Nothing */ local_skipped_file = TRUE; } else { g_assert_not_reached (); } } } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { primary = f (_("Error while deleting.")); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("The folder \"%B\" cannot be deleted because you do not have " "permissions to read it."), dir); } else { secondary = f (_("There was an error reading the folder \"%B\"."), dir); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, SKIP, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* Skip: Do Nothing */ local_skipped_file = TRUE; } else if (response == 2) { goto retry; } else { g_assert_not_reached (); } } if (!job_aborted (job) && /* Don't delete dir if there was a skipped file */ !local_skipped_file) { if (!file_delete_wrapper (dir, job->cancellable, &error)) { if (job->skip_all_error) { goto skip; } primary = f (_("Error while deleting.")); secondary = f (_("Could not remove the folder %B."), dir); details = error->message; response = run_warning (job, primary, secondary, details, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; local_skipped_file = TRUE; } else if (response == 2) { /* skip */ local_skipped_file = TRUE; } else { g_assert_not_reached (); } skip: g_error_free (error); } else { nemo_file_changes_queue_file_removed (dir); transfer_info->num_files ++; report_delete_progress (job, source_info, transfer_info); return; } } if (local_skipped_file) { *skipped_file = TRUE; } } static void delete_file (CommonJob *job, GFile *file, gboolean *skipped_file, SourceInfo *source_info, TransferInfo *transfer_info, gboolean toplevel) { GError *error; char *primary, *secondary, *details; int response; if (should_skip_file (job, file)) { *skipped_file = TRUE; return; } error = NULL; if (file_delete_wrapper (file, job->cancellable, &error)) { nemo_file_changes_queue_file_removed (file); transfer_info->num_files ++; report_delete_progress (job, source_info, transfer_info); return; } if (IS_IO_ERROR (error, NOT_EMPTY)) { g_error_free (error); delete_dir (job, file, skipped_file, source_info, transfer_info, toplevel); return; } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { if (job->skip_all_error) { goto skip; } primary = f (_("Error while deleting.")); secondary = f (_("There was an error deleting %B."), file); details = error->message; response = run_warning (job, primary, secondary, details, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } skip: g_error_free (error); } *skipped_file = TRUE; } static void delete_files (CommonJob *job, GList *files, guint *files_skipped) { GList *l; GFile *file; SourceInfo source_info; TransferInfo transfer_info; gboolean skipped_file; if (job_aborted (job)) { return; } scan_sources (files, &source_info, job, OP_KIND_DELETE); if (job_aborted (job)) { return; } g_timer_start (job->time); memset (&transfer_info, 0, sizeof (transfer_info)); report_delete_progress (job, &source_info, &transfer_info); for (l = files; l != NULL && !job_aborted (job); l = l->next) { file = l->data; skipped_file = FALSE; delete_file (job, file, &skipped_file, &source_info, &transfer_info, TRUE); if (skipped_file) { (*files_skipped)++; } } } static void report_trash_progress (CommonJob *job, int files_trashed, int total_files) { int files_left; char *s; files_left = total_files - files_trashed; nemo_progress_info_take_status (job->progress, f (_("Moving files to trash"))); s = f (ngettext ("%'d file left to trash", "%'d files left to trash", files_left), files_left); nemo_progress_info_take_details (job->progress, s); if (total_files != 0) { nemo_progress_info_set_progress (job->progress, files_trashed, total_files); } } static void trash_files (CommonJob *job, GList *files, guint *files_skipped) { GList *l; GFile *file; GList *to_delete; GError *error; int total_files, files_trashed; char *primary, *secondary, *details; int response; if (job_aborted (job)) { return; } total_files = g_list_length (files); files_trashed = 0; report_trash_progress (job, files_trashed, total_files); to_delete = NULL; for (l = files; l != NULL && !job_aborted (job); l = l->next) { file = l->data; error = NULL; if (!g_file_trash (file, job->cancellable, &error)) { if (job->skip_all_error) { (*files_skipped)++; goto skip; } if (job->delete_all) { to_delete = g_list_prepend (to_delete, file); goto skip; } primary = f (_("Cannot move file to trash, do you want to delete immediately?")); secondary = f (_("The file \"%B\" cannot be moved to the trash."), file); details = NULL; if (!IS_IO_ERROR (error, NOT_SUPPORTED)) { details = error->message; } response = run_question (job, primary, secondary, details, (total_files - files_trashed) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, DELETE_ALL, GTK_STOCK_DELETE, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { ((DeleteJob *) job)->user_cancel = TRUE; abort_job (job); } else if (response == 1) { /* skip all */ (*files_skipped)++; job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ (*files_skipped)++; } else if (response == 3) { /* delete all */ to_delete = g_list_prepend (to_delete, file); job->delete_all = TRUE; } else if (response == 4) { /* delete */ to_delete = g_list_prepend (to_delete, file); } skip: g_error_free (error); total_files--; } else { nemo_file_changes_queue_file_removed (file); if (job->undo_info != NULL) { nemo_file_undo_info_trash_add_file (NEMO_FILE_UNDO_INFO_TRASH (job->undo_info), file); } files_trashed++; report_trash_progress (job, files_trashed, total_files); } } if (to_delete) { to_delete = g_list_reverse (to_delete); delete_files (job, to_delete, files_skipped); g_list_free (to_delete); } } static gboolean delete_job_done (gpointer user_data) { DeleteJob *job; GHashTable *debuting_uris; job = user_data; g_list_free_full (job->files, g_object_unref); if (job->done_callback) { debuting_uris = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); job->done_callback (debuting_uris, job->user_cancel, job->done_callback_data); g_hash_table_unref (debuting_uris); } finalize_common ((CommonJob *)job); nemo_file_changes_consume_changes (TRUE); return FALSE; } static gboolean delete_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { DeleteJob *job = user_data; GList *to_trash_files; GList *to_delete_files; GList *l; GFile *file; gboolean confirmed; CommonJob *common; gboolean must_confirm_delete_in_trash; gboolean must_confirm_delete; guint files_skipped; common = (CommonJob *)job; common->io_job = io_job; nemo_progress_info_start (common->progress); to_trash_files = NULL; to_delete_files = NULL; must_confirm_delete_in_trash = FALSE; must_confirm_delete = FALSE; files_skipped = 0; for (l = job->files; l != NULL; l = l->next) { file = l->data; if (job->try_trash && g_file_has_uri_scheme (file, "trash")) { must_confirm_delete_in_trash = TRUE; to_delete_files = g_list_prepend (to_delete_files, file); } else if (can_delete_without_confirm (file)) { to_delete_files = g_list_prepend (to_delete_files, file); } else { if (job->try_trash) { to_trash_files = g_list_prepend (to_trash_files, file); } else { must_confirm_delete = TRUE; to_delete_files = g_list_prepend (to_delete_files, file); } } } if (to_delete_files != NULL && !job_aborted (common)) { to_delete_files = g_list_reverse (to_delete_files); confirmed = TRUE; if (must_confirm_delete_in_trash) { confirmed = confirm_delete_from_trash (common, to_delete_files); } else if (must_confirm_delete) { confirmed = confirm_delete_directly (common, to_delete_files); } if (confirmed) { delete_files (common, to_delete_files, &files_skipped); } else { job->user_cancel = TRUE; } } if (to_trash_files != NULL && !job_aborted (common)) { to_trash_files = g_list_reverse (to_trash_files); confirmed = confirm_move_to_trash (common, to_trash_files); if (confirmed) { trash_files (common, to_trash_files, &files_skipped); } else { job->user_cancel = TRUE; /* destroy the undo action data too */ g_clear_object (&common->undo_info); } } g_list_free (to_trash_files); g_list_free (to_delete_files); if (files_skipped == g_list_length (job->files)) { /* User has skipped all files, report user cancel */ job->user_cancel = TRUE; } g_io_scheduler_job_send_to_mainloop_async (io_job, delete_job_done, job, NULL); return FALSE; } static void trash_or_delete_internal (GList *files, GtkWindow *parent_window, gboolean try_trash, NemoDeleteCallback done_callback, gpointer done_callback_data) { DeleteJob *job; /* TODO: special case desktop icon link files ... */ job = op_job_new (DeleteJob, parent_window); job->files = eel_g_object_list_copy (files); job->try_trash = try_trash; job->user_cancel = FALSE; job->done_callback = done_callback; job->done_callback_data = done_callback_data; if (try_trash) { inhibit_power_manager ((CommonJob *)job, _("Trashing Files")); } else { inhibit_power_manager ((CommonJob *)job, _("Deleting Files")); } if (try_trash && !nemo_file_undo_manager_pop_flag ()) { job->common.undo_info = nemo_file_undo_info_trash_new (g_list_length (files)); } generate_initial_job_details (job->common.progress, try_trash ? OP_KIND_TRASH : OP_KIND_DELETE, job->files, NULL); add_job_to_job_queue (delete_job, job, job->common.cancellable, job->common.progress, try_trash ? OP_KIND_TRASH : OP_KIND_DELETE); } void nemo_file_operations_trash_or_delete (GList *files, GtkWindow *parent_window, NemoDeleteCallback done_callback, gpointer done_callback_data) { g_return_if_fail (files != NULL); trash_or_delete_internal (files, parent_window, TRUE, done_callback, done_callback_data); } void nemo_file_operations_delete (GList *files, GtkWindow *parent_window, NemoDeleteCallback done_callback, gpointer done_callback_data) { trash_or_delete_internal (files, parent_window, FALSE, done_callback, done_callback_data); } typedef struct { gboolean eject; GMount *mount; GMountOperation *mount_operation; GtkWindow *parent_window; NemoUnmountCallback callback; gpointer callback_data; } UnmountData; static void unmount_data_free (UnmountData *data) { if (data->parent_window) { g_object_remove_weak_pointer (G_OBJECT (data->parent_window), (gpointer *) &data->parent_window); } g_clear_object (&data->mount_operation); g_object_unref (data->mount); g_free (data); } static void unmount_mount_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { UnmountData *data = user_data; GError *error; char *primary; gboolean unmounted; error = NULL; if (data->eject) { unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error); } else { unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object), res, &error); } if (! unmounted) { if (error->code != G_IO_ERROR_FAILED_HANDLED) { if (data->eject) { primary = f (_("Unable to eject %V"), source_object); } else { primary = f (_("Unable to unmount %V"), source_object); } eel_show_error_dialog (primary, error->message, data->parent_window); g_free (primary); } } if (data->callback) { data->callback (data->callback_data); } if (error != NULL) { g_error_free (error); } unmount_data_free (data); } static void do_unmount (UnmountData *data) { GMountOperation *mount_op; if (data->mount_operation) { mount_op = g_object_ref (data->mount_operation); } else { mount_op = gtk_mount_operation_new (data->parent_window); } if (data->eject) { g_mount_eject_with_operation (data->mount, 0, mount_op, NULL, unmount_mount_callback, data); } else { g_mount_unmount_with_operation (data->mount, 0, mount_op, NULL, unmount_mount_callback, data); } g_object_unref (mount_op); } static gboolean dir_has_files (GFile *dir) { GFileEnumerator *enumerator; gboolean res; GFileInfo *file_info; res = FALSE; enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); if (enumerator) { file_info = g_file_enumerator_next_file (enumerator, NULL, NULL); if (file_info != NULL) { res = TRUE; g_object_unref (file_info); } g_file_enumerator_close (enumerator, NULL, NULL); g_object_unref (enumerator); } return res; } static GList * get_trash_dirs_for_mount (GMount *mount) { GFile *root; GFile *trash; char *relpath; GList *list; root = g_mount_get_root (mount); if (root == NULL) { return NULL; } list = NULL; if (g_file_is_native (root)) { relpath = g_strdup_printf (".Trash/%d", getuid ()); trash = g_file_resolve_relative_path (root, relpath); g_free (relpath); list = g_list_prepend (list, g_file_get_child (trash, "files")); list = g_list_prepend (list, g_file_get_child (trash, "info")); g_object_unref (trash); relpath = g_strdup_printf (".Trash-%d", getuid ()); trash = g_file_get_child (root, relpath); g_free (relpath); list = g_list_prepend (list, g_file_get_child (trash, "files")); list = g_list_prepend (list, g_file_get_child (trash, "info")); g_object_unref (trash); } g_object_unref (root); return list; } static gboolean has_trash_files (GMount *mount) { GList *dirs, *l; GFile *dir; gboolean res; dirs = get_trash_dirs_for_mount (mount); res = FALSE; for (l = dirs; l != NULL; l = l->next) { dir = l->data; if (dir_has_files (dir)) { res = TRUE; break; } } g_list_free_full (dirs, g_object_unref); return res; } static gint prompt_empty_trash (GtkWindow *parent_window) { gint result; GtkWidget *dialog; GdkScreen *screen; screen = NULL; if (parent_window != NULL) { screen = gtk_widget_get_screen (GTK_WIDGET (parent_window)); } /* Do we need to be modal ? */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Do you want to empty the trash before you unmount?")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("In order to regain the " "free space on this volume " "the trash must be emptied. " "All trashed items on the volume " "will be permanently lost.")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Do _not Empty Trash"), GTK_RESPONSE_REJECT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("Empty _Trash"), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT); gtk_window_set_title (GTK_WINDOW (dialog), ""); /* as per HIG */ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); if (screen) { gtk_window_set_screen (GTK_WINDOW (dialog), screen); } atk_object_set_role (gtk_widget_get_accessible (dialog), ATK_ROLE_ALERT); gtk_window_set_wmclass (GTK_WINDOW (dialog), "empty_trash", "Nemo"); /* Make transient for the window group */ gtk_widget_realize (dialog); if (screen != NULL) { gdk_window_set_transient_for (gtk_widget_get_window (GTK_WIDGET (dialog)), gdk_screen_get_root_window (screen)); } result = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return result; } static void empty_trash_for_unmount_done (gboolean success, gpointer user_data) { UnmountData *data = user_data; do_unmount (data); } void nemo_file_operations_unmount_mount_full (GtkWindow *parent_window, GMount *mount, GMountOperation *mount_operation, gboolean eject, gboolean check_trash, NemoUnmountCallback callback, gpointer callback_data) { UnmountData *data; int response; data = g_new0 (UnmountData, 1); data->callback = callback; data->callback_data = callback_data; if (parent_window) { data->parent_window = parent_window; g_object_add_weak_pointer (G_OBJECT (data->parent_window), (gpointer *) &data->parent_window); } if (mount_operation) { data->mount_operation = g_object_ref (mount_operation); } data->eject = eject; data->mount = g_object_ref (mount); if (check_trash && has_trash_files (mount)) { response = prompt_empty_trash (parent_window); if (response == GTK_RESPONSE_ACCEPT) { EmptyTrashJob *job; job = op_job_new (EmptyTrashJob, parent_window); job->should_confirm = FALSE; job->trash_dirs = get_trash_dirs_for_mount (mount); job->done_callback = empty_trash_for_unmount_done; job->done_callback_data = data; generate_initial_job_details (job->common.progress, OP_KIND_EMPTY_TRASH, NULL, NULL); add_job_to_job_queue (empty_trash_job, job, job->common.cancellable, job->common.progress, OP_KIND_EMPTY_TRASH); return; } else if (response == GTK_RESPONSE_CANCEL) { if (callback) { callback (callback_data); } unmount_data_free (data); return; } } do_unmount (data); } void nemo_file_operations_unmount_mount (GtkWindow *parent_window, GMount *mount, gboolean eject, gboolean check_trash) { nemo_file_operations_unmount_mount_full (parent_window, mount, NULL, eject, check_trash, NULL, NULL); } static void mount_callback_data_notify (gpointer data, GObject *object) { GMountOperation *mount_op; mount_op = G_MOUNT_OPERATION (data); g_object_set_data (G_OBJECT (mount_op), "mount-callback", NULL); g_object_set_data (G_OBJECT (mount_op), "mount-callback-data", NULL); } static void volume_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoMountCallback mount_callback; GObject *mount_callback_data_object; GMountOperation *mount_op = user_data; GError *error; char *primary; char *name; gboolean success; success = TRUE; error = NULL; if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) { if (error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED) { name = g_volume_get_name (G_VOLUME (source_object)); primary = g_strdup_printf (_("Unable to mount %s"), name); g_free (name); success = FALSE; eel_show_error_dialog (primary, error->message, NULL); g_free (primary); } g_error_free (error); } mount_callback = (NemoMountCallback) g_object_get_data (G_OBJECT (mount_op), "mount-callback"); mount_callback_data_object = g_object_get_data (G_OBJECT (mount_op), "mount-callback-data"); if (mount_callback != NULL) { (* mount_callback) (G_VOLUME (source_object), success, mount_callback_data_object); if (mount_callback_data_object != NULL) { g_object_weak_unref (mount_callback_data_object, mount_callback_data_notify, mount_op); } } g_object_unref (mount_op); } void nemo_file_operations_mount_volume (GtkWindow *parent_window, GVolume *volume) { nemo_file_operations_mount_volume_full (parent_window, volume, NULL, NULL); } void nemo_file_operations_mount_volume_full (GtkWindow *parent_window, GVolume *volume, NemoMountCallback mount_callback, GObject *mount_callback_data_object) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (parent_window); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); g_object_set_data (G_OBJECT (mount_op), "mount-callback", mount_callback); if (mount_callback != NULL && mount_callback_data_object != NULL) { g_object_weak_ref (mount_callback_data_object, mount_callback_data_notify, mount_op); } g_object_set_data (G_OBJECT (mount_op), "mount-callback-data", mount_callback_data_object); g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, mount_op); } static void report_count_progress (CommonJob *job, SourceInfo *source_info) { char *s; switch (source_info->op) { case OP_KIND_LINK: /* FIXME */ case OP_KIND_CREATE: case OP_KIND_PERMISSIONS: case OP_KIND_TRUST: default: case OP_KIND_DUPE: case OP_KIND_COPY: s = f (ngettext("Preparing to copy %'d file (%S)", "Preparing to copy %'d files (%S)", source_info->num_files), source_info->num_files, source_info->num_bytes); break; case OP_KIND_MOVE: s = f (ngettext("Preparing to move %'d file (%S)", "Preparing to move %'d files (%S)", source_info->num_files), source_info->num_files, source_info->num_bytes); break; case OP_KIND_DELETE: s = f (ngettext("Preparing to delete %'d file (%S)", "Preparing to delete %'d files (%S)", source_info->num_files), source_info->num_files, source_info->num_bytes); break; case OP_KIND_TRASH: case OP_KIND_EMPTY_TRASH: s = f (ngettext("Preparing to trash %'d file", "Preparing to trash %'d files", source_info->num_files), source_info->num_files); break; } nemo_progress_info_take_details (job->progress, s); nemo_progress_info_pulse_progress (job->progress); } static void count_file (GFileInfo *info, CommonJob *job, SourceInfo *source_info) { source_info->num_files += 1; source_info->num_bytes += g_file_info_get_size (info); if (source_info->num_files_since_progress++ > 100) { report_count_progress (job, source_info); source_info->num_files_since_progress = 0; } } static char * get_scan_primary (OpKind kind) { switch (kind) { case OP_KIND_PERMISSIONS: /* FIXME */ case OP_KIND_LINK: case OP_KIND_CREATE: case OP_KIND_TRUST: default: case OP_KIND_COPY: case OP_KIND_DUPE: return f (_("Error while copying.")); case OP_KIND_MOVE: return f (_("Error while moving.")); case OP_KIND_DELETE: return f (_("Error while deleting.")); case OP_KIND_TRASH: case OP_KIND_EMPTY_TRASH: return f (_("Error while moving files to trash.")); } } static void scan_dir (GFile *dir, SourceInfo *source_info, CommonJob *job, GQueue *dirs) { GFileInfo *info; GError *error; GFile *subdir; GFileEnumerator *enumerator; char *primary, *secondary, *details; int response; SourceInfo saved_info; saved_info = *source_info; retry: error = NULL; enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, &error); if (enumerator) { error = NULL; while ((info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) { count_file (info, job, source_info); if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { subdir = g_file_get_child (dir, g_file_info_get_name (info)); /* Push to head, since we want depth-first */ g_queue_push_head (dirs, subdir); } g_object_unref (info); } g_file_enumerator_close (enumerator, job->cancellable, NULL); g_object_unref (enumerator); if (error && IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else if (error) { primary = get_scan_primary (source_info->op); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("Files in the folder \"%B\" cannot be handled because you do " "not have permissions to see them."), dir); } else { secondary = f (_("There was an error getting information about the files in the folder \"%B\"."), dir); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, RETRY, SKIP, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { *source_info = saved_info; goto retry; } else if (response == 2) { skip_readdir_error (job, dir); } else { g_assert_not_reached (); } } } else if (job->skip_all_error) { g_error_free (error); skip_file (job, dir); } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { primary = get_scan_primary (source_info->op); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("The folder \"%B\" cannot be handled because you do not have " "permissions to read it."), dir); } else { secondary = f (_("There was an error reading the folder \"%B\"."), dir); details = error->message; } /* set show_all to TRUE here, as we don't know how many * files we'll end up processing yet. */ response = run_warning (job, primary, secondary, details, TRUE, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1 || response == 2) { if (response == 1) { job->skip_all_error = TRUE; } skip_file (job, dir); } else if (response == 3) { goto retry; } else { g_assert_not_reached (); } } } static void scan_file (GFile *file, SourceInfo *source_info, CommonJob *job) { GFileInfo *info; GError *error; GQueue *dirs; GFile *dir; char *primary; char *secondary; char *details; int response; dirs = g_queue_new (); retry: error = NULL; info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, &error); if (info) { count_file (info, job, source_info); /* trashing operation doesn't recurse */ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY && source_info->op != OP_KIND_TRASH) { g_queue_push_head (dirs, g_object_ref (file)); } g_object_unref (info); } else if (job->skip_all_error) { g_error_free (error); skip_file (job, file); } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { primary = get_scan_primary (source_info->op); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("The file \"%B\" cannot be handled because you do not have " "permissions to read it."), file); } else { secondary = f (_("There was an error getting information about \"%B\"."), file); details = error->message; } /* set show_all to TRUE here, as we don't know how many * files we'll end up processing yet. */ response = run_warning (job, primary, secondary, details, TRUE, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1 || response == 2) { if (response == 1) { job->skip_all_error = TRUE; } skip_file (job, file); } else if (response == 3) { goto retry; } else { g_assert_not_reached (); } } while (!job_aborted (job) && (dir = g_queue_pop_head (dirs)) != NULL) { scan_dir (dir, source_info, job, dirs); g_object_unref (dir); } /* Free all from queue if we exited early */ g_queue_foreach (dirs, (GFunc)g_object_unref, NULL); g_queue_free (dirs); } static void scan_sources (GList *files, SourceInfo *source_info, CommonJob *job, OpKind kind) { GList *l; GFile *file; memset (source_info, 0, sizeof (SourceInfo)); source_info->op = kind; report_count_progress (job, source_info); for (l = files; l != NULL && !job_aborted (job); l = l->next) { file = l->data; scan_file (file, source_info, job); } /* Make sure we report the final count */ report_count_progress (job, source_info); } static void verify_destination (CommonJob *job, GFile *dest, char **dest_fs_id, goffset required_size) { GFileInfo *info, *fsinfo; GError *error; guint64 free_size; guint64 size_difference; char *primary, *secondary, *details; int response; GFileType file_type; if (dest_fs_id) { *dest_fs_id = NULL; } retry: error = NULL; info = g_file_query_info (dest, G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_ID_FILESYSTEM, 0, job->cancellable, &error); if (info == NULL) { if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); return; } primary = f (_("Error while copying to \"%B\"."), dest); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("You do not have permissions to access the destination folder.")); } else { secondary = f (_("There was an error getting information about the destination.")); details = error->message; } response = run_error (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { goto retry; } else { g_assert_not_reached (); } return; } file_type = g_file_info_get_file_type (info); if (dest_fs_id) { *dest_fs_id = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); } g_object_unref (info); if (file_type != G_FILE_TYPE_DIRECTORY) { primary = f (_("Error while copying to \"%B\"."), dest); secondary = f (_("The destination is not a folder.")); response = run_error (job, primary, secondary, NULL, FALSE, GTK_STOCK_CANCEL, NULL); abort_job (job); return; } fsinfo = g_file_query_filesystem_info (dest, G_FILE_ATTRIBUTE_FILESYSTEM_FREE"," G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, job->cancellable, NULL); if (fsinfo == NULL) { /* All sorts of things can go wrong getting the fs info (like not supported) * only check these things if the fs returns them */ return; } if (required_size > 0 && g_file_info_has_attribute (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) { free_size = g_file_info_get_attribute_uint64 (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); if (free_size < abs(required_size)) { size_difference = required_size - free_size; primary = f (_("Error while copying to \"%B\"."), dest); secondary = f (_("There is not enough space on the destination. Try to remove files to make space.")); details = f (_("%S more space is required to copy to the destination."), size_difference); response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, COPY_FORCE, RETRY, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 2) { goto retry; } else if (response == 1) { /* We are forced to copy - just fall through ... */ } else { g_assert_not_reached (); } } } if (!job_aborted (job) && g_file_info_get_attribute_boolean (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY)) { primary = f (_("Error while copying to \"%B\"."), dest); secondary = f (_("The destination is read-only.")); response = run_error (job, primary, secondary, NULL, FALSE, GTK_STOCK_CANCEL, NULL); g_error_free (error); abort_job (job); } g_object_unref (fsinfo); } static void report_copy_progress (CopyMoveJob *copy_job, SourceInfo *source_info, TransferInfo *transfer_info) { int files_left; goffset total_size; double elapsed, transfer_rate; int remaining_time; guint64 now; CommonJob *job; gboolean is_move; job = (CommonJob *)copy_job; is_move = copy_job->is_move; now = g_get_monotonic_time (); if (transfer_info->last_report_time != 0 && ABS ((gint64)(transfer_info->last_report_time - now)) < PROGRESS_UPDATE_THRESHOLD * US_PER_MS) { return; } transfer_info->last_report_time = now; files_left = source_info->num_files - transfer_info->num_files; /* Races and whatnot could cause this to be negative... */ if (files_left < 0) { files_left = 1; } if (files_left != transfer_info->last_reported_files_left || transfer_info->last_reported_files_left == 0) { /* Avoid changing this unless files_left changed since last time */ transfer_info->last_reported_files_left = files_left; if (source_info->num_files == 1) { if (copy_job->destination != NULL) { nemo_progress_info_take_status (job->progress, f (is_move ? _("Moving \"%B\" to \"%B\""): _("Copying \"%B\" to \"%B\""), copy_job->fake_display_source != NULL ? copy_job->fake_display_source : (GFile *)copy_job->files->data, copy_job->destination)); } else { nemo_progress_info_take_status (job->progress, f (_("Duplicating \"%B\""), (GFile *)copy_job->files->data)); } } else if (copy_job->files != NULL && copy_job->files->next == NULL) { if (copy_job->destination != NULL) { nemo_progress_info_take_status (job->progress, f (is_move ? _("Moving file %'d of %'d (in \"%B\") to \"%B\"") : _("Copying file %'d of %'d (in \"%B\") to \"%B\""), transfer_info->num_files + 1, source_info->num_files, (GFile *)copy_job->files->data, copy_job->destination)); } else { nemo_progress_info_take_status (job->progress, f (_("Duplicating file %'d of %'d (in \"%B\")"), transfer_info->num_files + 1, source_info->num_files, (GFile *)copy_job->files->data)); } } else { if (copy_job->destination != NULL) { nemo_progress_info_take_status (job->progress, f (is_move ? _("Moving file %'d of %'d to \"%B\"") : _ ("Copying file %'d of %'d to \"%B\""), transfer_info->num_files + 1, source_info->num_files, copy_job->destination)); } else { nemo_progress_info_take_status (job->progress, f (_("Duplicating file %'d of %'d"), transfer_info->num_files + 1, source_info->num_files)); } } } total_size = MAX (source_info->num_bytes, transfer_info->num_bytes); elapsed = g_timer_elapsed (job->time, NULL); transfer_rate = 0; if (elapsed > 0) { transfer_rate = transfer_info->num_bytes / elapsed; } if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE && transfer_rate > 0) { char *s; /* To translators: %S will expand to a size like "2 bytes" or "3 MB", so something like "4 kb of 4 MB" */ s = f (_("%S of %S"), transfer_info->num_bytes, total_size); nemo_progress_info_take_details (job->progress, s); } else { char *s; remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate; /* To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration like * "2 minutes". So the whole thing will be something like "2 kb of 4 MB -- 2 hours left (4kb/sec)" * * The singular/plural form will be used depending on the remaining time (i.e. the %T argument). */ s = f (ngettext ("%S of %S \xE2\x80\x94 %T left (%S/sec)", "%S of %S \xE2\x80\x94 %T left (%S/sec)", seconds_count_format_time_units (remaining_time)), transfer_info->num_bytes, total_size, remaining_time, (goffset)transfer_rate); nemo_progress_info_take_details (job->progress, s); } nemo_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size); } static int get_max_name_length (GFile *file_dir) { int max_length; char *dir; long max_path; long max_name; max_length = -1; if (!g_file_has_uri_scheme (file_dir, "file")) return max_length; dir = g_file_get_path (file_dir); if (!dir) return max_length; max_path = pathconf (dir, _PC_PATH_MAX); max_name = pathconf (dir, _PC_NAME_MAX); if (max_name == -1 && max_path == -1) { max_length = -1; } else if (max_name == -1 && max_path != -1) { max_length = max_path - (strlen (dir) + 1); } else if (max_name != -1 && max_path == -1) { max_length = max_name; } else { int leftover; leftover = max_path - (strlen (dir) + 1); max_length = MIN (leftover, max_name); } g_free (dir); return max_length; } #define FAT_FORBIDDEN_CHARACTERS "/:;*?\"<>" static gboolean str_replace (char *str, const char *chars_to_replace, char replacement) { gboolean success; int i; success = FALSE; for (i = 0; str[i] != '\0'; i++) { if (strchr (chars_to_replace, str[i])) { success = TRUE; str[i] = replacement; } } return success; } static gboolean make_file_name_valid_for_dest_fs (char *filename, const char *dest_fs_type) { if (dest_fs_type != NULL && filename != NULL) { if (!strcmp (dest_fs_type, "fat") || !strcmp (dest_fs_type, "vfat") || !strcmp (dest_fs_type, "msdos") || !strcmp (dest_fs_type, "msdosfs")) { gboolean ret; guint i, old_len; ret = str_replace (filename, FAT_FORBIDDEN_CHARACTERS, '_'); old_len = strlen (filename); for (i = 0; i < old_len; i++) { if (filename[i] != ' ') { g_strchomp (filename); ret |= (old_len != strlen (filename)); break; } } return ret; } } return FALSE; } static GFile * get_unique_target_file (GFile *src, GFile *dest_dir, gboolean same_fs, const char *dest_fs_type, int count) { const char *editname, *end; char *basename, *new_name; GFileInfo *info; GFile *dest; int max_length; max_length = get_max_name_length (dest_dir); dest = NULL; info = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME, 0, NULL, NULL); if (info != NULL) { editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME); if (editname != NULL) { new_name = get_duplicate_name (editname, count, max_length); make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL); g_free (new_name); } g_object_unref (info); } if (dest == NULL) { basename = g_file_get_basename (src); if (g_utf8_validate (basename, -1, NULL)) { new_name = get_duplicate_name (basename, count, max_length); make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL); g_free (new_name); } if (dest == NULL) { end = strrchr (basename, '.'); if (end != NULL) { count += atoi (end + 1); } new_name = g_strdup_printf ("%s.%d", basename, count); make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child (dest_dir, new_name); g_free (new_name); } g_free (basename); } return dest; } static GFile * get_target_file_for_link (GFile *src, GFile *dest_dir, const char *dest_fs_type, int count) { const char *editname; char *basename, *new_name; GFileInfo *info; GFile *dest; int max_length; max_length = get_max_name_length (dest_dir); dest = NULL; info = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME, 0, NULL, NULL); if (info != NULL) { editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME); if (editname != NULL) { new_name = get_link_name (editname, count, max_length); make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL); g_free (new_name); } g_object_unref (info); } if (dest == NULL) { basename = g_file_get_basename (src); make_file_name_valid_for_dest_fs (basename, dest_fs_type); if (g_utf8_validate (basename, -1, NULL)) { new_name = get_link_name (basename, count, max_length); make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL); g_free (new_name); } if (dest == NULL) { if (count == 1) { new_name = g_strdup_printf ("%s.lnk", basename); } else { new_name = g_strdup_printf ("%s.lnk%d", basename, count); } make_file_name_valid_for_dest_fs (new_name, dest_fs_type); dest = g_file_get_child (dest_dir, new_name); g_free (new_name); } g_free (basename); } return dest; } static GFile * get_target_file_with_custom_name (GFile *src, GFile *dest_dir, const char *dest_fs_type, gboolean same_fs, const gchar *custom_name) { char *basename; GFile *dest; GFileInfo *info; char *copyname; dest = NULL; if (custom_name != NULL) { copyname = g_strdup (custom_name); make_file_name_valid_for_dest_fs (copyname, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL); g_free (copyname); } if (dest == NULL && !same_fs) { info = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME "," G_FILE_ATTRIBUTE_TRASH_ORIG_PATH, 0, NULL, NULL); if (info) { copyname = NULL; /* if file is being restored from trash make sure it uses its original name */ if (g_file_has_uri_scheme (src, "trash")) { copyname = g_path_get_basename (g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH)); } if (copyname == NULL) { copyname = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME)); } if (copyname) { make_file_name_valid_for_dest_fs (copyname, dest_fs_type); dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL); g_free (copyname); } g_object_unref (info); } } if (dest == NULL) { basename = g_file_get_basename (src); make_file_name_valid_for_dest_fs (basename, dest_fs_type); dest = g_file_get_child (dest_dir, basename); g_free (basename); } return dest; } static GFile * get_target_file (GFile *src, GFile *dest_dir, const char *dest_fs_type, gboolean same_fs) { return get_target_file_with_custom_name (src, dest_dir, dest_fs_type, same_fs, NULL); } static gboolean has_fs_id (GFile *file, const char *fs_id) { const char *id; GFileInfo *info; gboolean res; res = FALSE; info = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (info) { id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if (id && strcmp (id, fs_id) == 0) { res = TRUE; } g_object_unref (info); } return res; } static gboolean is_dir (GFile *file) { GFileInfo *info; gboolean res; res = FALSE; info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (info) { res = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY; g_object_unref (info); } return res; } static void copy_move_file (CopyMoveJob *job, GFile *src, GFile *dest_dir, gboolean same_fs, gboolean unique_names, char **dest_fs_type, SourceInfo *source_info, TransferInfo *transfer_info, GHashTable *debuting_files, GdkPoint *point, gboolean overwrite, gboolean *skipped_file, gboolean readonly_source_fs); typedef enum { CREATE_DEST_DIR_RETRY, CREATE_DEST_DIR_FAILED, CREATE_DEST_DIR_SUCCESS } CreateDestDirResult; static CreateDestDirResult create_dest_dir (CommonJob *job, GFile *src, GFile **dest, gboolean same_fs, char **dest_fs_type) { GError *error; GFile *new_dest, *dest_dir; char *primary, *secondary, *details; int response; gboolean handled_invalid_filename; handled_invalid_filename = *dest_fs_type != NULL; retry: /* First create the directory, then copy stuff to it before copying the attributes, because we need to be sure we can write to it */ error = NULL; if (!g_file_make_directory (*dest, job->cancellable, &error)) { if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); return CREATE_DEST_DIR_FAILED; } else if (IS_IO_ERROR (error, INVALID_FILENAME) && !handled_invalid_filename) { handled_invalid_filename = TRUE; g_assert (*dest_fs_type == NULL); dest_dir = g_file_get_parent (*dest); if (dest_dir != NULL) { *dest_fs_type = query_fs_type (dest_dir, job->cancellable); new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs); g_object_unref (dest_dir); if (!g_file_equal (*dest, new_dest)) { g_object_unref (*dest); *dest = new_dest; g_error_free (error); return CREATE_DEST_DIR_RETRY; } else { g_object_unref (new_dest); } } } primary = f (_("Error while copying.")); details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("The folder \"%B\" cannot be copied because you do not have " "permissions to create it in the destination."), src); } else { secondary = f (_("There was an error creating the folder \"%B\"."), src); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, SKIP, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* Skip: Do Nothing */ } else if (response == 2) { goto retry; } else { g_assert_not_reached (); } return CREATE_DEST_DIR_FAILED; } nemo_file_changes_queue_file_added (*dest); if (job->undo_info != NULL) { nemo_file_undo_info_ext_add_origin_target_pair (NEMO_FILE_UNDO_INFO_EXT (job->undo_info), src, *dest); } return CREATE_DEST_DIR_SUCCESS; } /* a return value of FALSE means retry, i.e. * the destination has changed and the source * is expected to re-try the preceeding * g_file_move() or g_file_copy() call with * the new destination. */ static gboolean copy_move_directory (CopyMoveJob *copy_job, GFile *src, GFile **dest, gboolean same_fs, gboolean create_dest, char **parent_dest_fs_type, SourceInfo *source_info, TransferInfo *transfer_info, GHashTable *debuting_files, gboolean *skipped_file, gboolean readonly_source_fs) { GFileInfo *info; GError *error; GFile *src_file; GFileEnumerator *enumerator; char *primary, *secondary, *details; char *dest_fs_type; int response; gboolean skip_error; gboolean local_skipped_file; CommonJob *job; GFileCopyFlags flags; job = (CommonJob *)copy_job; if (create_dest) { switch (create_dest_dir (job, src, dest, same_fs, parent_dest_fs_type)) { case CREATE_DEST_DIR_RETRY: /* next time copy_move_directory() is called, * create_dest will be FALSE if a directory already * exists under the new name (i.e. WOULD_RECURSE) */ return FALSE; case CREATE_DEST_DIR_FAILED: *skipped_file = TRUE; return TRUE; case CREATE_DEST_DIR_SUCCESS: default: break; } if (debuting_files) { g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (TRUE)); } } local_skipped_file = FALSE; dest_fs_type = NULL; skip_error = should_skip_readdir_error (job, src); retry: error = NULL; enumerator = g_file_enumerate_children (src, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, &error); if (enumerator) { error = NULL; while (!job_aborted (job) && (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) { src_file = g_file_get_child (src, g_file_info_get_name (info)); copy_move_file (copy_job, src_file, *dest, same_fs, FALSE, &dest_fs_type, source_info, transfer_info, NULL, NULL, FALSE, &local_skipped_file, readonly_source_fs); g_object_unref (src_file); g_object_unref (info); } g_file_enumerator_close (enumerator, job->cancellable, NULL); g_object_unref (enumerator); if (error && IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else if (error) { if (copy_job->is_move) { primary = f (_("Error while moving.")); } else { primary = f (_("Error while copying.")); } details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("Files in the folder \"%B\" cannot be copied because you do " "not have permissions to see them."), src); } else { secondary = f (_("There was an error getting information about the files in the folder \"%B\"."), src); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, _("_Skip files"), NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* Skip: Do Nothing */ local_skipped_file = TRUE; } else { g_assert_not_reached (); } } /* Count the copied directory as a file */ transfer_info->num_files ++; report_copy_progress (copy_job, source_info, transfer_info); if (debuting_files) { g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (create_dest)); } } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { if (copy_job->is_move) { primary = f (_("Error while moving.")); } else { primary = f (_("Error while copying.")); } details = NULL; if (IS_IO_ERROR (error, PERMISSION_DENIED)) { secondary = f (_("The folder \"%B\" cannot be copied because you do not have " "permissions to read it."), src); } else { secondary = f (_("There was an error reading the folder \"%B\"."), src); details = error->message; } response = run_warning (job, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, SKIP, RETRY, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* Skip: Do Nothing */ local_skipped_file = TRUE; } else if (response == 2) { goto retry; } else { g_assert_not_reached (); } } if (create_dest) { flags = (readonly_source_fs) ? G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_PERMS : G_FILE_COPY_NOFOLLOW_SYMLINKS; /* Ignore errors here. Failure to copy metadata is not a hard error */ g_file_copy_attributes (src, *dest, flags, job->cancellable, NULL); } if (!job_aborted (job) && copy_job->is_move && /* Don't delete source if there was a skipped file */ !local_skipped_file) { if (!file_delete_wrapper (src, job->cancellable, &error)) { if (job->skip_all_error) { goto skip; } primary = f (_("Error while moving \"%B\"."), src); secondary = f (_("Could not remove the source folder.")); details = error->message; response = run_warning (job, primary, secondary, details, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; local_skipped_file = TRUE; } else if (response == 2) { /* skip */ local_skipped_file = TRUE; } else { g_assert_not_reached (); } skip: g_error_free (error); } } if (local_skipped_file) { *skipped_file = TRUE; } g_free (dest_fs_type); return TRUE; } static gboolean remove_target_recursively (CommonJob *job, GFile *src, GFile *toplevel_dest, GFile *file) { GFileEnumerator *enumerator; GError *error; GFile *child; gboolean stop; char *primary, *secondary, *details; int response; GFileInfo *info; stop = FALSE; error = NULL; enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, &error); if (enumerator) { error = NULL; while (!job_aborted (job) && (info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) { child = g_file_get_child (file, g_file_info_get_name (info)); if (!remove_target_recursively (job, src, toplevel_dest, child)) { stop = TRUE; break; } g_object_unref (child); g_object_unref (info); } g_file_enumerator_close (enumerator, job->cancellable, NULL); g_object_unref (enumerator); } else if (IS_IO_ERROR (error, NOT_DIRECTORY)) { /* Not a dir, continue */ g_error_free (error); } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } else { if (job->skip_all_error) { goto skip1; } primary = f (_("Error while copying \"%B\"."), src); secondary = f (_("Could not remove files from the already existing folder %F."), file); details = error->message; /* set show_all to TRUE here, as we don't know how many * files we'll end up processing yet. */ response = run_warning (job, primary, secondary, details, TRUE, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } skip1: g_error_free (error); stop = TRUE; } if (stop) { return FALSE; } error = NULL; if (!file_delete_wrapper (file, job->cancellable, &error)) { if (job->skip_all_error || IS_IO_ERROR (error, CANCELLED)) { goto skip2; } primary = f (_("Error while copying \"%B\"."), src); secondary = f (_("Could not remove the already existing file %F."), file); details = error->message; /* set show_all to TRUE here, as we don't know how many * files we'll end up processing yet. */ response = run_warning (job, primary, secondary, details, TRUE, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } skip2: g_error_free (error); return FALSE; } nemo_file_changes_queue_file_removed (file); return TRUE; } typedef struct { CopyMoveJob *job; goffset last_size; SourceInfo *source_info; TransferInfo *transfer_info; } ProgressData; static void copy_file_progress_callback (goffset current_num_bytes, goffset total_num_bytes, gpointer user_data) { ProgressData *pdata; goffset new_size; pdata = user_data; new_size = current_num_bytes - pdata->last_size; if (new_size > 0) { pdata->transfer_info->num_bytes += new_size; pdata->last_size = current_num_bytes; report_copy_progress (pdata->job, pdata->source_info, pdata->transfer_info); } } static gboolean test_dir_is_parent (GFile *child, GFile *root) { GFile *f, *tmp; f = g_file_dup (child); while (f) { if (g_file_equal (f, root)) { g_object_unref (f); return TRUE; } tmp = f; f = g_file_get_parent (f); g_object_unref (tmp); } if (f) { g_object_unref (f); } return FALSE; } static char * query_fs_type (GFile *file, GCancellable *cancellable) { GFileInfo *fsinfo; char *ret; ret = NULL; fsinfo = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, cancellable, NULL); if (fsinfo != NULL) { ret = g_strdup (g_file_info_get_attribute_string (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE)); g_object_unref (fsinfo); } if (ret == NULL) { /* ensure that we don't attempt to query * the FS type for each file in a given * directory, if it can't be queried. */ ret = g_strdup (""); } return ret; } static gboolean is_trusted_desktop_file (GFile *file, GCancellable *cancellable) { char *basename; gboolean res; GFileInfo *info; /* Don't trust non-local files */ if (!g_file_is_native (file)) { return FALSE; } basename = g_file_get_basename (file); if (!g_str_has_suffix (basename, ".desktop")) { g_free (basename); return FALSE; } g_free (basename); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, NULL); if (info == NULL) { return FALSE; } res = FALSE; /* Weird file => not trusted, Already executable => no need to mark trusted */ if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR && !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE) && nemo_is_in_system_dir (file)) { res = TRUE; } g_object_unref (info); return res; } typedef struct { int id; char *new_name; gboolean apply_to_all; } ConflictResponseData; typedef struct { GFile *src; GFile *dest; GFile *dest_dir; GtkWindow *parent; ConflictResponseData *resp_data; } ConflictDialogData; static gboolean do_run_conflict_dialog (gpointer _data) { ConflictDialogData *data = _data; GtkWidget *dialog; int response; dialog = nemo_file_conflict_dialog_new (data->parent, data->src, data->dest, data->dest_dir); response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == CONFLICT_RESPONSE_RENAME) { data->resp_data->new_name = nemo_file_conflict_dialog_get_new_name (NEMO_FILE_CONFLICT_DIALOG (dialog)); } else if (response != GTK_RESPONSE_CANCEL || response != GTK_RESPONSE_NONE) { data->resp_data->apply_to_all = nemo_file_conflict_dialog_get_apply_to_all (NEMO_FILE_CONFLICT_DIALOG (dialog)); } data->resp_data->id = response; gtk_widget_destroy (dialog); return FALSE; } static ConflictResponseData * run_conflict_dialog (CommonJob *job, GFile *src, GFile *dest, GFile *dest_dir) { ConflictDialogData *data; ConflictResponseData *resp_data; g_timer_stop (job->time); data = g_slice_new0 (ConflictDialogData); data->parent = job->parent_window; data->src = src; data->dest = dest; data->dest_dir = dest_dir; resp_data = g_slice_new0 (ConflictResponseData); resp_data->new_name = NULL; data->resp_data = resp_data; nemo_progress_info_pause (job->progress); g_io_scheduler_job_send_to_mainloop (job->io_job, do_run_conflict_dialog, data, NULL); nemo_progress_info_resume (job->progress); g_slice_free (ConflictDialogData, data); g_timer_continue (job->time); return resp_data; } static void conflict_response_data_free (ConflictResponseData *data) { g_free (data->new_name); g_slice_free (ConflictResponseData, data); } static GFile * get_target_file_for_display_name (GFile *dir, const gchar *name) { GFile *dest; dest = NULL; dest = g_file_get_child_for_display_name (dir, name, NULL); if (dest == NULL) { dest = g_file_get_child (dir, name); } return dest; } /* Debuting files is non-NULL only for toplevel items */ static void copy_move_file (CopyMoveJob *copy_job, GFile *src, GFile *dest_dir, gboolean same_fs, gboolean unique_names, char **dest_fs_type, SourceInfo *source_info, TransferInfo *transfer_info, GHashTable *debuting_files, GdkPoint *position, gboolean overwrite, gboolean *skipped_file, gboolean readonly_source_fs) { GFile *dest, *new_dest; GError *error; GFileCopyFlags flags; char *primary, *secondary, *details; int response; ProgressData pdata; gboolean would_recurse, is_merge; CommonJob *job; gboolean res; int unique_name_nr; gboolean handled_invalid_filename; gboolean target_is_desktop, source_is_desktop; job = (CommonJob *)copy_job; if (should_skip_file (job, src)) { *skipped_file = TRUE; return; } target_is_desktop = (copy_job->desktop_location != NULL && g_file_equal (copy_job->desktop_location, dest_dir)); source_is_desktop = FALSE; if (src != NULL) { GFile *parent = g_file_get_parent (src); if (parent != NULL && g_file_equal (copy_job->desktop_location, parent)) { source_is_desktop = TRUE; g_object_unref (parent); } } unique_name_nr = 1; /* another file in the same directory might have handled the invalid * filename condition for us */ handled_invalid_filename = *dest_fs_type != NULL; if (unique_names) { dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++); } else if (copy_job->target_name != NULL) { dest = get_target_file_with_custom_name (src, dest_dir, *dest_fs_type, same_fs, copy_job->target_name); } else { dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs); } /* Don't allow recursive move/copy into itself. * (We would get a file system error if we proceeded but it is nicer to * detect and report it at this level) */ if (test_dir_is_parent (dest_dir, src)) { if (job->skip_all_error) { goto out; } /* the run_warning() frees all strings passed in automatically */ primary = copy_job->is_move ? g_strdup (_("You cannot move a folder into itself.")) : g_strdup (_("You cannot copy a folder into itself.")); secondary = g_strdup (_("The destination folder is inside the source folder.")); response = run_warning (job, primary, secondary, NULL, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } goto out; } /* Don't allow copying over the source or one of the parents of the source. */ if (test_dir_is_parent (src, dest)) { if (job->skip_all_error) { goto out; } /* the run_warning() frees all strings passed in automatically */ primary = copy_job->is_move ? g_strdup (_("You cannot move a file over itself.")) : g_strdup (_("You cannot copy a file over itself.")); secondary = g_strdup (_("The source file would be overwritten by the destination.")); response = run_warning (job, primary, secondary, NULL, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } goto out; } retry: error = NULL; flags = G_FILE_COPY_NOFOLLOW_SYMLINKS; if (overwrite) { flags |= G_FILE_COPY_OVERWRITE; } if (readonly_source_fs) { flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS; } pdata.job = copy_job; pdata.last_size = 0; pdata.source_info = source_info; pdata.transfer_info = transfer_info; if (copy_job->is_move) { res = g_file_move (src, dest, flags, job->cancellable, copy_file_progress_callback, &pdata, &error); } else { res = g_file_copy (src, dest, flags, job->cancellable, copy_file_progress_callback, &pdata, &error); } if (res) { transfer_info->num_files ++; report_copy_progress (copy_job, source_info, transfer_info); if (debuting_files) { if (target_is_desktop && position) { nemo_file_changes_queue_schedule_position_set (dest, *position, job->monitor_num); } else if (source_is_desktop && copy_job->is_move) { nemo_file_changes_queue_schedule_position_remove (dest); } g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE)); } if (copy_job->is_move) { nemo_file_changes_queue_file_moved (src, dest); } else { nemo_file_changes_queue_file_added (dest); } /* If copying a trusted desktop file to the desktop, mark it as trusted. */ if (copy_job->desktop_location != NULL && g_file_equal (copy_job->desktop_location, dest_dir) && is_trusted_desktop_file (src, job->cancellable)) { mark_desktop_file_trusted (job, job->cancellable, dest, FALSE); } if (job->undo_info != NULL) { nemo_file_undo_info_ext_add_origin_target_pair (NEMO_FILE_UNDO_INFO_EXT (job->undo_info), src, dest); } g_object_unref (dest); return; } if (!handled_invalid_filename && IS_IO_ERROR (error, INVALID_FILENAME)) { handled_invalid_filename = TRUE; g_assert (*dest_fs_type == NULL); *dest_fs_type = query_fs_type (dest_dir, job->cancellable); if (unique_names) { new_dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr); } else { new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs); } if (!g_file_equal (dest, new_dest)) { g_object_unref (dest); dest = new_dest; g_error_free (error); goto retry; } else { g_object_unref (new_dest); } } /* Conflict */ if (!overwrite && IS_IO_ERROR (error, EXISTS)) { gboolean is_a_merge; ConflictResponseData *resp; g_error_free (error); if (unique_names) { g_object_unref (dest); dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++); goto retry; } is_a_merge = FALSE; if (is_dir (dest) && is_dir (src)) { is_a_merge = TRUE; } if ((is_a_merge && job->merge_all) || (!is_a_merge && job->replace_all)) { overwrite = TRUE; goto retry; } if (job->skip_all_conflict) { goto out; } resp = run_conflict_dialog (job, src, dest, dest_dir); if (resp->id == GTK_RESPONSE_CANCEL || resp->id == GTK_RESPONSE_DELETE_EVENT) { conflict_response_data_free (resp); abort_job (job); } else if (resp->id == CONFLICT_RESPONSE_SKIP) { if (resp->apply_to_all) { job->skip_all_conflict = TRUE; } conflict_response_data_free (resp); } else if (resp->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */ if (resp->apply_to_all) { if (is_a_merge) { job->merge_all = TRUE; } else { job->replace_all = TRUE; } } overwrite = TRUE; conflict_response_data_free (resp); goto retry; } else if (resp->id == CONFLICT_RESPONSE_RENAME) { g_object_unref (dest); dest = get_target_file_for_display_name (dest_dir, resp->new_name); conflict_response_data_free (resp); goto retry; } else { g_assert_not_reached (); } } else if (overwrite && IS_IO_ERROR (error, IS_DIRECTORY)) { g_error_free (error); if (remove_target_recursively (job, src, dest, dest)) { goto retry; } } /* Needs to recurse */ else if (IS_IO_ERROR (error, WOULD_RECURSE) || IS_IO_ERROR (error, WOULD_MERGE)) { is_merge = error->code == G_IO_ERROR_WOULD_MERGE; would_recurse = error->code == G_IO_ERROR_WOULD_RECURSE; g_error_free (error); if (overwrite && would_recurse) { error = NULL; /* Copying a dir onto file, first remove the file */ if (!file_delete_wrapper (dest, job->cancellable, &error) && !IS_IO_ERROR (error, NOT_FOUND)) { if (job->skip_all_error) { g_error_free (error); goto out; } if (copy_job->is_move) { primary = f (_("Error while moving \"%B\"."), src); } else { primary = f (_("Error while copying \"%B\"."), src); } secondary = f (_("Could not remove the already existing file with the same name in %F."), dest_dir); details = error->message; /* setting TRUE on show_all here, as we could have * another error on the same file later. */ response = run_warning (job, primary, secondary, details, TRUE, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } goto out; } if (error) { g_error_free (error); error = NULL; } nemo_file_changes_queue_file_removed (dest); } if (is_merge) { /* On merge we now write in the target directory, which may not be in the same directory as the source, even if the parent is (if the merged directory is a mountpoint). This could cause problems as we then don't transcode filenames. We just set same_fs to FALSE which is safe but a bit slower. */ same_fs = FALSE; } if (!copy_move_directory (copy_job, src, &dest, same_fs, would_recurse, dest_fs_type, source_info, transfer_info, debuting_files, skipped_file, readonly_source_fs)) { /* destination changed, since it was an invalid file name */ g_assert (*dest_fs_type != NULL); handled_invalid_filename = TRUE; goto retry; } g_object_unref (dest); return; } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } /* Other error */ else { if (job->skip_all_error) { g_error_free (error); goto out; } primary = f (_("Error while copying \"%B\"."), src); secondary = f (_("There was an error copying the file into %F."), dest_dir); details = error->message; response = run_warning (job, primary, secondary, details, (source_info->num_files - transfer_info->num_files) > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } } out: *skipped_file = TRUE; /* Or aborted, but same-same */ g_object_unref (dest); } static void copy_files (CopyMoveJob *job, const char *dest_fs_id, SourceInfo *source_info, TransferInfo *transfer_info) { CommonJob *common; GList *l; GFile *src; gboolean same_fs; int i; GdkPoint *point; gboolean skipped_file; gboolean unique_names; GFile *dest; GFile *source_dir; char *dest_fs_type; GFileInfo *inf; gboolean readonly_source_fs; dest_fs_type = NULL; readonly_source_fs = FALSE; common = &job->common; report_copy_progress (job, source_info, transfer_info); /* Query the source dir, not the file because if its a symlink we'll follow it */ source_dir = g_file_get_parent ((GFile *) job->files->data); if (source_dir) { inf = g_file_query_filesystem_info (source_dir, "filesystem::readonly", NULL, NULL); if (inf != NULL) { readonly_source_fs = g_file_info_get_attribute_boolean (inf, "filesystem::readonly"); g_object_unref (inf); } g_object_unref (source_dir); } unique_names = (job->destination == NULL); i = 0; for (l = job->files; l != NULL && !job_aborted (common); l = l->next) { src = l->data; if (i < job->n_icon_positions) { point = &job->icon_positions[i]; } else { point = NULL; } same_fs = FALSE; if (dest_fs_id) { same_fs = has_fs_id (src, dest_fs_id); } if (job->destination) { dest = g_object_ref (job->destination); } else { dest = g_file_get_parent (src); } if (dest) { skipped_file = FALSE; copy_move_file (job, src, dest, same_fs, unique_names, &dest_fs_type, source_info, transfer_info, job->debuting_files, point, FALSE, &skipped_file, readonly_source_fs); g_object_unref (dest); } i++; } g_free (dest_fs_type); } static gboolean copy_job_done (gpointer user_data) { CopyMoveJob *job; job = user_data; if (job->done_callback) { job->done_callback (job->debuting_files, !job_aborted ((CommonJob *) job), job->done_callback_data); } g_list_free_full (job->files, g_object_unref); if (job->destination) { g_object_unref (job->destination); } if (job->desktop_location) { g_object_unref (job->desktop_location); } g_hash_table_unref (job->debuting_files); g_free (job->icon_positions); g_free (job->target_name); g_clear_object (&job->fake_display_source); finalize_common ((CommonJob *)job); nemo_file_changes_consume_changes (TRUE); return FALSE; } static gboolean copy_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { CopyMoveJob *job; CommonJob *common; SourceInfo source_info; TransferInfo transfer_info; char *dest_fs_id; GFile *dest; job = user_data; common = &job->common; common->io_job = io_job; dest_fs_id = NULL; nemo_progress_info_start (common->progress); scan_sources (job->files, &source_info, common, OP_KIND_COPY); if (job_aborted (common)) { goto aborted; } if (job->destination) { dest = g_object_ref (job->destination); } else { /* Duplication, no dest, * use source for free size, etc */ dest = g_file_get_parent (job->files->data); } verify_destination (&job->common, dest, &dest_fs_id, source_info.num_bytes); g_object_unref (dest); if (job_aborted (common)) { goto aborted; } g_timer_start (job->common.time); memset (&transfer_info, 0, sizeof (transfer_info)); copy_files (job, dest_fs_id, &source_info, &transfer_info); aborted: g_free (dest_fs_id); g_io_scheduler_job_send_to_mainloop_async (io_job, copy_job_done, job, NULL); return FALSE; } void nemo_file_operations_copy_file (GFile *source_file, GFile *target_dir, const gchar *source_display_name, const gchar *new_name, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data) { CopyMoveJob *job; job = op_job_new (CopyMoveJob, parent_window); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->files = g_list_append (NULL, g_object_ref (source_file)); job->destination = g_object_ref (target_dir); job->target_name = g_strdup (new_name); job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); if (source_display_name != NULL) { gchar *path; path = g_build_filename ("/", source_display_name, NULL); job->fake_display_source = g_file_new_for_path (path); g_free (path); } inhibit_power_manager ((CommonJob *)job, _("Copying Files")); generate_initial_job_details (job->common.progress, OP_KIND_COPY, job->files, job->destination); add_job_to_job_queue (copy_job, job, job->common.cancellable, job->common.progress, OP_KIND_COPY); } void nemo_file_operations_copy (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data) { CopyMoveJob *job; job = op_job_new (CopyMoveJob, parent_window); job->desktop_location = nemo_get_desktop_location (); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->files = eel_g_object_list_copy (files); job->destination = g_object_ref (target_dir); if (relative_item_points != NULL && relative_item_points->len > 0) { job->icon_positions = g_memdup (relative_item_points->data, sizeof (GdkPoint) * relative_item_points->len); job->n_icon_positions = relative_item_points->len; } job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); inhibit_power_manager ((CommonJob *)job, _("Copying Files")); if (!nemo_file_undo_manager_pop_flag ()) { GFile* src_dir; src_dir = g_file_get_parent (files->data); job->common.undo_info = nemo_file_undo_info_ext_new (NEMO_FILE_UNDO_OP_COPY, g_list_length (files), src_dir, target_dir); g_object_unref (src_dir); } generate_initial_job_details (job->common.progress, OP_KIND_COPY, job->files, job->destination); add_job_to_job_queue (copy_job, job, job->common.cancellable, job->common.progress, OP_KIND_COPY); } static void report_move_progress (CopyMoveJob *move_job, int total, int left) { CommonJob *job; job = (CommonJob *)move_job; nemo_progress_info_take_status (job->progress, f (_("Preparing to Move to \"%B\""), move_job->destination)); nemo_progress_info_take_details (job->progress, f (ngettext ("Preparing to move %'d file", "Preparing to move %'d files", left), left)); nemo_progress_info_pulse_progress (job->progress); } typedef struct { GFile *file; gboolean overwrite; gboolean has_position; GdkPoint position; } MoveFileCopyFallback; static MoveFileCopyFallback * move_copy_file_callback_new (GFile *file, gboolean overwrite, GdkPoint *position) { MoveFileCopyFallback *fallback; fallback = g_new (MoveFileCopyFallback, 1); fallback->file = file; fallback->overwrite = overwrite; if (position) { fallback->has_position = TRUE; fallback->position = *position; } else { fallback->has_position = FALSE; } return fallback; } static GList * get_files_from_fallbacks (GList *fallbacks) { MoveFileCopyFallback *fallback; GList *res, *l; res = NULL; for (l = fallbacks; l != NULL; l = l->next) { fallback = l->data; res = g_list_prepend (res, fallback->file); } return g_list_reverse (res); } static void move_file_prepare (CopyMoveJob *move_job, GFile *src, GFile *dest_dir, gboolean same_fs, char **dest_fs_type, GHashTable *debuting_files, GdkPoint *position, GList **fallback_files, int files_left) { GFile *dest, *new_dest; GError *error; CommonJob *job; gboolean overwrite; char *primary, *secondary, *details; int response; GFileCopyFlags flags; MoveFileCopyFallback *fallback; gboolean handled_invalid_filename; gboolean target_is_desktop, source_is_desktop; target_is_desktop = (move_job->desktop_location != NULL && g_file_equal (move_job->desktop_location, dest_dir)); source_is_desktop = FALSE; if (src != NULL) { GFile *parent = g_file_get_parent (src); if (parent != NULL && g_file_equal (move_job->desktop_location, parent)) { source_is_desktop = TRUE; g_object_unref (parent); } } overwrite = FALSE; handled_invalid_filename = *dest_fs_type != NULL; job = (CommonJob *)move_job; dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs); /* Don't allow recursive move/copy into itself. * (We would get a file system error if we proceeded but it is nicer to * detect and report it at this level) */ if (test_dir_is_parent (dest_dir, src)) { if (job->skip_all_error) { goto out; } /* the run_warning() frees all strings passed in automatically */ primary = move_job->is_move ? g_strdup (_("You cannot move a folder into itself.")) : g_strdup (_("You cannot copy a folder into itself.")); secondary = g_strdup (_("The destination folder is inside the source folder.")); response = run_warning (job, primary, secondary, NULL, files_left > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } goto out; } retry: flags = G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_NO_FALLBACK_FOR_MOVE; if (overwrite) { flags |= G_FILE_COPY_OVERWRITE; } error = NULL; if (g_file_move (src, dest, flags, job->cancellable, NULL, NULL, &error)) { if (debuting_files) { g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE)); } nemo_file_changes_queue_file_moved (src, dest); if (target_is_desktop && position) { nemo_file_changes_queue_schedule_position_set (dest, *position, job->monitor_num); } else if (source_is_desktop) { nemo_file_changes_queue_schedule_position_remove (dest); } if (job->undo_info != NULL) { nemo_file_undo_info_ext_add_origin_target_pair (NEMO_FILE_UNDO_INFO_EXT (job->undo_info), src, dest); } return; } if (IS_IO_ERROR (error, INVALID_FILENAME) && !handled_invalid_filename) { g_error_free (error); handled_invalid_filename = TRUE; g_assert (*dest_fs_type == NULL); *dest_fs_type = query_fs_type (dest_dir, job->cancellable); new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs); if (!g_file_equal (dest, new_dest)) { g_object_unref (dest); dest = new_dest; goto retry; } else { g_object_unref (new_dest); } } /* Conflict */ else if (!overwrite && IS_IO_ERROR (error, EXISTS)) { gboolean is_merge; ConflictResponseData *resp; g_error_free (error); is_merge = FALSE; if (is_dir (dest) && is_dir (src)) { is_merge = TRUE; } if ((is_merge && job->merge_all) || (!is_merge && job->replace_all)) { overwrite = TRUE; goto retry; } if (job->skip_all_conflict) { goto out; } resp = run_conflict_dialog (job, src, dest, dest_dir); if (resp->id == GTK_RESPONSE_CANCEL || resp->id == GTK_RESPONSE_DELETE_EVENT) { conflict_response_data_free (resp); abort_job (job); } else if (resp->id == CONFLICT_RESPONSE_SKIP) { if (resp->apply_to_all) { job->skip_all_conflict = TRUE; } conflict_response_data_free (resp); } else if (resp->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */ if (resp->apply_to_all) { if (is_merge) { job->merge_all = TRUE; } else { job->replace_all = TRUE; } } overwrite = TRUE; conflict_response_data_free (resp); goto retry; } else if (resp->id == CONFLICT_RESPONSE_RENAME) { g_object_unref (dest); dest = get_target_file_for_display_name (dest_dir, resp->new_name); conflict_response_data_free (resp); goto retry; } else { g_assert_not_reached (); } } else if (IS_IO_ERROR (error, WOULD_RECURSE) || IS_IO_ERROR (error, WOULD_MERGE) || IS_IO_ERROR (error, NOT_SUPPORTED) || (overwrite && IS_IO_ERROR (error, IS_DIRECTORY))) { g_error_free (error); fallback = move_copy_file_callback_new (src, overwrite, position); *fallback_files = g_list_prepend (*fallback_files, fallback); } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } /* Other error */ else { if (job->skip_all_error) { goto out; } primary = f (_("Error while moving \"%B\"."), src); secondary = f (_("There was an error moving the file into %F."), dest_dir); details = error->message; response = run_warning (job, primary, secondary, details, files_left > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (job); } else if (response == 1) { /* skip all */ job->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } } out: g_object_unref (dest); } static void move_files_prepare (CopyMoveJob *job, const char *dest_fs_id, char **dest_fs_type, GList **fallbacks) { CommonJob *common; GList *l; GFile *src; gboolean same_fs; int i; GdkPoint *point; int total, left; common = &job->common; total = left = g_list_length (job->files); report_move_progress (job, total, left); i = 0; for (l = job->files; l != NULL && !job_aborted (common); l = l->next) { src = l->data; if (i < job->n_icon_positions) { point = &job->icon_positions[i]; } else { point = NULL; } same_fs = FALSE; if (dest_fs_id) { same_fs = has_fs_id (src, dest_fs_id); } move_file_prepare (job, src, job->destination, same_fs, dest_fs_type, job->debuting_files, point, fallbacks, left); report_move_progress (job, total, --left); i++; } *fallbacks = g_list_reverse (*fallbacks); } static void move_files (CopyMoveJob *job, GList *fallbacks, const char *dest_fs_id, char **dest_fs_type, SourceInfo *source_info, TransferInfo *transfer_info) { CommonJob *common; GList *l; GFile *src; gboolean same_fs; int i; GdkPoint *point; gboolean skipped_file; MoveFileCopyFallback *fallback; common = &job->common; report_copy_progress (job, source_info, transfer_info); i = 0; for (l = fallbacks; l != NULL && !job_aborted (common); l = l->next) { fallback = l->data; src = fallback->file; if (fallback->has_position) { point = &fallback->position; } else { point = NULL; } same_fs = FALSE; if (dest_fs_id) { same_fs = has_fs_id (src, dest_fs_id); } /* Set overwrite to true, as the user has selected overwrite on all toplevel items */ skipped_file = FALSE; copy_move_file (job, src, job->destination, same_fs, FALSE, dest_fs_type, source_info, transfer_info, job->debuting_files, point, fallback->overwrite, &skipped_file, FALSE); i++; } } static gboolean move_job_done (gpointer user_data) { CopyMoveJob *job; job = user_data; if (job->done_callback) { job->done_callback (job->debuting_files, !job_aborted ((CommonJob *) job), job->done_callback_data); } g_list_free_full (job->files, g_object_unref); g_object_unref (job->destination); g_hash_table_unref (job->debuting_files); g_free (job->icon_positions); finalize_common ((CommonJob *)job); nemo_file_changes_consume_changes (TRUE); return FALSE; } static gboolean move_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { CopyMoveJob *job; CommonJob *common; GList *fallbacks; SourceInfo source_info; TransferInfo transfer_info; char *dest_fs_id; char *dest_fs_type; GList *fallback_files; job = user_data; common = &job->common; common->io_job = io_job; dest_fs_id = NULL; dest_fs_type = NULL; fallbacks = NULL; nemo_progress_info_start (common->progress); verify_destination (&job->common, job->destination, &dest_fs_id, -1); if (job_aborted (common)) { goto aborted; } /* This moves all files that we can do without copy + delete */ move_files_prepare (job, dest_fs_id, &dest_fs_type, &fallbacks); if (job_aborted (common)) { goto aborted; } /* The rest we need to do deep copy + delete behind on, so scan for size */ fallback_files = get_files_from_fallbacks (fallbacks); scan_sources (fallback_files, &source_info, common, OP_KIND_MOVE); g_list_free (fallback_files); if (job_aborted (common)) { goto aborted; } verify_destination (&job->common, job->destination, NULL, source_info.num_bytes); if (job_aborted (common)) { goto aborted; } memset (&transfer_info, 0, sizeof (transfer_info)); move_files (job, fallbacks, dest_fs_id, &dest_fs_type, &source_info, &transfer_info); aborted: g_list_free_full (fallbacks, g_free); g_free (dest_fs_id); g_free (dest_fs_type); g_io_scheduler_job_send_to_mainloop (io_job, move_job_done, job, NULL); return FALSE; } void nemo_file_operations_move (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data) { CopyMoveJob *job; job = op_job_new (CopyMoveJob, parent_window); job->is_move = TRUE; job->desktop_location = nemo_get_desktop_location (); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->files = eel_g_object_list_copy (files); job->destination = g_object_ref (target_dir); if (relative_item_points != NULL && relative_item_points->len > 0) { job->icon_positions = g_memdup (relative_item_points->data, sizeof (GdkPoint) * relative_item_points->len); job->n_icon_positions = relative_item_points->len; } job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); inhibit_power_manager ((CommonJob *)job, _("Moving Files")); if (!nemo_file_undo_manager_pop_flag ()) { GFile* src_dir; src_dir = g_file_get_parent (files->data); if (g_file_has_uri_scheme (g_list_first (files)->data, "trash")) { job->common.undo_info = nemo_file_undo_info_ext_new (NEMO_FILE_UNDO_OP_RESTORE_FROM_TRASH, g_list_length (files), src_dir, target_dir); } else { job->common.undo_info = nemo_file_undo_info_ext_new (NEMO_FILE_UNDO_OP_MOVE, g_list_length (files), src_dir, target_dir); } g_object_unref (src_dir); } generate_initial_job_details (job->common.progress, OP_KIND_MOVE, job->files, job->destination); add_job_to_job_queue (move_job, job, job->common.cancellable, job->common.progress, OP_KIND_MOVE); } static void report_link_progress (CopyMoveJob *link_job, int total, int left) { CommonJob *job; job = (CommonJob *)link_job; nemo_progress_info_take_status (job->progress, f (_("Creating links in \"%B\""), link_job->destination)); nemo_progress_info_take_details (job->progress, f (ngettext ("Making link to %'d file", "Making links to %'d files", left), left)); nemo_progress_info_set_progress (job->progress, left, total); } static char * get_abs_path_for_symlink (GFile *file) { GFile *root, *parent; char *relative, *abs; if (g_file_is_native (file)) { return g_file_get_path (file); } root = g_object_ref (file); while ((parent = g_file_get_parent (root)) != NULL) { g_object_unref (root); root = parent; } relative = g_file_get_relative_path (root, file); g_object_unref (root); abs = g_strconcat ("/", relative, NULL); g_free (relative); return abs; } static void link_file (CopyMoveJob *job, GFile *src, GFile *dest_dir, char **dest_fs_type, GHashTable *debuting_files, GdkPoint *position, int files_left) { GFile *src_dir, *dest, *new_dest; int count; char *path; gboolean not_local; GError *error; CommonJob *common; char *primary, *secondary, *details; int response; gboolean handled_invalid_filename; gboolean target_is_desktop; target_is_desktop = (job->desktop_location != NULL && g_file_equal (job->desktop_location, dest_dir)); common = (CommonJob *)job; count = 0; src_dir = g_file_get_parent (src); if (g_file_equal (src_dir, dest_dir)) { count = 1; } g_object_unref (src_dir); handled_invalid_filename = *dest_fs_type != NULL; dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count); retry: error = NULL; not_local = FALSE; path = get_abs_path_for_symlink (src); if (path == NULL) { not_local = TRUE; } else if (g_file_make_symbolic_link (dest, path, common->cancellable, &error)) { if (common->undo_info != NULL) { nemo_file_undo_info_ext_add_origin_target_pair (NEMO_FILE_UNDO_INFO_EXT (common->undo_info), src, dest); } g_free (path); if (debuting_files) { g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE)); } nemo_file_changes_queue_file_added (dest); if (target_is_desktop && position) { nemo_file_changes_queue_schedule_position_set (dest, *position, common->monitor_num); } g_object_unref (dest); return; } g_free (path); if (error != NULL && IS_IO_ERROR (error, INVALID_FILENAME) && !handled_invalid_filename) { handled_invalid_filename = TRUE; g_assert (*dest_fs_type == NULL); *dest_fs_type = query_fs_type (dest_dir, common->cancellable); new_dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count); if (!g_file_equal (dest, new_dest)) { g_object_unref (dest); dest = new_dest; g_error_free (error); goto retry; } else { g_object_unref (new_dest); } } /* Conflict */ if (error != NULL && IS_IO_ERROR (error, EXISTS)) { g_object_unref (dest); dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count++); g_error_free (error); goto retry; } else if (error != NULL && IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } /* Other error */ else { if (common->skip_all_error) { goto out; } primary = f (_("Error while creating link to %B."), src); if (not_local) { secondary = f (_("Symbolic links only supported for local files")); details = NULL; } else if (error != NULL && IS_IO_ERROR (error, NOT_SUPPORTED)) { secondary = f (_("The target doesn't support symbolic links.")); details = NULL; } else { secondary = f (_("There was an error creating the symlink in %F."), dest_dir); details = error->message; } response = run_warning (common, primary, secondary, details, files_left > 1, GTK_STOCK_CANCEL, SKIP_ALL, SKIP, NULL); if (error) { g_error_free (error); } if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { /* skip all */ common->skip_all_error = TRUE; } else if (response == 2) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } } out: g_object_unref (dest); } static gboolean link_job_done (gpointer user_data) { CopyMoveJob *job; job = user_data; if (job->done_callback) { job->done_callback (job->debuting_files, !job_aborted ((CommonJob *) job), job->done_callback_data); } g_list_free_full (job->files, g_object_unref); g_object_unref (job->destination); g_hash_table_unref (job->debuting_files); g_free (job->icon_positions); finalize_common ((CommonJob *)job); nemo_file_changes_consume_changes (TRUE); return FALSE; } static gboolean link_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { CopyMoveJob *job; CommonJob *common; GFile *src; GdkPoint *point; char *dest_fs_type; int total, left; int i; GList *l; job = user_data; common = &job->common; common->io_job = io_job; dest_fs_type = NULL; nemo_progress_info_start (common->progress); verify_destination (&job->common, job->destination, NULL, -1); if (job_aborted (common)) { goto aborted; } total = left = g_list_length (job->files); report_link_progress (job, total, left); i = 0; for (l = job->files; l != NULL && !job_aborted (common); l = l->next) { src = l->data; if (i < job->n_icon_positions) { point = &job->icon_positions[i]; } else { point = NULL; } link_file (job, src, job->destination, &dest_fs_type, job->debuting_files, point, left); report_link_progress (job, total, --left); i++; } aborted: g_free (dest_fs_type); g_io_scheduler_job_send_to_mainloop (io_job, link_job_done, job, NULL); return FALSE; } void nemo_file_operations_link (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data) { CopyMoveJob *job; job = op_job_new (CopyMoveJob, parent_window); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->files = eel_g_object_list_copy (files); job->destination = g_object_ref (target_dir); if (relative_item_points != NULL && relative_item_points->len > 0) { job->icon_positions = g_memdup (relative_item_points->data, sizeof (GdkPoint) * relative_item_points->len); job->n_icon_positions = relative_item_points->len; } job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); if (!nemo_file_undo_manager_pop_flag ()) { GFile* src_dir; src_dir = g_file_get_parent (files->data); job->common.undo_info = nemo_file_undo_info_ext_new (NEMO_FILE_UNDO_OP_CREATE_LINK, g_list_length (files), src_dir, target_dir); g_object_unref (src_dir); } generate_initial_job_details (job->common.progress, OP_KIND_LINK, job->files, job->destination); add_job_to_job_queue (link_job, job, job->common.cancellable, job->common.progress, OP_KIND_LINK); } void nemo_file_operations_duplicate (GList *files, GArray *relative_item_points, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data) { CopyMoveJob *job; job = op_job_new (CopyMoveJob, parent_window); job->desktop_location = nemo_get_desktop_location (); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->files = eel_g_object_list_copy (files); job->destination = NULL; if (relative_item_points != NULL && relative_item_points->len > 0) { job->icon_positions = g_memdup (relative_item_points->data, sizeof (GdkPoint) * relative_item_points->len); job->n_icon_positions = relative_item_points->len; } job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); if (!nemo_file_undo_manager_pop_flag ()) { GFile* src_dir; src_dir = g_file_get_parent (files->data); job->common.undo_info = nemo_file_undo_info_ext_new (NEMO_FILE_UNDO_OP_DUPLICATE, g_list_length (files), src_dir, src_dir); g_object_unref (src_dir); } GFile *src_dir = g_file_get_parent (files->data); generate_initial_job_details (job->common.progress, OP_KIND_DUPE, job->files, src_dir); g_object_unref (src_dir); add_job_to_job_queue (copy_job, job, job->common.cancellable, job->common.progress, OP_KIND_DUPE); } static gboolean set_permissions_job_done (gpointer user_data) { SetPermissionsJob *job; job = user_data; g_object_unref (job->file); if (job->done_callback) { job->done_callback (!job_aborted ((CommonJob *) job), job->done_callback_data); } finalize_common ((CommonJob *)job); return FALSE; } static void set_permissions_file (SetPermissionsJob *job, GFile *file, GFileInfo *info) { CommonJob *common; GFileInfo *child_info; gboolean free_info; guint32 current; guint32 value; guint32 mask; GFileEnumerator *enumerator; GFile *child; common = (CommonJob *)job; nemo_progress_info_pulse_progress (common->progress); free_info = FALSE; if (info == NULL) { free_info = TRUE; info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, common->cancellable, NULL); /* Ignore errors */ if (info == NULL) { return; } } if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { value = job->dir_permissions; mask = job->dir_mask; } else { value = job->file_permissions; mask = job->file_mask; } if (!job_aborted (common) && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE)) { current = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE); if (common->undo_info != NULL) { nemo_file_undo_info_rec_permissions_add_file (NEMO_FILE_UNDO_INFO_REC_PERMISSIONS (common->undo_info), file, current); } current = (current & ~mask) | value; g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE, current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, common->cancellable, NULL); } if (!job_aborted (common) && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, common->cancellable, NULL); if (enumerator) { while (!job_aborted (common) && (child_info = g_file_enumerator_next_file (enumerator, common->cancellable, NULL)) != NULL) { child = g_file_get_child (file, g_file_info_get_name (child_info)); set_permissions_file (job, child, child_info); g_object_unref (child); g_object_unref (child_info); } g_file_enumerator_close (enumerator, common->cancellable, NULL); g_object_unref (enumerator); } } if (free_info) { g_object_unref (info); } } static gboolean set_permissions_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { SetPermissionsJob *job = user_data; CommonJob *common; common = (CommonJob *)job; common->io_job = io_job; nemo_progress_info_set_status (common->progress, _("Setting permissions")); nemo_progress_info_start (common->progress); set_permissions_file (job, job->file, NULL); g_io_scheduler_job_send_to_mainloop_async (io_job, set_permissions_job_done, job, NULL); return FALSE; } void nemo_file_set_permissions_recursive (const char *directory, guint32 file_permissions, guint32 file_mask, guint32 dir_permissions, guint32 dir_mask, NemoOpCallback callback, gpointer callback_data) { SetPermissionsJob *job; job = op_job_new (SetPermissionsJob, NULL); job->file = g_file_new_for_uri (directory); job->file_permissions = file_permissions; job->file_mask = file_mask; job->dir_permissions = dir_permissions; job->dir_mask = dir_mask; job->done_callback = callback; job->done_callback_data = callback_data; if (!nemo_file_undo_manager_pop_flag ()) { job->common.undo_info = nemo_file_undo_info_rec_permissions_new (job->file, file_permissions, file_mask, dir_permissions, dir_mask); } generate_initial_job_details (job->common.progress, OP_KIND_PERMISSIONS, NULL, job->file); add_job_to_job_queue (set_permissions_job, job, job->common.cancellable, job->common.progress, OP_KIND_PERMISSIONS); } static GList * location_list_from_uri_list (const GList *uris) { const GList *l; GList *files; GFile *f; files = NULL; for (l = uris; l != NULL; l = l->next) { f = g_file_new_for_uri (l->data); files = g_list_prepend (files, f); } return g_list_reverse (files); } typedef struct { NemoCopyCallback real_callback; gpointer real_data; } MoveTrashCBData; static void callback_for_move_to_trash (GHashTable *debuting_uris, gboolean user_cancelled, MoveTrashCBData *data) { if (data->real_callback) data->real_callback (debuting_uris, !user_cancelled, data->real_data); g_slice_free (MoveTrashCBData, data); } void nemo_file_operations_copy_move (const GList *item_uris, GArray *relative_item_points, const char *target_dir, GdkDragAction copy_action, GtkWidget *parent_view, NemoCopyCallback done_callback, gpointer done_callback_data) { GList *locations; GList *p; GFile *dest, *src_dir; GtkWindow *parent_window; gboolean target_is_mapping; gboolean have_nonmapping_source; dest = NULL; target_is_mapping = FALSE; have_nonmapping_source = FALSE; if (target_dir) { dest = g_file_new_for_uri (target_dir); if (g_file_has_uri_scheme (dest, "burn")) { target_is_mapping = TRUE; } } locations = location_list_from_uri_list (item_uris); for (p = locations; p != NULL; p = p->next) { if (!g_file_has_uri_scheme ((GFile* )p->data, "burn")) { have_nonmapping_source = TRUE; } } if (target_is_mapping && have_nonmapping_source && copy_action == GDK_ACTION_MOVE) { /* never move to "burn:///", but fall back to copy. * This is a workaround, because otherwise the source files would be removed. */ copy_action = GDK_ACTION_COPY; } parent_window = NULL; if (parent_view) { parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); } if (copy_action == GDK_ACTION_COPY) { src_dir = g_file_get_parent (locations->data); if (target_dir == NULL || (src_dir != NULL && g_file_equal (src_dir, dest))) { nemo_file_operations_duplicate (locations, relative_item_points, parent_window, done_callback, done_callback_data); } else { nemo_file_operations_copy (locations, relative_item_points, dest, parent_window, done_callback, done_callback_data); } if (src_dir) { g_object_unref (src_dir); } } else if (copy_action == GDK_ACTION_MOVE) { if (g_file_has_uri_scheme (dest, "trash")) { MoveTrashCBData *cb_data; cb_data = g_slice_new0 (MoveTrashCBData); cb_data->real_callback = done_callback; cb_data->real_data = done_callback_data; nemo_file_operations_trash_or_delete (locations, parent_window, (NemoDeleteCallback) callback_for_move_to_trash, cb_data); } else { nemo_file_operations_move (locations, relative_item_points, dest, parent_window, done_callback, done_callback_data); } } else { nemo_file_operations_link (locations, relative_item_points, dest, parent_window, done_callback, done_callback_data); } g_list_free_full (locations, g_object_unref); if (dest) { g_object_unref (dest); } } static gboolean create_job_done (gpointer user_data) { CreateJob *job; job = user_data; if (job->done_callback) { job->done_callback (job->created_file, !job_aborted ((CommonJob *) job), job->done_callback_data); } g_object_unref (job->dest_dir); if (job->src) { g_object_unref (job->src); } g_free (job->src_data); g_free (job->filename); if (job->created_file) { g_object_unref (job->created_file); } finalize_common ((CommonJob *)job); nemo_file_changes_consume_changes (TRUE); return FALSE; } static gboolean create_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { CreateJob *job; CommonJob *common; int count; GFile *dest; char *basename; char *filename, *filename2, *new_filename; char *filename_base, *suffix; char *dest_fs_type; GError *error; gboolean res; gboolean filename_is_utf8; char *primary, *secondary, *details; int response; char *data; int length; GFileOutputStream *out; gboolean handled_invalid_filename; int max_length, offset; job = user_data; common = &job->common; common->io_job = io_job; nemo_progress_info_start (common->progress); handled_invalid_filename = FALSE; dest_fs_type = NULL; filename = NULL; dest = NULL; max_length = get_max_name_length (job->dest_dir); verify_destination (common, job->dest_dir, NULL, -1); if (job_aborted (common)) { goto aborted; } filename = g_strdup (job->filename); filename_is_utf8 = FALSE; if (filename) { filename_is_utf8 = g_utf8_validate (filename, -1, NULL); } if (filename == NULL) { if (job->make_dir) { /* localizers: the initial name of a new folder */ filename = g_strdup (_("Untitled Folder")); filename_is_utf8 = TRUE; /* Pass in utf8 */ } else { if (job->src != NULL) { basename = g_file_get_basename (job->src); /* localizers: the initial name of a new template document */ filename = g_strdup_printf ("%s", basename); g_free (basename); } if (filename == NULL) { /* localizers: the initial name of a new empty document */ filename = g_strdup (_("Untitled Document")); filename_is_utf8 = TRUE; /* Pass in utf8 */ } } } make_file_name_valid_for_dest_fs (filename, dest_fs_type); if (filename_is_utf8) { dest = g_file_get_child_for_display_name (job->dest_dir, filename, NULL); } if (dest == NULL) { dest = g_file_get_child (job->dest_dir, filename); } count = 1; retry: error = NULL; if (job->make_dir) { res = g_file_make_directory (dest, common->cancellable, &error); if (res && common->undo_info != NULL) { nemo_file_undo_info_create_set_data (NEMO_FILE_UNDO_INFO_CREATE (common->undo_info), dest, NULL, 0); } } else { if (job->src) { res = g_file_copy (job->src, dest, G_FILE_COPY_NONE, common->cancellable, NULL, NULL, &error); if (res && common->undo_info != NULL) { gchar *uri; uri = g_file_get_uri (job->src); nemo_file_undo_info_create_set_data (NEMO_FILE_UNDO_INFO_CREATE (common->undo_info), dest, uri, 0); g_free (uri); } } else { data = ""; length = 0; if (job->src_data) { data = job->src_data; length = job->length; } out = g_file_create (dest, G_FILE_CREATE_NONE, common->cancellable, &error); if (out) { res = g_output_stream_write_all (G_OUTPUT_STREAM (out), data, length, NULL, common->cancellable, &error); if (res) { res = g_output_stream_close (G_OUTPUT_STREAM (out), common->cancellable, &error); if (res && common->undo_info != NULL) { nemo_file_undo_info_create_set_data (NEMO_FILE_UNDO_INFO_CREATE (common->undo_info), dest, data, length); } } /* This will close if the write failed and we didn't close */ g_object_unref (out); } else { res = FALSE; } } } if (res) { job->created_file = g_object_ref (dest); nemo_file_changes_queue_file_added (dest); if (job->has_position) { nemo_file_changes_queue_schedule_position_set (dest, job->position, common->monitor_num); } } else { g_assert (error != NULL); if (IS_IO_ERROR (error, INVALID_FILENAME) && !handled_invalid_filename) { handled_invalid_filename = TRUE; g_assert (dest_fs_type == NULL); dest_fs_type = query_fs_type (job->dest_dir, common->cancellable); g_clear_object (&dest); if (count == 1) { new_filename = g_strdup (filename); } else { filename_base = eel_filename_strip_extension (filename); offset = strlen (filename_base); suffix = g_strdup (filename + offset); filename2 = g_strdup_printf ("%s %d%s", filename_base, count, suffix); new_filename = NULL; if (max_length > 0 && strlen (filename2) > abs(max_length)) { new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length); } if (new_filename == NULL) { new_filename = g_strdup (filename2); } g_free (filename2); g_free (suffix); } if (make_file_name_valid_for_dest_fs (new_filename, dest_fs_type)) { g_clear_object (&dest); if (filename_is_utf8) { dest = g_file_get_child_for_display_name (job->dest_dir, new_filename, NULL); } if (dest == NULL) { dest = g_file_get_child (job->dest_dir, new_filename); } g_free (new_filename); g_error_free (error); goto retry; } g_free (new_filename); } else if (IS_IO_ERROR (error, EXISTS)) { g_clear_object (&dest); dest = NULL; filename_base = eel_filename_strip_extension (filename); offset = strlen (filename_base); suffix = g_strdup (filename + offset); filename2 = g_strdup_printf ("%s %d%s", filename_base, ++count, suffix); if (max_length > 0 && strlen (filename2) > abs(max_length)) { new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length); if (new_filename != NULL) { g_free (filename2); filename2 = new_filename; } } make_file_name_valid_for_dest_fs (filename2, dest_fs_type); if (filename_is_utf8) { dest = g_file_get_child_for_display_name (job->dest_dir, filename2, NULL); } if (dest == NULL) { dest = g_file_get_child (job->dest_dir, filename2); } g_free (filename2); g_free (suffix); g_error_free (error); goto retry; } else if (IS_IO_ERROR (error, CANCELLED)) { g_error_free (error); } /* Other error */ else { if (job->make_dir) { primary = f (_("Error while creating directory %B."), dest); } else { primary = f (_("Error while creating file %B."), dest); } secondary = f (_("There was an error creating the directory in %F."), job->dest_dir); details = error->message; response = run_warning (common, primary, secondary, details, FALSE, GTK_STOCK_CANCEL, SKIP, NULL); g_error_free (error); if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { /* skip */ /* do nothing */ } else { g_assert_not_reached (); } } } aborted: g_clear_object (&dest); g_free (filename); g_free (dest_fs_type); g_io_scheduler_job_send_to_mainloop_async (io_job, create_job_done, job, NULL); return FALSE; } void nemo_file_operations_new_folder (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, NemoCreateCallback done_callback, gpointer done_callback_data) { CreateJob *job; GtkWindow *parent_window; parent_window = NULL; if (parent_view) { parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); } job = op_job_new (CreateJob, parent_window); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->dest_dir = g_file_new_for_uri (parent_dir); job->make_dir = TRUE; if (target_point != NULL) { job->position = *target_point; job->has_position = TRUE; } if (!nemo_file_undo_manager_pop_flag ()) { job->common.undo_info = nemo_file_undo_info_create_new (NEMO_FILE_UNDO_OP_CREATE_FOLDER); } add_job_to_job_queue (create_job, job, job->common.cancellable, job->common.progress, OP_KIND_CREATE); } void nemo_file_operations_new_file_from_template (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, const char *target_filename, const char *template_uri, NemoCreateCallback done_callback, gpointer done_callback_data) { CreateJob *job; GtkWindow *parent_window; parent_window = NULL; if (parent_view) { parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); } job = op_job_new (CreateJob, parent_window); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->dest_dir = g_file_new_for_uri (parent_dir); if (target_point != NULL) { job->position = *target_point; job->has_position = TRUE; } job->filename = g_strdup (target_filename); if (template_uri) { job->src = g_file_new_for_uri (template_uri); } if (!nemo_file_undo_manager_pop_flag ()) { job->common.undo_info = nemo_file_undo_info_create_new (NEMO_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE); } add_job_to_job_queue (create_job, job, job->common.cancellable, job->common.progress, OP_KIND_CREATE); } void nemo_file_operations_new_file (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, const char *target_filename, const char *initial_contents, int length, NemoCreateCallback done_callback, gpointer done_callback_data) { CreateJob *job; GtkWindow *parent_window; parent_window = NULL; if (parent_view) { parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); } job = op_job_new (CreateJob, parent_window); job->done_callback = done_callback; job->done_callback_data = done_callback_data; job->dest_dir = g_file_new_for_uri (parent_dir); if (target_point != NULL) { job->position = *target_point; job->has_position = TRUE; } job->src_data = g_memdup (initial_contents, length); job->length = length; job->filename = g_strdup (target_filename); if (!nemo_file_undo_manager_pop_flag ()) { job->common.undo_info = nemo_file_undo_info_create_new (NEMO_FILE_UNDO_OP_CREATE_EMPTY_FILE); } add_job_to_job_queue (create_job, job, job->common.cancellable, job->common.progress, OP_KIND_CREATE); } static void delete_trash_file (CommonJob *job, GFile *file, int *deletions_since_progress, gboolean del_file, gboolean del_children) { GFileInfo *info; GFile *child; GFileEnumerator *enumerator; if (job_aborted (job)) { return; } if (del_children) { enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, NULL); if (enumerator) { while (!job_aborted (job) && (info = g_file_enumerator_next_file (enumerator, job->cancellable, NULL)) != NULL) { child = g_file_get_child (file, g_file_info_get_name (info)); delete_trash_file (job, child, deletions_since_progress, TRUE, g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY); g_object_unref (child); g_object_unref (info); } g_file_enumerator_close (enumerator, job->cancellable, NULL); g_object_unref (enumerator); } } if (!job_aborted (job) && del_file) { file_delete_wrapper (file, job->cancellable, NULL); if ((*deletions_since_progress)++ > 100) { nemo_progress_info_pulse_progress (job->progress); *deletions_since_progress = 0; } } } static gboolean empty_trash_job_done (gpointer user_data) { EmptyTrashJob *job; job = user_data; g_list_free_full (job->trash_dirs, g_object_unref); if (job->done_callback) { job->done_callback (!job_aborted ((CommonJob *) job), job->done_callback_data); } finalize_common ((CommonJob *)job); return FALSE; } static gboolean empty_trash_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { EmptyTrashJob *job = user_data; CommonJob *common; GList *l; gboolean confirmed; int deletions_since_progress = 0; common = (CommonJob *)job; common->io_job = io_job; nemo_progress_info_start (common->progress); if (job->should_confirm && !job_aborted (common)) { confirmed = confirm_empty_trash (common); } else { confirmed = TRUE; } if (confirmed) { nemo_progress_info_set_status (common->progress, _("Emptying Trash")); nemo_progress_info_set_details (common->progress, _("Emptying Trash")); for (l = job->trash_dirs; l != NULL && !job_aborted (common); l = l->next) { delete_trash_file (common, l->data, &deletions_since_progress, FALSE, TRUE); } } g_io_scheduler_job_send_to_mainloop_async (io_job, empty_trash_job_done, job, NULL); return FALSE; } void nemo_file_operations_empty_trash (GtkWidget *parent_view) { EmptyTrashJob *job; GtkWindow *parent_window; parent_window = NULL; if (parent_view) { parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); } job = op_job_new (EmptyTrashJob, parent_window); job->trash_dirs = g_list_prepend (job->trash_dirs, g_file_new_for_uri ("trash:")); job->should_confirm = TRUE; inhibit_power_manager ((CommonJob *)job, _("Emptying Trash")); generate_initial_job_details (job->common.progress, OP_KIND_EMPTY_TRASH, NULL, NULL); add_job_to_job_queue (empty_trash_job, job, job->common.cancellable, job->common.progress, OP_KIND_EMPTY_TRASH); } static gboolean mark_trusted_job_done (gpointer user_data) { MarkTrustedJob *job = user_data; g_object_unref (job->file); if (job->done_callback) { job->done_callback (!job_aborted ((CommonJob *) job), job->done_callback_data); } finalize_common ((CommonJob *)job); return FALSE; } #define TRUSTED_SHEBANG "#!/usr/bin/env xdg-open\n" static void mark_desktop_file_trusted (CommonJob *common, GCancellable *cancellable, GFile *file, gboolean interactive) { char *contents, *new_contents; gsize length, new_length; GError *error; guint32 current_perms, new_perms; int response; GFileInfo *info; retry: error = NULL; if (!g_file_load_contents (file, cancellable, &contents, &length, NULL, &error)) { if (interactive) { response = run_error (common, g_strdup (_("Unable to mark launcher trusted (executable)")), error->message, NULL, FALSE, GTK_STOCK_CANCEL, RETRY, NULL); } else { response = 0; } if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { goto retry; } else { g_assert_not_reached (); } goto out; } if (!g_str_has_prefix (contents, "#!")) { new_length = length + strlen (TRUSTED_SHEBANG); new_contents = g_malloc (new_length); strcpy (new_contents, TRUSTED_SHEBANG); memcpy (new_contents + strlen (TRUSTED_SHEBANG), contents, length); if (!g_file_replace_contents (file, new_contents, new_length, NULL, FALSE, 0, NULL, cancellable, &error)) { g_free (contents); g_free (new_contents); if (interactive) { response = run_error (common, g_strdup (_("Unable to mark launcher trusted (executable)")), error->message, NULL, FALSE, GTK_STOCK_CANCEL, RETRY, NULL); } else { response = 0; } if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { goto retry; } else { g_assert_not_reached (); } goto out; } g_free (new_contents); } g_free (contents); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, common->cancellable, &error); if (info == NULL) { if (interactive) { response = run_error (common, g_strdup (_("Unable to mark launcher trusted (executable)")), error->message, NULL, FALSE, GTK_STOCK_CANCEL, RETRY, NULL); } else { response = 0; } if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { goto retry; } else { g_assert_not_reached (); } goto out; } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE)) { current_perms = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE); new_perms = current_perms | S_IXGRP | S_IXUSR | S_IXOTH; if ((current_perms != new_perms) && !g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE, new_perms, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, common->cancellable, &error)) { g_object_unref (info); if (interactive) { response = run_error (common, g_strdup (_("Unable to mark launcher trusted (executable)")), error->message, NULL, FALSE, GTK_STOCK_CANCEL, RETRY, NULL); } else { response = 0; } if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { abort_job (common); } else if (response == 1) { goto retry; } else { g_assert_not_reached (); } goto out; } } g_object_unref (info); out: ; } static gboolean mark_trusted_job (GIOSchedulerJob *io_job, GCancellable *cancellable, gpointer user_data) { MarkTrustedJob *job = user_data; CommonJob *common; common = (CommonJob *)job; common->io_job = io_job; nemo_progress_info_start (common->progress); mark_desktop_file_trusted (common, cancellable, job->file, job->interactive); g_io_scheduler_job_send_to_mainloop_async (io_job, mark_trusted_job_done, job, NULL); return FALSE; } void nemo_file_mark_desktop_file_trusted (GFile *file, GtkWindow *parent_window, gboolean interactive, NemoOpCallback done_callback, gpointer done_callback_data) { MarkTrustedJob *job; job = op_job_new (MarkTrustedJob, parent_window); job->file = g_object_ref (file); job->interactive = interactive; job->done_callback = done_callback; job->done_callback_data = done_callback_data; add_job_to_job_queue (mark_trusted_job, job, job->common.cancellable, job->common.progress, OP_KIND_PERMISSIONS); } #if 0 #define DEBUG_FILE_OP_QUEUE #endif static gboolean job_is_local (GList *files, GFile *destination) { gboolean ret = FALSE; NemoFile *source = nemo_file_get_existing (G_FILE (files->data)); if (source == NULL) return FALSE; NemoFile *dest = destination != NULL ? nemo_file_get_existing (destination) : NULL; if (dest != NULL) { ret = nemo_file_is_local (source) && nemo_file_is_local (dest); } else { ret = nemo_file_is_local (source); } nemo_file_unref (source); nemo_file_unref (dest); #ifdef DEBUG_FILE_OP_QUEUE g_message ("File op job is local: %s\n", ret ? "TRUE" : "FALSE"); #endif return ret; } static gboolean job_is_same_fs (GList *files, GFile *destination) { gboolean ret = FALSE; NemoFile *source = nemo_file_get_existing (G_FILE (files->data)); if (source == NULL) return FALSE; NemoFile *dest = nemo_file_get_existing (destination); if (dest != NULL) { gchar *src_fs_id = nemo_file_get_filesystem_id (source); gchar *dst_fs_id = nemo_file_get_filesystem_id (dest); if (g_strcmp0 (src_fs_id, dst_fs_id) == 0) ret = TRUE; #ifdef DEBUG_FILE_OP_QUEUE g_message ("File op job is same filesystem (src: %s, dst: %s): %s\n", src_fs_id, dst_fs_id, ret ? "TRUE" : "FALSE"); #endif g_free (src_fs_id); g_free (dst_fs_id); } nemo_file_unref (source); nemo_file_unref (dest); return ret; } static gboolean job_has_no_folders (GList *files) { GList *l; gboolean ret = TRUE; for (l = files; l != NULL; l = l->next) { GFile *location = G_FILE (l->data); NemoFile *file = nemo_file_get_existing (location); if (file == NULL) { ret = FALSE; break; } if (nemo_file_is_directory (file)) { ret = FALSE; nemo_file_unref (file); break; } nemo_file_unref (file); } #ifdef DEBUG_FILE_OP_QUEUE g_message ("File op job has no folders: %s\n", ret ? "TRUE" : "FALSE"); #endif return ret; } static gboolean job_is_small (GList *files) { gboolean ret = FALSE; GList *l; goffset size = 0; for (l = files; l != NULL; l = l->next) { GFile *location = G_FILE (l->data); NemoFile *file = nemo_file_get_existing (location); if (file == NULL) { size = G_MAXOFFSET; break; } size = size + nemo_file_get_size (file); nemo_file_unref (file); } ret = size < 104857600; /* 100 mb */ #ifdef DEBUG_FILE_OP_QUEUE g_message ("File op job is small: %s\n", ret ? "TRUE" : "FALSE"); #endif return ret; } static gboolean should_start_immediately (OpKind kind, gpointer op_data) { gboolean ret = FALSE; switch (kind) { case OP_KIND_CREATE: case OP_KIND_TRUST: case OP_KIND_EMPTY_TRASH: case OP_KIND_PERMISSIONS: case OP_KIND_LINK: ret = TRUE; break; case OP_KIND_MOVE: ; CopyMoveJob *mjob = (CopyMoveJob *) op_data; ret = job_is_same_fs (mjob->files, mjob->destination) && job_is_local (mjob->files, mjob->destination); break; case OP_KIND_COPY: ; CopyMoveJob *cjob = (CopyMoveJob *) op_data; ret = job_is_same_fs (cjob->files, cjob->destination) && job_is_local (cjob->files, cjob->destination) && job_has_no_folders (cjob->files) && job_is_small (cjob->files); break; case OP_KIND_DUPE: ; CopyMoveJob *dupejob = (CopyMoveJob *) op_data; ret = job_is_local (dupejob->files, dupejob->destination) && job_has_no_folders (dupejob->files) && job_is_small (dupejob->files); break; case OP_KIND_DELETE: case OP_KIND_TRASH: ; DeleteJob *deljob = (DeleteJob *) op_data; ret = job_is_local (deljob->files, NULL) || (job_has_no_folders (deljob->files) && job_is_small (deljob->files)); break; default: ret = FALSE; break; } #ifdef DEBUG_FILE_OP_QUEUE g_message ("File op job STARTING IMMEDIATELY: %s\n", ret ? "TRUE" : "FALSE"); #endif return ret; } void add_job_to_job_queue (GIOSchedulerJobFunc job_func, gpointer user_data, GCancellable *cancellable, NemoProgressInfo *info, OpKind kind) { gboolean start_immediately; NemoJobQueue *job_queue = nemo_job_queue_get (); start_immediately = should_start_immediately (kind, user_data); nemo_job_queue_add_new_job (job_queue, job_func, user_data, cancellable, info, start_immediately); } #if !defined (NEMO_OMIT_SELF_CHECK) void nemo_self_check_file_operations (void) { setlocale (LC_MESSAGES, "C"); /* test the next duplicate name generator */ EEL_CHECK_STRING_RESULT (get_duplicate_name (" (copy)", 1, -1), " (another copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo", 1, -1), "foo (copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name (".bashrc", 1, -1), ".bashrc (copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name (".foo.txt", 1, -1), ".foo (copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo", 1, -1), "foo foo (copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo.txt", 1, -1), "foo (copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt", 1, -1), "foo foo (copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt txt", 1, -1), "foo foo (copy).txt txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...txt", 1, -1), "foo.. (copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...", 1, -1), "foo... (copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo. (copy)", 1, -1), "foo. (another copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy)", 1, -1), "foo (another copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy).txt", 1, -1), "foo (another copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy)", 1, -1), "foo (3rd copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy).txt", 1, -1), "foo (3rd copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (another copy).txt", 1, -1), "foo foo (3rd copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy)", 1, -1), "foo (14th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy).txt", 1, -1), "foo (14th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy)", 1, -1), "foo (22nd copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy).txt", 1, -1), "foo (22nd copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy)", 1, -1), "foo (23rd copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy).txt", 1, -1), "foo (23rd copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy)", 1, -1), "foo (24th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy).txt", 1, -1), "foo (24th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy)", 1, -1), "foo (25th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy).txt", 1, -1), "foo (25th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy)", 1, -1), "foo foo (25th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy).txt", 1, -1), "foo foo (25th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (100000000000000th copy).txt", 1, -1), "foo foo (copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy)", 1, -1), "foo (11th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy).txt", 1, -1), "foo (11th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy)", 1, -1), "foo (12th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy).txt", 1, -1), "foo (12th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy)", 1, -1), "foo (13th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy).txt", 1, -1), "foo (13th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy)", 1, -1), "foo (111th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy).txt", 1, -1), "foo (111th copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy)", 1, -1), "foo (123rd copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy).txt", 1, -1), "foo (123rd copy).txt"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy)", 1, -1), "foo (124th copy)"); EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy).txt", 1, -1), "foo (124th copy).txt"); setlocale (LC_MESSAGES, ""); } #endif nemo-4.4.2/libnemo-private/nemo-file-operations.h000066400000000000000000000155241357442400300217720ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-operations: execute file operations. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Ettore Perazzoli , Pavel Cisler */ #ifndef NEMO_FILE_OPERATIONS_H #define NEMO_FILE_OPERATIONS_H #include #include typedef void (* NemoCopyCallback) (GHashTable *debuting_uris, gboolean success, gpointer callback_data); typedef void (* NemoCreateCallback) (GFile *new_file, gboolean success, gpointer callback_data); typedef void (* NemoOpCallback) (gboolean success, gpointer callback_data); typedef void (* NemoDeleteCallback) (GHashTable *debuting_uris, gboolean user_cancel, gpointer callback_data); typedef void (* NemoMountCallback) (GVolume *volume, gboolean success, GObject *callback_data_object); typedef void (* NemoUnmountCallback) (gpointer callback_data); /* FIXME: int copy_action should be an enum */ void nemo_file_operations_copy_move (const GList *item_uris, GArray *relative_item_points, const char *target_dir_uri, GdkDragAction copy_action, GtkWidget *parent_view, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_operations_copy_file (GFile *source_file, GFile *target_dir, const gchar *source_display_name, const gchar *new_name, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_operations_empty_trash (GtkWidget *parent_view); void nemo_file_operations_new_folder (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir_uri, NemoCreateCallback done_callback, gpointer done_callback_data); void nemo_file_operations_new_file (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, const char *target_filename, const char *initial_contents, int length, NemoCreateCallback done_callback, gpointer data); void nemo_file_operations_new_file_from_template (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, const char *target_filename, const char *template_uri, NemoCreateCallback done_callback, gpointer data); void nemo_file_operations_delete (GList *files, GtkWindow *parent_window, NemoDeleteCallback done_callback, gpointer done_callback_data); void nemo_file_operations_trash_or_delete (GList *files, GtkWindow *parent_window, NemoDeleteCallback done_callback, gpointer done_callback_data); void nemo_file_set_permissions_recursive (const char *directory, guint32 file_permissions, guint32 file_mask, guint32 folder_permissions, guint32 folder_mask, NemoOpCallback callback, gpointer callback_data); void nemo_file_operations_unmount_mount (GtkWindow *parent_window, GMount *mount, gboolean eject, gboolean check_trash); void nemo_file_operations_unmount_mount_full (GtkWindow *parent_window, GMount *mount, GMountOperation *mount_operation, gboolean eject, gboolean check_trash, NemoUnmountCallback callback, gpointer callback_data); void nemo_file_operations_mount_volume (GtkWindow *parent_window, GVolume *volume); void nemo_file_operations_mount_volume_full (GtkWindow *parent_window, GVolume *volume, NemoMountCallback mount_callback, GObject *mount_callback_data_object); void nemo_file_operations_copy (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_operations_move (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_operations_duplicate (GList *files, GArray *relative_item_points, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_operations_link (GList *files, GArray *relative_item_points, GFile *target_dir, GtkWindow *parent_window, NemoCopyCallback done_callback, gpointer done_callback_data); void nemo_file_mark_desktop_file_trusted (GFile *file, GtkWindow *parent_window, gboolean interactive, NemoOpCallback done_callback, gpointer done_callback_data); #endif /* NEMO_FILE_OPERATIONS_H */ nemo-4.4.2/libnemo-private/nemo-file-private.h000066400000000000000000000253111357442400300212540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-file-private.h: Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_FILE_PRIVATE_H #define NEMO_FILE_PRIVATE_H #include #include #include #include #include #include #define NEMO_FILE_DEFAULT_ATTRIBUTES \ "standard::*,access::*,mountable::*,time::*,unix::*,owner::*,selinux::*,thumbnail::*,id::filesystem,trash::orig-path,trash::deletion-date,metadata::*" /* These are in the typical sort order. Known things come first, then * things where we can't know, finally things where we don't yet know. */ typedef enum { KNOWN, UNKNOWABLE, UNKNOWN } Knowledge; typedef enum { FILE_PINNING_UNKNOWN = -1, FILE_PINNED = 0, FILE_NOT_PINNED, } NemoFilePinning; struct NemoFileDetails { NemoDirectory *directory; eel_ref_str name; /* File info: */ GFileType type; eel_ref_str display_name; char *display_name_collation_key; eel_ref_str edit_name; goffset size; /* -1 is unknown */ int sort_order; guint32 permissions; int uid; /* -1 is none */ int gid; /* -1 is none */ eel_ref_str owner; eel_ref_str owner_real; eel_ref_str group; time_t atime; /* 0 is unknown */ time_t mtime; /* 0 is unknown */ time_t ctime; /* 0 is unknown */ time_t btime; /* 0 is unknown */ char *symlink_name; eel_ref_str mime_type; char *selinux_context; char *description; GError *get_info_error; guint directory_count; guint deep_directory_count; guint deep_file_count; guint deep_unreadable_count; guint deep_hidden_count; goffset deep_size; GIcon *icon; char *thumbnail_path; eel_boolean_bit thumbnail_access_problem : 1; GdkPixbuf *thumbnail; time_t thumbnail_mtime; gint thumbnail_throttle_count; time_t last_thumbnail_try_mtime; GList *mime_list; /* If this is a directory, the list of MIME types in it. */ /* Info you might get from a link (.desktop, .directory or nemo link) */ GIcon *custom_icon; char *activation_uri; /* used during DND, for checking whether source and destination are on * the same file system. */ eel_ref_str filesystem_id; char *trash_orig_path; /* The following is for file operations in progress. Since * there are normally only a few of these, we can move them to * a separate hash table or something if required to keep the * file objects small. */ GList *operations_in_progress; /* NemoInfoProviders that need to be run for this file */ GList *pending_info_providers; /* Emblems provided by extensions */ GList *extension_emblems; GList *pending_extension_emblems; /* Attributes provided by extensions */ GHashTable *extension_attributes; GHashTable *pending_extension_attributes; GHashTable *metadata; /* Mount for mountpoint or the references GMount for a "mountable" */ GMount *mount; /* boolean fields: bitfield to save space, since there can be many NemoFile objects. */ eel_boolean_bit unconfirmed : 1; eel_boolean_bit is_gone : 1; /* Set when emitting files_added on the directory to make sure we add a file, and only once */ eel_boolean_bit is_added : 1; /* Set by the NemoDirectory while it's loading the file * list so the file knows not to do redundant I/O. */ eel_boolean_bit loading_directory : 1; eel_boolean_bit got_file_info : 1; eel_boolean_bit get_info_failed : 1; eel_boolean_bit file_info_is_up_to_date : 1; eel_boolean_bit got_btime : 1; eel_boolean_bit get_btime_failed : 1; eel_boolean_bit btime_is_up_to_date : 1; eel_boolean_bit got_directory_count : 1; eel_boolean_bit directory_count_failed : 1; eel_boolean_bit directory_count_is_up_to_date : 1; eel_boolean_bit deep_counts_status : 2; /* NemoRequestStatus */ /* no deep_counts_are_up_to_date field; since we expose intermediate values for this attribute, we do actually forget it rather than invalidating. */ eel_boolean_bit got_mime_list : 1; eel_boolean_bit mime_list_failed : 1; eel_boolean_bit mime_list_is_up_to_date : 1; eel_boolean_bit mount_is_up_to_date : 1; eel_boolean_bit got_link_info : 1; eel_boolean_bit link_info_is_up_to_date : 1; eel_boolean_bit got_custom_display_name : 1; eel_boolean_bit got_custom_activation_uri : 1; eel_boolean_bit thumbnail_is_up_to_date : 1; eel_boolean_bit thumbnail_wants_original : 1; eel_boolean_bit thumbnail_tried_original : 1; eel_boolean_bit thumbnailing_failed : 1; eel_boolean_bit is_thumbnailing : 1; eel_boolean_bit is_desktop_orphan : 1; /* TRUE if the file is open in a spatial window */ eel_boolean_bit has_open_window : 1; eel_boolean_bit is_launcher : 1; eel_boolean_bit is_trusted_link : 1; eel_boolean_bit is_foreign_link : 1; eel_boolean_bit is_symlink : 1; eel_boolean_bit is_mountpoint : 1; eel_boolean_bit is_hidden : 1; eel_boolean_bit has_permissions : 1; eel_boolean_bit can_read : 1; eel_boolean_bit can_write : 1; eel_boolean_bit can_execute : 1; eel_boolean_bit can_delete : 1; eel_boolean_bit can_trash : 1; eel_boolean_bit can_rename : 1; eel_boolean_bit can_mount : 1; eel_boolean_bit can_unmount : 1; eel_boolean_bit can_eject : 1; eel_boolean_bit can_start : 1; eel_boolean_bit can_start_degraded : 1; eel_boolean_bit can_stop : 1; eel_boolean_bit start_stop_type : 3; /* GDriveStartStopType */ eel_boolean_bit can_poll_for_media : 1; eel_boolean_bit is_media_check_automatic : 1; eel_boolean_bit filesystem_readonly : 1; eel_boolean_bit filesystem_use_preview : 2; /* GFilesystemPreviewType */ eel_boolean_bit filesystem_info_is_up_to_date : 1; NemoFilePinning pinning; time_t trash_time; /* 0 is unknown */ guint64 free_space; /* (guint)-1 for unknown */ time_t free_space_read; /* The time free_space was updated, or 0 for never */ gint desktop_monitor; gint cached_position_x; gint cached_position_y; }; typedef struct { NemoFile *file; GCancellable *cancellable; NemoFileOperationCallback callback; gpointer callback_data; gboolean is_rename; gpointer data; GDestroyNotify free_data; NemoFileUndoInfo *undo_info; } NemoFileOperation; NemoFile *nemo_file_new_from_info (NemoDirectory *directory, GFileInfo *info); void nemo_file_emit_changed (NemoFile *file); void nemo_file_mark_gone (NemoFile *file); void nemo_file_set_directory (NemoFile *file, NemoDirectory *directory); gboolean nemo_file_get_date (NemoFile *file, NemoDateType date_type, time_t *date); void nemo_file_updated_deep_count_in_progress (NemoFile *file); void nemo_file_clear_info (NemoFile *file); /* Compare file's state with a fresh file info struct, return FALSE if * no change, update file and return TRUE if the file info contains * new state. */ gboolean nemo_file_update_info (NemoFile *file, GFileInfo *info); gboolean nemo_file_update_name (NemoFile *file, const char *name); gboolean nemo_file_update_metadata_from_info (NemoFile *file, GFileInfo *info); gboolean nemo_file_update_name_and_directory (NemoFile *file, const char *name, NemoDirectory *directory); gboolean nemo_file_set_display_name (NemoFile *file, const char *display_name, const char *edit_name, gboolean custom); /* Mark specified attributes for this file out of date without canceling current * I/O or kicking off new I/O. */ void nemo_file_invalidate_attributes_internal (NemoFile *file, NemoFileAttributes file_attributes); NemoFileAttributes nemo_file_get_all_attributes (void); gboolean nemo_file_is_self_owned (NemoFile *file); void nemo_file_invalidate_count_and_mime_list (NemoFile *file); gboolean nemo_file_rename_in_progress (NemoFile *file); void nemo_file_invalidate_extension_info_internal (NemoFile *file); void nemo_file_info_providers_done (NemoFile *file); /* Thumbnailing: */ void nemo_file_set_is_thumbnailing (NemoFile *file, gboolean is_thumbnailing); NemoFileOperation *nemo_file_operation_new (NemoFile *file, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_operation_free (NemoFileOperation *op); void nemo_file_operation_complete (NemoFileOperation *op, GFile *result_location, GError *error); void nemo_file_operation_cancel (NemoFileOperation *op); #endif nemo-4.4.2/libnemo-private/nemo-file-queue.c000066400000000000000000000053671357442400300207320ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 2001 Maciej Stachowiak 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Maciej Stachowiak */ #include #include "nemo-file-queue.h" #include struct NemoFileQueue { GList *head; GList *tail; GHashTable *item_to_link_map; }; NemoFileQueue * nemo_file_queue_new (void) { NemoFileQueue *queue; queue = g_new0 (NemoFileQueue, 1); queue->item_to_link_map = g_hash_table_new (g_direct_hash, g_direct_equal); return queue; } void nemo_file_queue_destroy (NemoFileQueue *queue) { g_hash_table_destroy (queue->item_to_link_map); nemo_file_list_free (queue->head); g_free (queue); } void nemo_file_queue_enqueue (NemoFileQueue *queue, NemoFile *file) { if (g_hash_table_lookup (queue->item_to_link_map, file) != NULL) { /* It's already on the queue. */ return; } if (queue->tail == NULL) { queue->head = g_list_append (NULL, file); queue->tail = queue->head; } else { queue->tail = g_list_append (queue->tail, file); queue->tail = queue->tail->next; } nemo_file_ref (file); g_hash_table_insert (queue->item_to_link_map, file, queue->tail); } NemoFile * nemo_file_queue_dequeue (NemoFileQueue *queue) { NemoFile *file; file = nemo_file_queue_head (queue); nemo_file_queue_remove (queue, file); return file; } void nemo_file_queue_remove (NemoFileQueue *queue, NemoFile *file) { GList *link; link = g_hash_table_lookup (queue->item_to_link_map, file); if (link == NULL) { /* It's not on the queue */ return; } if (link == queue->tail) { /* Need to special-case removing the tail. */ queue->tail = queue->tail->prev; } queue->head = g_list_remove_link (queue->head, link); g_list_free (link); g_hash_table_remove (queue->item_to_link_map, file); nemo_file_unref (file); } NemoFile * nemo_file_queue_head (NemoFileQueue *queue) { if (queue->head == NULL) { return NULL; } return NEMO_FILE (queue->head->data); } gboolean nemo_file_queue_is_empty (NemoFileQueue *queue) { return (queue->head == NULL); } nemo-4.4.2/libnemo-private/nemo-file-queue.h000066400000000000000000000036741357442400300207360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 2001 Maciej Stachowiak 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Maciej Stachowiak */ #ifndef NEMO_FILE_QUEUE_H #define NEMO_FILE_QUEUE_H #include typedef struct NemoFileQueue NemoFileQueue; NemoFileQueue *nemo_file_queue_new (void); void nemo_file_queue_destroy (NemoFileQueue *queue); /* Add a file to the tail of the queue, unless it's already in the queue */ void nemo_file_queue_enqueue (NemoFileQueue *queue, NemoFile *file); /* Return the file at the head of the queue after removing it from the * queue. This is dangerous unless you have another ref to the file, * since it will unref it. */ NemoFile * nemo_file_queue_dequeue (NemoFileQueue *queue); /* Remove a file from an arbitrary point in the queue in constant time. */ void nemo_file_queue_remove (NemoFileQueue *queue, NemoFile *file); /* Get the file at the head of the queue without removing or unrefing it. */ NemoFile * nemo_file_queue_head (NemoFileQueue *queue); gboolean nemo_file_queue_is_empty (NemoFileQueue *queue); #endif /* NEMO_FILE_CHANGES_QUEUE_H */ nemo-4.4.2/libnemo-private/nemo-file-undo-manager.c000066400000000000000000000161451357442400300221570ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-undo-manager.c - Manages the undo/redo stack * * Copyright (C) 2007-2011 Amos Brocco * Copyright (C) 2010, 2012 Red Hat, Inc. * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Amos Brocco * Cosimo Cecchi * */ #include #include "nemo-file-undo-manager.h" #include "nemo-file-operations.h" #include "nemo-file.h" #include "nemo-trash-monitor.h" #include #define DEBUG_FLAG NEMO_DEBUG_UNDO #include "nemo-debug.h" enum { SIGNAL_UNDO_CHANGED, NUM_SIGNALS, }; static guint signals[NUM_SIGNALS] = { 0, }; G_DEFINE_TYPE (NemoFileUndoManager, nemo_file_undo_manager, G_TYPE_OBJECT) struct _NemoFileUndoManagerPrivate { NemoFileUndoInfo *info; NemoFileUndoManagerState state; NemoFileUndoManagerState last_state; guint undo_redo_flag : 1; gulong trash_signal_id; }; static NemoFileUndoManager *undo_singleton = NULL; static NemoFileUndoManager * get_singleton (void) { if (undo_singleton == NULL) { undo_singleton = g_object_new (NEMO_TYPE_FILE_UNDO_MANAGER, NULL); g_object_add_weak_pointer (G_OBJECT (undo_singleton), (gpointer) &undo_singleton); } return undo_singleton; } static void file_undo_manager_clear (NemoFileUndoManager *self) { g_clear_object (&self->priv->info); self->priv->state = NEMO_FILE_UNDO_MANAGER_STATE_NONE; } static void trash_state_changed_cb (NemoTrashMonitor *monitor, gboolean is_empty, gpointer user_data) { NemoFileUndoManager *self = user_data; if (!is_empty) { return; } if (self->priv->state == NEMO_FILE_UNDO_MANAGER_STATE_NONE) { return; } if (NEMO_IS_FILE_UNDO_INFO_TRASH (self->priv->info)) { file_undo_manager_clear (self); g_signal_emit (self, signals[SIGNAL_UNDO_CHANGED], 0); } } static void nemo_file_undo_manager_init (NemoFileUndoManager * self) { NemoFileUndoManagerPrivate *priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_FILE_UNDO_MANAGER, NemoFileUndoManagerPrivate); priv->trash_signal_id = g_signal_connect (nemo_trash_monitor_get (), "trash-state-changed", G_CALLBACK (trash_state_changed_cb), self); } static void nemo_file_undo_manager_finalize (GObject * object) { NemoFileUndoManager *self = NEMO_FILE_UNDO_MANAGER (object); NemoFileUndoManagerPrivate *priv = self->priv; if (priv->trash_signal_id != 0) { g_signal_handler_disconnect (nemo_trash_monitor_get (), priv->trash_signal_id); priv->trash_signal_id = 0; } file_undo_manager_clear (self); G_OBJECT_CLASS (nemo_file_undo_manager_parent_class)->finalize (object); } static void nemo_file_undo_manager_class_init (NemoFileUndoManagerClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_file_undo_manager_finalize; signals[SIGNAL_UNDO_CHANGED] = g_signal_new ("undo-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (NemoFileUndoManagerPrivate)); } static void undo_info_apply_ready (GObject *source, GAsyncResult *res, gpointer user_data) { NemoFileUndoManager *self = user_data; NemoFileUndoInfo *info = NEMO_FILE_UNDO_INFO (source); gboolean success, user_cancel; success = nemo_file_undo_info_apply_finish (info, res, &user_cancel, NULL); /* just return in case we got another another operation set */ if ((self->priv->info != NULL) && (self->priv->info != info)) { return; } if (success) { if (self->priv->last_state == NEMO_FILE_UNDO_MANAGER_STATE_UNDO) { self->priv->state = NEMO_FILE_UNDO_MANAGER_STATE_REDO; } else if (self->priv->last_state == NEMO_FILE_UNDO_MANAGER_STATE_REDO) { self->priv->state = NEMO_FILE_UNDO_MANAGER_STATE_UNDO; } self->priv->info = g_object_ref (info); } else if (user_cancel) { self->priv->state = self->priv->last_state; self->priv->info = g_object_ref (info); } else { file_undo_manager_clear (self); } g_signal_emit (self, signals[SIGNAL_UNDO_CHANGED], 0); } static void do_undo_redo (NemoFileUndoManager *self, GtkWindow *parent_window) { gboolean undo = self->priv->state == NEMO_FILE_UNDO_MANAGER_STATE_UNDO; self->priv->last_state = self->priv->state; nemo_file_undo_manager_push_flag (); nemo_file_undo_info_apply_async (self->priv->info, undo, parent_window, undo_info_apply_ready, self); /* clear actions while undoing */ file_undo_manager_clear (self); g_signal_emit (self, signals[SIGNAL_UNDO_CHANGED], 0); } void nemo_file_undo_manager_redo (GtkWindow *parent_window) { NemoFileUndoManager *self = get_singleton (); if (self->priv->state != NEMO_FILE_UNDO_MANAGER_STATE_REDO) { g_warning ("Called redo, but state is %s!", self->priv->state == 0 ? "none" : "undo"); return; } do_undo_redo (self, parent_window); } void nemo_file_undo_manager_undo (GtkWindow *parent_window) { NemoFileUndoManager *self = get_singleton (); if (self->priv->state != NEMO_FILE_UNDO_MANAGER_STATE_UNDO) { g_warning ("Called undo, but state is %s!", self->priv->state == 0 ? "none" : "redo"); return; } do_undo_redo (self, parent_window); } void nemo_file_undo_manager_set_action (NemoFileUndoInfo *info) { NemoFileUndoManager *self = get_singleton (); DEBUG ("Setting undo information %p", info); file_undo_manager_clear (self); if (info != NULL) { self->priv->info = g_object_ref (info); self->priv->state = NEMO_FILE_UNDO_MANAGER_STATE_UNDO; self->priv->last_state = NEMO_FILE_UNDO_MANAGER_STATE_NONE; } g_signal_emit (self, signals[SIGNAL_UNDO_CHANGED], 0); } NemoFileUndoInfo * nemo_file_undo_manager_get_action (void) { NemoFileUndoManager *self = get_singleton (); return self->priv->info; } NemoFileUndoManagerState nemo_file_undo_manager_get_state (void) { NemoFileUndoManager *self = get_singleton (); return self->priv->state; } void nemo_file_undo_manager_push_flag (void) { NemoFileUndoManager *self = get_singleton (); NemoFileUndoManagerPrivate *priv = self->priv; priv->undo_redo_flag = TRUE; } gboolean nemo_file_undo_manager_pop_flag (void) { NemoFileUndoManager *self = get_singleton (); NemoFileUndoManagerPrivate *priv = self->priv; gboolean retval = FALSE; if (priv->undo_redo_flag) { retval = TRUE; } priv->undo_redo_flag = FALSE; return retval; } NemoFileUndoManager * nemo_file_undo_manager_get (void) { return get_singleton (); } nemo-4.4.2/libnemo-private/nemo-file-undo-manager.h000066400000000000000000000056761357442400300221730ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-undo-manager.h - Manages the undo/redo stack * * Copyright (C) 2007-2011 Amos Brocco * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Amos Brocco */ #ifndef __NEMO_FILE_UNDO_MANAGER_H__ #define __NEMO_FILE_UNDO_MANAGER_H__ #include #include #include #include #include typedef struct _NemoFileUndoManager NemoFileUndoManager; typedef struct _NemoFileUndoManagerClass NemoFileUndoManagerClass; typedef struct _NemoFileUndoManagerPrivate NemoFileUndoManagerPrivate; #define NEMO_TYPE_FILE_UNDO_MANAGER\ (nemo_file_undo_manager_get_type()) #define NEMO_FILE_UNDO_MANAGER(object)\ (G_TYPE_CHECK_INSTANCE_CAST((object), NEMO_TYPE_FILE_UNDO_MANAGER,\ NemoFileUndoManager)) #define NEMO_FILE_UNDO_MANAGER_CLASS(klass)\ (G_TYPE_CHECK_CLASS_CAST((klass), NEMO_TYPE_FILE_UNDO_MANAGER,\ NemoFileUndoManagerClass)) #define NEMO_IS_FILE_UNDO_MANAGER(object)\ (G_TYPE_CHECK_INSTANCE_TYPE((object), NEMO_TYPE_FILE_UNDO_MANAGER)) #define NEMO_IS_FILE_UNDO_MANAGER_CLASS(klass)\ (G_TYPE_CHECK_CLASS_TYPE((klass), NEMO_TYPE_FILE_UNDO_MANAGER)) #define NEMO_FILE_UNDO_MANAGER_GET_CLASS(object)\ (G_TYPE_INSTANCE_GET_CLASS((object), NEMO_TYPE_FILE_UNDO_MANAGER,\ NemoFileUndoManagerClass)) typedef enum { NEMO_FILE_UNDO_MANAGER_STATE_NONE, NEMO_FILE_UNDO_MANAGER_STATE_UNDO, NEMO_FILE_UNDO_MANAGER_STATE_REDO } NemoFileUndoManagerState; struct _NemoFileUndoManager { GObject parent_instance; /* < private > */ NemoFileUndoManagerPrivate* priv; }; struct _NemoFileUndoManagerClass { GObjectClass parent_class; }; GType nemo_file_undo_manager_get_type (void) G_GNUC_CONST; NemoFileUndoManager * nemo_file_undo_manager_get (void); void nemo_file_undo_manager_set_action (NemoFileUndoInfo *info); NemoFileUndoInfo *nemo_file_undo_manager_get_action (void); NemoFileUndoManagerState nemo_file_undo_manager_get_state (void); void nemo_file_undo_manager_undo (GtkWindow *parent_window); void nemo_file_undo_manager_redo (GtkWindow *parent_window); void nemo_file_undo_manager_push_flag (void); gboolean nemo_file_undo_manager_pop_flag (void); #endif /* __NEMO_FILE_UNDO_MANAGER_H__ */ nemo-4.4.2/libnemo-private/nemo-file-undo-operations.c000066400000000000000000001404471357442400300227330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-undo-operations.c - Manages undo/redo of file operations * * Copyright (C) 2007-2011 Amos Brocco * Copyright (C) 2010, 2012 Red Hat, Inc. * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Amos Brocco * Cosimo Cecchi * */ #include #include "nemo-file-undo-operations.h" #include #include #include "nemo-file-operations.h" #include "nemo-file.h" #include "nemo-file-undo-manager.h" /* Since we use g_get_current_time for setting "orig_trash_time" in the undo * info, there are situations where the difference between this value and the * real deletion time can differ enough to make the rounding a difference of 1 * second, failing the equality check. To make sure we avoid this, and to be * preventive, use 2 seconds epsilon. */ #define TRASH_TIME_EPSILON 2 #define HEAD(q) (g_queue_peek_head_link(q)) G_DEFINE_TYPE (NemoFileUndoInfo, nemo_file_undo_info, G_TYPE_OBJECT) enum { PROP_OP_TYPE = 1, PROP_ITEM_COUNT, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES] = { NULL, }; struct _NemoFileUndoInfoDetails { NemoFileUndoOp op_type; guint count; /* Number of items */ GSimpleAsyncResult *apply_async_result; gchar *undo_label; gchar *redo_label; gchar *undo_description; gchar *redo_description; }; /* description helpers */ static void nemo_file_undo_info_init (NemoFileUndoInfo *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_FILE_UNDO_INFO, NemoFileUndoInfoDetails); self->priv->apply_async_result = NULL; } static void nemo_file_undo_info_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoFileUndoInfo *self = NEMO_FILE_UNDO_INFO (object); switch (property_id) { case PROP_OP_TYPE: g_value_set_int (value, self->priv->op_type); break; case PROP_ITEM_COUNT: g_value_set_int (value, self->priv->count); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_file_undo_info_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoFileUndoInfo *self = NEMO_FILE_UNDO_INFO (object); switch (property_id) { case PROP_OP_TYPE: self->priv->op_type = g_value_get_int (value); break; case PROP_ITEM_COUNT: self->priv->count = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_file_redo_info_warn_redo (NemoFileUndoInfo *self, GtkWindow *parent_window) { g_critical ("Object %p of type %s does not implement redo_func!!", self, G_OBJECT_TYPE_NAME (self)); } static void nemo_file_undo_info_warn_undo (NemoFileUndoInfo *self, GtkWindow *parent_window) { g_critical ("Object %p of type %s does not implement undo_func!!", self, G_OBJECT_TYPE_NAME (self)); } static void nemo_file_undo_info_strings_func (NemoFileUndoInfo *self, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { if (undo_label != NULL) { *undo_label = g_strdup (_("Undo")); } if (undo_description != NULL) { *undo_description = g_strdup (_("Undo last action")); } if (redo_label != NULL) { *redo_label = g_strdup (_("Redo")); } if (redo_description != NULL) { *redo_description = g_strdup (_("Redo last undone action")); } } static void nemo_file_undo_info_finalize (GObject *obj) { NemoFileUndoInfo *self = NEMO_FILE_UNDO_INFO (obj); g_clear_object (&self->priv->apply_async_result); G_OBJECT_CLASS (nemo_file_undo_info_parent_class)->finalize (obj); } static void nemo_file_undo_info_class_init (NemoFileUndoInfoClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_file_undo_info_finalize; oclass->get_property = nemo_file_undo_info_get_property; oclass->set_property = nemo_file_undo_info_set_property; klass->undo_func = nemo_file_undo_info_warn_undo; klass->redo_func = nemo_file_redo_info_warn_redo; klass->strings_func = nemo_file_undo_info_strings_func; properties[PROP_OP_TYPE] = g_param_spec_int ("op-type", "Undo info op type", "Type of undo operation", 0, NEMO_FILE_UNDO_OP_NUM_TYPES - 1, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_ITEM_COUNT] = g_param_spec_int ("item-count", "Number of items", "Number of items", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_type_class_add_private (klass, sizeof (NemoFileUndoInfoDetails)); g_object_class_install_properties (oclass, N_PROPERTIES, properties); } static NemoFileUndoOp nemo_file_undo_info_get_op_type (NemoFileUndoInfo *self) { return self->priv->op_type; } static gint nemo_file_undo_info_get_item_count (NemoFileUndoInfo *self) { return self->priv->count; } void nemo_file_undo_info_apply_async (NemoFileUndoInfo *self, gboolean undo, GtkWindow *parent_window, GAsyncReadyCallback callback, gpointer user_data) { g_assert (self->priv->apply_async_result == NULL); self->priv->apply_async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, nemo_file_undo_info_apply_async); if (undo) { NEMO_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->undo_func (self, parent_window); } else { NEMO_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->redo_func (self, parent_window); } } typedef struct { gboolean success; gboolean user_cancel; } FileUndoInfoOpRes; static void file_undo_info_op_res_free (gpointer data) { g_slice_free (FileUndoInfoOpRes, data); } gboolean nemo_file_undo_info_apply_finish (NemoFileUndoInfo *self, GAsyncResult *res, gboolean *user_cancel, GError **error) { FileUndoInfoOpRes *op_res; if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { return FALSE; } op_res = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)); *user_cancel = op_res->user_cancel; return op_res->success; } void nemo_file_undo_info_get_strings (NemoFileUndoInfo *self, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { return NEMO_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->strings_func (self, undo_label, undo_description, redo_label, redo_description); } static void file_undo_info_complete_apply (NemoFileUndoInfo *self, gboolean success, gboolean user_cancel) { FileUndoInfoOpRes *op_res = g_slice_new0 (FileUndoInfoOpRes); op_res->user_cancel = user_cancel; op_res->success = success; g_simple_async_result_set_op_res_gpointer (self->priv->apply_async_result, op_res, file_undo_info_op_res_free); g_simple_async_result_complete_in_idle (self->priv->apply_async_result); g_clear_object (&self->priv->apply_async_result); } static void file_undo_info_transfer_callback (GHashTable * debuting_uris, gboolean success, gpointer user_data) { NemoFileUndoInfo *self = user_data; /* TODO: we need to forward the cancelled state from * the file operation to the file undo info object. */ file_undo_info_complete_apply (self, success, FALSE); } static void file_undo_info_operation_callback (NemoFile * file, GFile * result_location, GError * error, gpointer user_data) { NemoFileUndoInfo *self = user_data; file_undo_info_complete_apply (self, (error == NULL), g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)); } static void file_undo_info_delete_callback (GHashTable *debuting_uris, gboolean user_cancel, gpointer user_data) { NemoFileUndoInfo *self = user_data; file_undo_info_complete_apply (self, !user_cancel, user_cancel); } /* copy/move/duplicate/link/restore from trash */ G_DEFINE_TYPE (NemoFileUndoInfoExt, nemo_file_undo_info_ext, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoExtDetails { GFile *src_dir; GFile *dest_dir; GQueue *sources; /* Relative to src_dir */ GQueue *destinations; /* Relative to dest_dir */ }; static char * ext_get_first_target_short_name (NemoFileUndoInfoExt *self) { GFile *first_file; char *file_name = NULL; first_file = G_FILE (g_queue_peek_head (self->priv->destinations)); if (first_file != NULL) { file_name = g_file_get_basename (first_file); } return file_name; } static void ext_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoExt *self = NEMO_FILE_UNDO_INFO_EXT (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); gint count = nemo_file_undo_info_get_item_count (info); gchar *name = NULL, *source, *destination; source = g_file_get_path (self->priv->src_dir); destination = g_file_get_path (self->priv->dest_dir); if (count <= 1) { name = ext_get_first_target_short_name (self); } if (op_type == NEMO_FILE_UNDO_OP_MOVE) { if (count > 1) { *undo_description = g_strdup_printf (ngettext ("Move %d item back to '%s'", "Move %d items back to '%s'", count), count, source); *redo_description = g_strdup_printf (ngettext ("Move %d item to '%s'", "Move %d items to '%s'", count), count, destination); *undo_label = g_strdup_printf (ngettext ("_Undo Move %d item", "_Undo Move %d items", count), count); *redo_label = g_strdup_printf (ngettext ("_Redo Move %d item", "_Redo Move %d items", count), count); } else { *undo_description = g_strdup_printf (_("Move '%s' back to '%s'"), name, source); *redo_description = g_strdup_printf (_("Move '%s' to '%s'"), name, destination); *undo_label = g_strdup (_("_Undo Move")); *redo_label = g_strdup (_("_Redo Move")); } } else if (op_type == NEMO_FILE_UNDO_OP_RESTORE_FROM_TRASH) { *undo_label = g_strdup (_("_Undo Restore from Trash")); *redo_label = g_strdup (_("_Redo Restore from Trash")); if (count > 1) { *undo_description = g_strdup_printf (ngettext ("Move %d item back to trash", "Move %d items back to trash", count), count); *redo_description = g_strdup_printf (ngettext ("Restore %d item from trash", "Restore %d items from trash", count), count); } else { *undo_description = g_strdup_printf (_("Move '%s' back to trash"), name); *redo_description = g_strdup_printf (_("Restore '%s' from trash"), name); } } else if (op_type == NEMO_FILE_UNDO_OP_COPY) { if (count > 1) { *undo_description = g_strdup_printf (ngettext ("Delete %d copied item", "Delete %d copied items", count), count); *redo_description = g_strdup_printf (ngettext ("Copy %d item to '%s'", "Copy %d items to '%s'", count), count, destination); *undo_label = g_strdup_printf (ngettext ("_Undo Copy %d item", "_Undo Copy %d items", count), count); *redo_label = g_strdup_printf (ngettext ("_Redo Copy %d item", "_Redo Copy %d items", count), count); } else { *undo_description = g_strdup_printf (_("Delete '%s'"), name); *redo_description = g_strdup_printf (_("Copy '%s' to '%s'"), name, destination); *undo_label = g_strdup (_("_Undo Copy")); *redo_label = g_strdup (_("_Redo Copy")); } } else if (op_type == NEMO_FILE_UNDO_OP_DUPLICATE) { if (count > 1) { *undo_description = g_strdup_printf (ngettext ("Delete %d duplicated item", "Delete %d duplicated items", count), count); *redo_description = g_strdup_printf (ngettext ("Duplicate %d item in '%s'", "Duplicate %d items in '%s'", count), count, destination); *undo_label = g_strdup_printf (ngettext ("_Undo Duplicate %d item", "_Undo Duplicate %d items", count), count); *redo_label = g_strdup_printf (ngettext ("_Redo Duplicate %d item", "_Redo Duplicate %d items", count), count); } else { *undo_description = g_strdup_printf (_("Delete '%s'"), name); *redo_description = g_strdup_printf (_("Duplicate '%s' in '%s'"), name, destination); *undo_label = g_strdup (_("_Undo Duplicate")); *redo_label = g_strdup (_("_Redo Duplicate")); } } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_LINK) { if (count > 1) { *undo_description = g_strdup_printf (ngettext ("Delete links to %d item", "Delete links to %d items", count), count); *redo_description = g_strdup_printf (ngettext ("Create links to %d item", "Create links to %d items", count), count); } else { *undo_description = g_strdup_printf (_("Delete link to '%s'"), name); *redo_description = g_strdup_printf (_("Create link to '%s'"), name); *undo_label = g_strdup (_("_Undo Create Link")); *redo_label = g_strdup (_("_Redo Create Link")); } } else { g_assert_not_reached (); } g_free (name); g_free (source); g_free (destination); } static void ext_create_link_redo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_link (HEAD (self->priv->sources), NULL, self->priv->dest_dir, parent_window, file_undo_info_transfer_callback, self); } static void ext_duplicate_redo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_duplicate (HEAD (self->priv->sources), NULL, parent_window, file_undo_info_transfer_callback, self); } static void ext_copy_redo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_copy (HEAD (self->priv->sources), NULL, self->priv->dest_dir, parent_window, file_undo_info_transfer_callback, self); } static void ext_move_restore_redo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_move (HEAD (self->priv->sources), NULL, self->priv->dest_dir, parent_window, file_undo_info_transfer_callback, self); } static void ext_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoExt *self = NEMO_FILE_UNDO_INFO_EXT (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); if (op_type == NEMO_FILE_UNDO_OP_MOVE || op_type == NEMO_FILE_UNDO_OP_RESTORE_FROM_TRASH) { ext_move_restore_redo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_COPY) { ext_copy_redo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_DUPLICATE) { ext_duplicate_redo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_LINK) { ext_create_link_redo_func (self, parent_window); } else { g_assert_not_reached (); } } static void ext_restore_undo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_trash_or_delete (HEAD (self->priv->destinations), parent_window, file_undo_info_delete_callback, self); } static void ext_move_undo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { nemo_file_operations_move (HEAD (self->priv->destinations), NULL, self->priv->src_dir, parent_window, file_undo_info_transfer_callback, self); } static void ext_copy_duplicate_undo_func (NemoFileUndoInfoExt *self, GtkWindow *parent_window) { GList *files; files = g_list_copy (HEAD (self->priv->destinations)); files = g_list_reverse (files); /* Deleting must be done in reverse */ nemo_file_operations_delete (files, parent_window, file_undo_info_delete_callback, self); g_list_free (files); } static void ext_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoExt *self = NEMO_FILE_UNDO_INFO_EXT (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); if (op_type == NEMO_FILE_UNDO_OP_COPY || op_type == NEMO_FILE_UNDO_OP_DUPLICATE || op_type == NEMO_FILE_UNDO_OP_CREATE_LINK) { ext_copy_duplicate_undo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_MOVE) { ext_move_undo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_RESTORE_FROM_TRASH) { ext_restore_undo_func (self, parent_window); } else { g_assert_not_reached (); } } static void nemo_file_undo_info_ext_init (NemoFileUndoInfoExt *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_ext_get_type (), NemoFileUndoInfoExtDetails); } static void nemo_file_undo_info_ext_finalize (GObject *obj) { NemoFileUndoInfoExt *self = NEMO_FILE_UNDO_INFO_EXT (obj); if (self->priv->sources) { g_queue_free_full (self->priv->sources, g_object_unref); } if (self->priv->destinations) { g_queue_free_full (self->priv->destinations, g_object_unref); } g_clear_object (&self->priv->src_dir); g_clear_object (&self->priv->dest_dir); G_OBJECT_CLASS (nemo_file_undo_info_ext_parent_class)->finalize (obj); } static void nemo_file_undo_info_ext_class_init (NemoFileUndoInfoExtClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_ext_finalize; iclass->undo_func = ext_undo_func; iclass->redo_func = ext_redo_func; iclass->strings_func = ext_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoExtDetails)); } NemoFileUndoInfo * nemo_file_undo_info_ext_new (NemoFileUndoOp op_type, gint item_count, GFile *src_dir, GFile *target_dir) { NemoFileUndoInfoExt *retval; retval = g_object_new (NEMO_TYPE_FILE_UNDO_INFO_EXT, "op-type", op_type, "item-count", item_count, NULL); retval->priv->src_dir = g_object_ref (src_dir); retval->priv->dest_dir = g_object_ref (target_dir); retval->priv->destinations = g_queue_new (); retval->priv->sources = g_queue_new (); return NEMO_FILE_UNDO_INFO (retval); } void nemo_file_undo_info_ext_add_origin_target_pair (NemoFileUndoInfoExt *self, GFile *origin, GFile *target) { g_queue_push_tail (self->priv->sources, g_object_ref (origin)); g_queue_push_tail (self->priv->destinations, g_object_ref (target)); } /* create new file/folder */ G_DEFINE_TYPE (NemoFileUndoInfoCreate, nemo_file_undo_info_create, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoCreateDetails { char *template; GFile *target_file; gint length; }; static void create_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoCreate *self = NEMO_FILE_UNDO_INFO_CREATE (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); char *name; name = g_file_get_parse_name (self->priv->target_file); *undo_description = g_strdup_printf (_("Delete '%s'"), name); if (op_type == NEMO_FILE_UNDO_OP_CREATE_EMPTY_FILE) { *redo_description = g_strdup_printf (_("Create an empty file '%s'"), name); *undo_label = g_strdup (_("_Undo Create Empty File")); *redo_label = g_strdup (_("_Redo Create Empty File")); } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_FOLDER) { *redo_description = g_strdup_printf (_("Create a new folder '%s'"), name); *undo_label = g_strdup (_("_Undo Create Folder")); *redo_label = g_strdup (_("_Redo Create Folder")); } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE) { *redo_description = g_strdup_printf (_("Create new file '%s' from template "), name); *undo_label = g_strdup (_("_Undo Create from Template")); *redo_label = g_strdup (_("_Redo Create from Template")); } else { g_assert_not_reached (); } g_free (name); } static void create_callback (GFile * new_file, gboolean success, gpointer callback_data) { file_undo_info_transfer_callback (NULL, success, callback_data); } static void create_from_template_redo_func (NemoFileUndoInfoCreate *self, GtkWindow *parent_window) { GFile *parent; gchar *parent_uri, *new_name; parent = g_file_get_parent (self->priv->target_file); parent_uri = g_file_get_uri (parent); new_name = g_file_get_parse_name (self->priv->target_file); nemo_file_operations_new_file_from_template (NULL, NULL, parent_uri, new_name, self->priv->template, create_callback, self); g_free (parent_uri); g_free (new_name); g_object_unref (parent); } static void create_folder_redo_func (NemoFileUndoInfoCreate *self, GtkWindow *parent_window) { GFile *parent; gchar *parent_uri; parent = g_file_get_parent (self->priv->target_file); parent_uri = g_file_get_uri (parent); nemo_file_operations_new_folder (NULL, NULL, parent_uri, create_callback, self); g_free (parent_uri); g_object_unref (parent); } static void create_empty_redo_func (NemoFileUndoInfoCreate *self, GtkWindow *parent_window) { GFile *parent; gchar *parent_uri; gchar *new_name; parent = g_file_get_parent (self->priv->target_file); parent_uri = g_file_get_uri (parent); new_name = g_file_get_parse_name (self->priv->target_file); nemo_file_operations_new_file (NULL, NULL, parent_uri, new_name, self->priv->template, self->priv->length, create_callback, self); g_free (parent_uri); g_free (new_name); g_object_unref (parent); } static void create_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoCreate *self = NEMO_FILE_UNDO_INFO_CREATE (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); if (op_type == NEMO_FILE_UNDO_OP_CREATE_EMPTY_FILE) { create_empty_redo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_FOLDER) { create_folder_redo_func (self, parent_window); } else if (op_type == NEMO_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE) { create_from_template_redo_func (self, parent_window); } else { g_assert_not_reached (); } } static void create_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoCreate *self = NEMO_FILE_UNDO_INFO_CREATE (info); GList *files = NULL; files = g_list_append (files, g_object_ref (self->priv->target_file)); nemo_file_operations_delete (files, parent_window, file_undo_info_delete_callback, self); g_list_free_full (files, g_object_unref); } static void nemo_file_undo_info_create_init (NemoFileUndoInfoCreate *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_create_get_type (), NemoFileUndoInfoCreateDetails); } static void nemo_file_undo_info_create_finalize (GObject *obj) { NemoFileUndoInfoCreate *self = NEMO_FILE_UNDO_INFO_CREATE (obj); g_clear_object (&self->priv->target_file); g_free (self->priv->template); G_OBJECT_CLASS (nemo_file_undo_info_create_parent_class)->finalize (obj); } static void nemo_file_undo_info_create_class_init (NemoFileUndoInfoCreateClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_create_finalize; iclass->undo_func = create_undo_func; iclass->redo_func = create_redo_func; iclass->strings_func = create_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoCreateDetails)); } NemoFileUndoInfo * nemo_file_undo_info_create_new (NemoFileUndoOp op_type) { return g_object_new (NEMO_TYPE_FILE_UNDO_INFO_CREATE, "op-type", op_type, "item-count", 1, NULL); } void nemo_file_undo_info_create_set_data (NemoFileUndoInfoCreate *self, GFile *file, const char *template, gint length) { self->priv->target_file = g_object_ref (file); self->priv->template = g_strdup (template); self->priv->length = length; } /* rename */ G_DEFINE_TYPE (NemoFileUndoInfoRename, nemo_file_undo_info_rename, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoRenameDetails { GFile *old_file; GFile *new_file; gchar *old_display_name; gchar *new_display_name; }; static void rename_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoRename *self = NEMO_FILE_UNDO_INFO_RENAME (info); gchar *new_name, *old_name; new_name = g_file_get_parse_name (self->priv->new_file); old_name = g_file_get_parse_name (self->priv->old_file); *undo_description = g_strdup_printf (_("Rename '%s' as '%s'"), new_name, old_name); *redo_description = g_strdup_printf (_("Rename '%s' as '%s'"), old_name, new_name); *undo_label = g_strdup (_("_Undo Rename")); *redo_label = g_strdup (_("_Redo Rename")); g_free (old_name); g_free (new_name); } static void rename_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoRename *self = NEMO_FILE_UNDO_INFO_RENAME (info); NemoFile *file; file = nemo_file_get (self->priv->old_file); nemo_file_rename (file, self->priv->new_display_name, file_undo_info_operation_callback, self); nemo_file_unref (file); } static void rename_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoRename *self = NEMO_FILE_UNDO_INFO_RENAME (info); NemoFile *file; file = nemo_file_get (self->priv->new_file); nemo_file_rename (file, self->priv->old_display_name, file_undo_info_operation_callback, self); nemo_file_unref (file); } static void nemo_file_undo_info_rename_init (NemoFileUndoInfoRename *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_rename_get_type (), NemoFileUndoInfoRenameDetails); } static void nemo_file_undo_info_rename_finalize (GObject *obj) { NemoFileUndoInfoRename *self = NEMO_FILE_UNDO_INFO_RENAME (obj); g_clear_object (&self->priv->old_file); g_clear_object (&self->priv->new_file); g_free (self->priv->old_display_name); g_free (self->priv->new_display_name); G_OBJECT_CLASS (nemo_file_undo_info_rename_parent_class)->finalize (obj); } static void nemo_file_undo_info_rename_class_init (NemoFileUndoInfoRenameClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_rename_finalize; iclass->undo_func = rename_undo_func; iclass->redo_func = rename_redo_func; iclass->strings_func = rename_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoRenameDetails)); } NemoFileUndoInfo * nemo_file_undo_info_rename_new (void) { return g_object_new (NEMO_TYPE_FILE_UNDO_INFO_RENAME, "op-type", NEMO_FILE_UNDO_OP_RENAME, "item-count", 1, NULL); } void nemo_file_undo_info_rename_set_data_pre (NemoFileUndoInfoRename *self, GFile *old_file, gchar *old_display_name, gchar *new_display_name) { self->priv->old_file = g_object_ref (old_file); self->priv->old_display_name = g_strdup (old_display_name); self->priv->new_display_name = g_strdup (new_display_name); } void nemo_file_undo_info_rename_set_data_post (NemoFileUndoInfoRename *self, GFile *new_file) { self->priv->new_file = g_object_ref (new_file); } /* trash */ G_DEFINE_TYPE (NemoFileUndoInfoTrash, nemo_file_undo_info_trash, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoTrashDetails { GHashTable *trashed; }; static void trash_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (info); gint count = g_hash_table_size (self->priv->trashed); if (count != 1) { *undo_description = g_strdup_printf (ngettext ("Restore %d item from trash", "Restore %d items from trash", count), count); *redo_description = g_strdup_printf (ngettext ("Move %d item to trash", "Move %d items to trash", count), count); } else { GList *keys; char *name, *orig_path; GFile *file; keys = g_hash_table_get_keys (self->priv->trashed); file = keys->data; name = g_file_get_basename (file); orig_path = g_file_get_path (file); *undo_description = g_strdup_printf (_("Restore '%s' to '%s'"), name, orig_path); g_free (name); g_free (orig_path); g_list_free (keys); name = g_file_get_parse_name (file); *redo_description = g_strdup_printf (_("Move '%s' to trash"), name); g_free (name); *undo_label = g_strdup (_("_Undo Trash")); *redo_label = g_strdup (_("_Redo Trash")); } } static void trash_redo_func_callback (GHashTable *debuting_uris, gboolean user_cancel, gpointer user_data) { NemoFileUndoInfoTrash *self = user_data; GHashTable *new_trashed_files; GTimeVal current_time; gsize updated_trash_time; GFile *file; GList *keys, *l; if (!user_cancel) { new_trashed_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL); keys = g_hash_table_get_keys (self->priv->trashed); g_get_current_time (¤t_time); updated_trash_time = current_time.tv_sec; for (l = keys; l != NULL; l = l->next) { file = l->data; g_hash_table_insert (new_trashed_files, g_object_ref (file), GSIZE_TO_POINTER (updated_trash_time)); } g_list_free (keys); g_hash_table_destroy (self->priv->trashed); self->priv->trashed = new_trashed_files; } file_undo_info_delete_callback (debuting_uris, user_cancel, user_data); } static void trash_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (info); if (g_hash_table_size (self->priv->trashed) > 0) { GList *locations; locations = g_hash_table_get_keys (self->priv->trashed); nemo_file_operations_trash_or_delete (locations, parent_window, trash_redo_func_callback, self); g_list_free (locations); } } static GHashTable * trash_retrieve_files_to_restore_finish (NemoFileUndoInfoTrash *self, GAsyncResult *res, GError **error) { GHashTable *retval = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)); if (retval == NULL) { g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } return retval; } static void trash_retrieve_files_to_restore_thread (GSimpleAsyncResult *res, GObject *object, GCancellable *cancellable) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (object); GFileEnumerator *enumerator; GHashTable *to_restore; GFile *trash; GError *error = NULL; to_restore = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref); trash = g_file_new_for_uri ("trash:///"); enumerator = g_file_enumerate_children (trash, G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_TRASH_DELETION_DATE"," G_FILE_ATTRIBUTE_TRASH_ORIG_PATH, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); if (enumerator) { GFileInfo *info; gpointer lookupvalue; GFile *item; GTimeVal timeval; glong trash_time, orig_trash_time; const char *origpath; GFile *origfile; const char *time_string; while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL) { /* Retrieve the original file uri */ origpath = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH); origfile = g_file_new_for_path (origpath); lookupvalue = g_hash_table_lookup (self->priv->trashed, origfile); if (lookupvalue) { orig_trash_time = GPOINTER_TO_SIZE (lookupvalue); time_string = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_TRASH_DELETION_DATE); if (time_string != NULL) { g_time_val_from_iso8601 (time_string, &timeval); trash_time = timeval.tv_sec; } else { trash_time = 0; } if (ABS (orig_trash_time - trash_time) <= TRASH_TIME_EPSILON) { /* File in the trash */ item = g_file_get_child (trash, g_file_info_get_name (info)); g_hash_table_insert (to_restore, item, g_object_ref (origfile)); } } g_object_unref (origfile); } g_file_enumerator_close (enumerator, FALSE, NULL); g_object_unref (enumerator); } g_object_unref (trash); if (error != NULL) { g_simple_async_result_take_error (res, error); g_hash_table_destroy (to_restore); } else { g_simple_async_result_set_op_res_gpointer (res, to_restore, NULL); } } static void trash_retrieve_files_to_restore_async (NemoFileUndoInfoTrash *self, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *async_op; async_op = g_simple_async_result_new (G_OBJECT (self), callback, user_data, trash_retrieve_files_to_restore_async); g_simple_async_result_run_in_thread (async_op, trash_retrieve_files_to_restore_thread, G_PRIORITY_DEFAULT, NULL); g_object_unref (async_op); } static void trash_retrieve_files_ready (GObject *source, GAsyncResult *res, gpointer user_data) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (source); GHashTable *files_to_restore; GError *error = NULL; files_to_restore = trash_retrieve_files_to_restore_finish (self, res, &error); if (error == NULL && g_hash_table_size (files_to_restore) > 0) { GList *gfiles_in_trash, *l; GFile *item; GFile *dest; gfiles_in_trash = g_hash_table_get_keys (files_to_restore); for (l = gfiles_in_trash; l != NULL; l = l->next) { item = l->data; dest = g_hash_table_lookup (files_to_restore, item); g_file_move (item, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL, NULL, NULL); } g_list_free (gfiles_in_trash); /* Here we must do what's necessary for the callback */ file_undo_info_transfer_callback (NULL, (error == NULL), self); } else { file_undo_info_transfer_callback (NULL, FALSE, self); } if (files_to_restore != NULL) { g_hash_table_destroy (files_to_restore); } g_clear_error (&error); } static void trash_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (info); /* Internally managed op, pop flag. */ nemo_file_undo_manager_pop_flag (); trash_retrieve_files_to_restore_async (self, trash_retrieve_files_ready, NULL); } static void nemo_file_undo_info_trash_init (NemoFileUndoInfoTrash *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_trash_get_type (), NemoFileUndoInfoTrashDetails); self->priv->trashed = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL); } static void nemo_file_undo_info_trash_finalize (GObject *obj) { NemoFileUndoInfoTrash *self = NEMO_FILE_UNDO_INFO_TRASH (obj); g_hash_table_destroy (self->priv->trashed); G_OBJECT_CLASS (nemo_file_undo_info_trash_parent_class)->finalize (obj); } static void nemo_file_undo_info_trash_class_init (NemoFileUndoInfoTrashClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_trash_finalize; iclass->undo_func = trash_undo_func; iclass->redo_func = trash_redo_func; iclass->strings_func = trash_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoTrashDetails)); } NemoFileUndoInfo * nemo_file_undo_info_trash_new (gint item_count) { return g_object_new (NEMO_TYPE_FILE_UNDO_INFO_TRASH, "op-type", NEMO_FILE_UNDO_OP_MOVE_TO_TRASH, "item-count", item_count, NULL); } void nemo_file_undo_info_trash_add_file (NemoFileUndoInfoTrash *self, GFile *file) { GTimeVal current_time; gsize orig_trash_time; g_get_current_time (¤t_time); orig_trash_time = current_time.tv_sec; g_hash_table_insert (self->priv->trashed, g_object_ref (file), GSIZE_TO_POINTER (orig_trash_time)); } /* recursive permissions */ G_DEFINE_TYPE (NemoFileUndoInfoRecPermissions, nemo_file_undo_info_rec_permissions, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoRecPermissionsDetails { GFile *dest_dir; GHashTable *original_permissions; guint32 dir_mask; guint32 dir_permissions; guint32 file_mask; guint32 file_permissions; }; static void rec_permissions_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoRecPermissions *self = NEMO_FILE_UNDO_INFO_REC_PERMISSIONS (info); char *name; name = g_file_get_path (self->priv->dest_dir); *undo_description = g_strdup_printf (_("Restore original permissions of items enclosed in '%s'"), name); *redo_description = g_strdup_printf (_("Set permissions of items enclosed in '%s'"), name); *undo_label = g_strdup (_("_Undo Change Permissions")); *redo_label = g_strdup (_("_Redo Change Permissions")); g_free (name); } static void rec_permissions_callback (gboolean success, gpointer callback_data) { file_undo_info_transfer_callback (NULL, success, callback_data); } static void rec_permissions_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoRecPermissions *self = NEMO_FILE_UNDO_INFO_REC_PERMISSIONS (info); gchar *parent_uri; parent_uri = g_file_get_uri (self->priv->dest_dir); nemo_file_set_permissions_recursive (parent_uri, self->priv->file_permissions, self->priv->file_mask, self->priv->dir_permissions, self->priv->dir_mask, rec_permissions_callback, self); g_free (parent_uri); } static void rec_permissions_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoRecPermissions *self = NEMO_FILE_UNDO_INFO_REC_PERMISSIONS (info); /* Internally managed op, pop flag. */ /* TODO: why? */ nemo_file_undo_manager_pop_flag (); if (g_hash_table_size (self->priv->original_permissions) > 0) { GList *gfiles_list; guint32 perm; GList *l; GFile *dest; char *item; gfiles_list = g_hash_table_get_keys (self->priv->original_permissions); for (l = gfiles_list; l != NULL; l = l->next) { item = l->data; perm = GPOINTER_TO_UINT (g_hash_table_lookup (self->priv->original_permissions, item)); dest = g_file_new_for_uri (item); g_file_set_attribute_uint32 (dest, G_FILE_ATTRIBUTE_UNIX_MODE, perm, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); g_object_unref (dest); } g_list_free (gfiles_list); /* Here we must do what's necessary for the callback */ file_undo_info_transfer_callback (NULL, TRUE, self); } } static void nemo_file_undo_info_rec_permissions_init (NemoFileUndoInfoRecPermissions *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_rec_permissions_get_type (), NemoFileUndoInfoRecPermissionsDetails); self->priv->original_permissions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static void nemo_file_undo_info_rec_permissions_finalize (GObject *obj) { NemoFileUndoInfoRecPermissions *self = NEMO_FILE_UNDO_INFO_REC_PERMISSIONS (obj); g_hash_table_destroy (self->priv->original_permissions); g_clear_object (&self->priv->dest_dir); G_OBJECT_CLASS (nemo_file_undo_info_rec_permissions_parent_class)->finalize (obj); } static void nemo_file_undo_info_rec_permissions_class_init (NemoFileUndoInfoRecPermissionsClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_rec_permissions_finalize; iclass->undo_func = rec_permissions_undo_func; iclass->redo_func = rec_permissions_redo_func; iclass->strings_func = rec_permissions_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoRecPermissionsDetails)); } NemoFileUndoInfo * nemo_file_undo_info_rec_permissions_new (GFile *dest, guint32 file_permissions, guint32 file_mask, guint32 dir_permissions, guint32 dir_mask) { NemoFileUndoInfoRecPermissions *retval; retval = g_object_new (NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS, "op-type", NEMO_FILE_UNDO_OP_RECURSIVE_SET_PERMISSIONS, "item-count", 1, NULL); retval->priv->dest_dir = g_object_ref (dest); retval->priv->file_permissions = file_permissions; retval->priv->file_mask = file_mask; retval->priv->dir_permissions = dir_permissions; retval->priv->dir_mask = dir_mask; return NEMO_FILE_UNDO_INFO (retval); } void nemo_file_undo_info_rec_permissions_add_file (NemoFileUndoInfoRecPermissions *self, GFile *file, guint32 permission) { gchar *original_uri = g_file_get_uri (file); g_hash_table_insert (self->priv->original_permissions, original_uri, GUINT_TO_POINTER (permission)); } /* single file change permissions */ G_DEFINE_TYPE (NemoFileUndoInfoPermissions, nemo_file_undo_info_permissions, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoPermissionsDetails { GFile *target_file; guint32 current_permissions; guint32 new_permissions; }; static void permissions_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoPermissions *self = NEMO_FILE_UNDO_INFO_PERMISSIONS (info); gchar *name; name = g_file_get_parse_name (self->priv->target_file); *undo_description = g_strdup_printf (_("Restore original permissions of '%s'"), name); *redo_description = g_strdup_printf (_("Set permissions of '%s'"), name); *undo_label = g_strdup (_("_Undo Change Permissions")); *redo_label = g_strdup (_("_Redo Change Permissions")); g_free (name); } static void permissions_real_func (NemoFileUndoInfoPermissions *self, guint32 permissions) { NemoFile *file; file = nemo_file_get (self->priv->target_file); nemo_file_set_permissions (file, permissions, file_undo_info_operation_callback, self); nemo_file_unref (file); } static void permissions_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoPermissions *self = NEMO_FILE_UNDO_INFO_PERMISSIONS (info); permissions_real_func (self, self->priv->new_permissions); } static void permissions_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoPermissions *self = NEMO_FILE_UNDO_INFO_PERMISSIONS (info); permissions_real_func (self, self->priv->current_permissions); } static void nemo_file_undo_info_permissions_init (NemoFileUndoInfoPermissions *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_permissions_get_type (), NemoFileUndoInfoPermissionsDetails); } static void nemo_file_undo_info_permissions_finalize (GObject *obj) { NemoFileUndoInfoPermissions *self = NEMO_FILE_UNDO_INFO_PERMISSIONS (obj); g_clear_object (&self->priv->target_file); G_OBJECT_CLASS (nemo_file_undo_info_permissions_parent_class)->finalize (obj); } static void nemo_file_undo_info_permissions_class_init (NemoFileUndoInfoPermissionsClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_permissions_finalize; iclass->undo_func = permissions_undo_func; iclass->redo_func = permissions_redo_func; iclass->strings_func = permissions_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoPermissionsDetails)); } NemoFileUndoInfo * nemo_file_undo_info_permissions_new (GFile *file, guint32 current_permissions, guint32 new_permissions) { NemoFileUndoInfoPermissions *retval; retval = g_object_new (NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS, "op-type", NEMO_FILE_UNDO_OP_SET_PERMISSIONS, "item-count", 1, NULL); retval->priv->target_file = g_object_ref (file); retval->priv->current_permissions = current_permissions; retval->priv->new_permissions = new_permissions; return NEMO_FILE_UNDO_INFO (retval); } /* group and owner change */ G_DEFINE_TYPE (NemoFileUndoInfoOwnership, nemo_file_undo_info_ownership, NEMO_TYPE_FILE_UNDO_INFO) struct _NemoFileUndoInfoOwnershipDetails { GFile *target_file; char *original_ownership; char *new_ownership; }; static void ownership_strings_func (NemoFileUndoInfo *info, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description) { NemoFileUndoInfoOwnership *self = NEMO_FILE_UNDO_INFO_OWNERSHIP (info); NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (info); gchar *name; name = g_file_get_parse_name (self->priv->target_file); if (op_type == NEMO_FILE_UNDO_OP_CHANGE_GROUP) { *undo_description = g_strdup_printf (_("Restore group of '%s' to '%s'"), name, self->priv->original_ownership); *redo_description = g_strdup_printf (_("Set group of '%s' to '%s'"), name, self->priv->new_ownership); *undo_label = g_strdup (_("_Undo Change Group")); *redo_label = g_strdup (_("_Redo Change Group")); } else if (op_type == NEMO_FILE_UNDO_OP_CHANGE_OWNER) { *undo_description = g_strdup_printf (_("Restore owner of '%s' to '%s'"), name, self->priv->original_ownership); *redo_description = g_strdup_printf (_("Set owner of '%s' to '%s'"), name, self->priv->new_ownership); *undo_label = g_strdup (_("_Undo Change Owner")); *redo_label = g_strdup (_("_Redo Change Owner")); } g_free (name); } static void ownership_real_func (NemoFileUndoInfoOwnership *self, const gchar *ownership) { NemoFileUndoOp op_type = nemo_file_undo_info_get_op_type (NEMO_FILE_UNDO_INFO (self)); NemoFile *file; file = nemo_file_get (self->priv->target_file); if (op_type == NEMO_FILE_UNDO_OP_CHANGE_OWNER) { nemo_file_set_owner (file, ownership, file_undo_info_operation_callback, self); } else if (op_type == NEMO_FILE_UNDO_OP_CHANGE_GROUP) { nemo_file_set_group (file, ownership, file_undo_info_operation_callback, self); } nemo_file_unref (file); } static void ownership_redo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoOwnership *self = NEMO_FILE_UNDO_INFO_OWNERSHIP (info); ownership_real_func (self, self->priv->new_ownership); } static void ownership_undo_func (NemoFileUndoInfo *info, GtkWindow *parent_window) { NemoFileUndoInfoOwnership *self = NEMO_FILE_UNDO_INFO_OWNERSHIP (info); ownership_real_func (self, self->priv->original_ownership); } static void nemo_file_undo_info_ownership_init (NemoFileUndoInfoOwnership *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nemo_file_undo_info_ownership_get_type (), NemoFileUndoInfoOwnershipDetails); } static void nemo_file_undo_info_ownership_finalize (GObject *obj) { NemoFileUndoInfoOwnership *self = NEMO_FILE_UNDO_INFO_OWNERSHIP (obj); g_clear_object (&self->priv->target_file); g_free (self->priv->original_ownership); g_free (self->priv->new_ownership); G_OBJECT_CLASS (nemo_file_undo_info_ownership_parent_class)->finalize (obj); } static void nemo_file_undo_info_ownership_class_init (NemoFileUndoInfoOwnershipClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); NemoFileUndoInfoClass *iclass = NEMO_FILE_UNDO_INFO_CLASS (klass); oclass->finalize = nemo_file_undo_info_ownership_finalize; iclass->undo_func = ownership_undo_func; iclass->redo_func = ownership_redo_func; iclass->strings_func = ownership_strings_func; g_type_class_add_private (klass, sizeof (NemoFileUndoInfoOwnershipDetails)); } NemoFileUndoInfo * nemo_file_undo_info_ownership_new (NemoFileUndoOp op_type, GFile *file, const char *current_data, const char *new_data) { NemoFileUndoInfoOwnership *retval; retval = g_object_new (NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP, "item-count", 1, "op-type", op_type, NULL); retval->priv->target_file = g_object_ref (file); retval->priv->original_ownership = g_strdup (current_data); retval->priv->new_ownership = g_strdup (new_data); return NEMO_FILE_UNDO_INFO (retval); } nemo-4.4.2/libnemo-private/nemo-file-undo-operations.h000066400000000000000000000344411357442400300227340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-undo-operations.h - Manages undo/redo of file operations * * Copyright (C) 2007-2011 Amos Brocco * Copyright (C) 2010 Red Hat, Inc. * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Amos Brocco * Cosimo Cecchi * */ #ifndef __NEMO_FILE_UNDO_OPERATIONS_H__ #define __NEMO_FILE_UNDO_OPERATIONS_H__ #include #include typedef enum { NEMO_FILE_UNDO_OP_COPY, NEMO_FILE_UNDO_OP_DUPLICATE, NEMO_FILE_UNDO_OP_MOVE, NEMO_FILE_UNDO_OP_RENAME, NEMO_FILE_UNDO_OP_CREATE_EMPTY_FILE, NEMO_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE, NEMO_FILE_UNDO_OP_CREATE_FOLDER, NEMO_FILE_UNDO_OP_MOVE_TO_TRASH, NEMO_FILE_UNDO_OP_RESTORE_FROM_TRASH, NEMO_FILE_UNDO_OP_CREATE_LINK, NEMO_FILE_UNDO_OP_RECURSIVE_SET_PERMISSIONS, NEMO_FILE_UNDO_OP_SET_PERMISSIONS, NEMO_FILE_UNDO_OP_CHANGE_GROUP, NEMO_FILE_UNDO_OP_CHANGE_OWNER, NEMO_FILE_UNDO_OP_NUM_TYPES, } NemoFileUndoOp; #define NEMO_TYPE_FILE_UNDO_INFO (nemo_file_undo_info_get_type ()) #define NEMO_FILE_UNDO_INFO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO, NemoFileUndoInfo)) #define NEMO_FILE_UNDO_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO, NemoFileUndoInfoClass)) #define NEMO_IS_FILE_UNDO_INFO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO)) #define NEMO_IS_FILE_UNDO_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO)) #define NEMO_FILE_UNDO_INFO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO, NemoFileUndoInfoClass)) typedef struct _NemoFileUndoInfo NemoFileUndoInfo; typedef struct _NemoFileUndoInfoClass NemoFileUndoInfoClass; typedef struct _NemoFileUndoInfoDetails NemoFileUndoInfoDetails; struct _NemoFileUndoInfo { GObject parent; NemoFileUndoInfoDetails *priv; }; struct _NemoFileUndoInfoClass { GObjectClass parent_class; void (* undo_func) (NemoFileUndoInfo *self, GtkWindow *parent_window); void (* redo_func) (NemoFileUndoInfo *self, GtkWindow *parent_window); void (* strings_func) (NemoFileUndoInfo *self, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description); }; GType nemo_file_undo_info_get_type (void) G_GNUC_CONST; void nemo_file_undo_info_apply_async (NemoFileUndoInfo *self, gboolean undo, GtkWindow *parent_window, GAsyncReadyCallback callback, gpointer user_data); gboolean nemo_file_undo_info_apply_finish (NemoFileUndoInfo *self, GAsyncResult *res, gboolean *user_cancel, GError **error); void nemo_file_undo_info_get_strings (NemoFileUndoInfo *self, gchar **undo_label, gchar **undo_description, gchar **redo_label, gchar **redo_description); /* copy/move/duplicate/link/restore from trash */ #define NEMO_TYPE_FILE_UNDO_INFO_EXT (nemo_file_undo_info_ext_get_type ()) #define NEMO_FILE_UNDO_INFO_EXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_EXT, NemoFileUndoInfoExt)) #define NEMO_FILE_UNDO_INFO_EXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_EXT, NemoFileUndoInfoExtClass)) #define NEMO_IS_FILE_UNDO_INFO_EXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_EXT)) #define NEMO_IS_FILE_UNDO_INFO_EXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_EXT)) #define NEMO_FILE_UNDO_INFO_EXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_EXT, NemoFileUndoInfoExtClass)) typedef struct _NemoFileUndoInfoExt NemoFileUndoInfoExt; typedef struct _NemoFileUndoInfoExtClass NemoFileUndoInfoExtClass; typedef struct _NemoFileUndoInfoExtDetails NemoFileUndoInfoExtDetails; struct _NemoFileUndoInfoExt { NemoFileUndoInfo parent; NemoFileUndoInfoExtDetails *priv; }; struct _NemoFileUndoInfoExtClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_ext_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_ext_new (NemoFileUndoOp op_type, gint item_count, GFile *src_dir, GFile *target_dir); void nemo_file_undo_info_ext_add_origin_target_pair (NemoFileUndoInfoExt *self, GFile *origin, GFile *target); /* create new file/folder */ #define NEMO_TYPE_FILE_UNDO_INFO_CREATE (nemo_file_undo_info_create_get_type ()) #define NEMO_FILE_UNDO_INFO_CREATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_CREATE, NemoFileUndoInfoCreate)) #define NEMO_FILE_UNDO_INFO_CREATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_CREATE, NemoFileUndoInfoCreateClass)) #define NEMO_IS_FILE_UNDO_INFO_CREATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_CREATE)) #define NEMO_IS_FILE_UNDO_INFO_CREATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_CREATE)) #define NEMO_FILE_UNDO_INFO_CREATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_CREATE, NemoFileUndoInfoCreateClass)) typedef struct _NemoFileUndoInfoCreate NemoFileUndoInfoCreate; typedef struct _NemoFileUndoInfoCreateClass NemoFileUndoInfoCreateClass; typedef struct _NemoFileUndoInfoCreateDetails NemoFileUndoInfoCreateDetails; struct _NemoFileUndoInfoCreate { NemoFileUndoInfo parent; NemoFileUndoInfoCreateDetails *priv; }; struct _NemoFileUndoInfoCreateClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_create_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_create_new (NemoFileUndoOp op_type); void nemo_file_undo_info_create_set_data (NemoFileUndoInfoCreate *self, GFile *file, const char *template, gint length); /* rename */ #define NEMO_TYPE_FILE_UNDO_INFO_RENAME (nemo_file_undo_info_rename_get_type ()) #define NEMO_FILE_UNDO_INFO_RENAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_RENAME, NemoFileUndoInfoRename)) #define NEMO_FILE_UNDO_INFO_RENAME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_RENAME, NemoFileUndoInfoRenameClass)) #define NEMO_IS_FILE_UNDO_INFO_RENAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_RENAME)) #define NEMO_IS_FILE_UNDO_INFO_RENAME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_RENAME)) #define NEMO_FILE_UNDO_INFO_RENAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_RENAME, NemoFileUndoInfoRenameClass)) typedef struct _NemoFileUndoInfoRename NemoFileUndoInfoRename; typedef struct _NemoFileUndoInfoRenameClass NemoFileUndoInfoRenameClass; typedef struct _NemoFileUndoInfoRenameDetails NemoFileUndoInfoRenameDetails; struct _NemoFileUndoInfoRename { NemoFileUndoInfo parent; NemoFileUndoInfoRenameDetails *priv; }; struct _NemoFileUndoInfoRenameClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_rename_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_rename_new (void); void nemo_file_undo_info_rename_set_data_pre (NemoFileUndoInfoRename *self, GFile *old_file, gchar *old_display_name, gchar *new_display_name); void nemo_file_undo_info_rename_set_data_post (NemoFileUndoInfoRename *self, GFile *new_file); /* trash */ #define NEMO_TYPE_FILE_UNDO_INFO_TRASH (nemo_file_undo_info_trash_get_type ()) #define NEMO_FILE_UNDO_INFO_TRASH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_TRASH, NemoFileUndoInfoTrash)) #define NEMO_FILE_UNDO_INFO_TRASH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_TRASH, NemoFileUndoInfoTrashClass)) #define NEMO_IS_FILE_UNDO_INFO_TRASH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_TRASH)) #define NEMO_IS_FILE_UNDO_INFO_TRASH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_TRASH)) #define NEMO_FILE_UNDO_INFO_TRASH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_TRASH, NemoFileUndoInfoTrashClass)) typedef struct _NemoFileUndoInfoTrash NemoFileUndoInfoTrash; typedef struct _NemoFileUndoInfoTrashClass NemoFileUndoInfoTrashClass; typedef struct _NemoFileUndoInfoTrashDetails NemoFileUndoInfoTrashDetails; struct _NemoFileUndoInfoTrash { NemoFileUndoInfo parent; NemoFileUndoInfoTrashDetails *priv; }; struct _NemoFileUndoInfoTrashClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_trash_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_trash_new (gint item_count); void nemo_file_undo_info_trash_add_file (NemoFileUndoInfoTrash *self, GFile *file); /* recursive permissions */ #define NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS (nemo_file_undo_info_rec_permissions_get_type ()) #define NEMO_FILE_UNDO_INFO_REC_PERMISSIONS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS, NemoFileUndoInfoRecPermissions)) #define NEMO_FILE_UNDO_INFO_REC_PERMISSIONS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS, NemoFileUndoInfoRecPermissionsClass)) #define NEMO_IS_FILE_UNDO_INFO_REC_PERMISSIONS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS)) #define NEMO_IS_FILE_UNDO_INFO_REC_PERMISSIONS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS)) #define NEMO_FILE_UNDO_INFO_REC_PERMISSIONS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS, NemoFileUndoInfoRecPermissionsClass)) typedef struct _NemoFileUndoInfoRecPermissions NemoFileUndoInfoRecPermissions; typedef struct _NemoFileUndoInfoRecPermissionsClass NemoFileUndoInfoRecPermissionsClass; typedef struct _NemoFileUndoInfoRecPermissionsDetails NemoFileUndoInfoRecPermissionsDetails; struct _NemoFileUndoInfoRecPermissions { NemoFileUndoInfo parent; NemoFileUndoInfoRecPermissionsDetails *priv; }; struct _NemoFileUndoInfoRecPermissionsClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_rec_permissions_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_rec_permissions_new (GFile *dest, guint32 file_permissions, guint32 file_mask, guint32 dir_permissions, guint32 dir_mask); void nemo_file_undo_info_rec_permissions_add_file (NemoFileUndoInfoRecPermissions *self, GFile *file, guint32 permission); /* single file change permissions */ #define NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS (nemo_file_undo_info_permissions_get_type ()) #define NEMO_FILE_UNDO_INFO_PERMISSIONS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS, NemoFileUndoInfoPermissions)) #define NEMO_FILE_UNDO_INFO_PERMISSIONS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS, NemoFileUndoInfoPermissionsClass)) #define NEMO_IS_FILE_UNDO_INFO_PERMISSIONS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS)) #define NEMO_IS_FILE_UNDO_INFO_PERMISSIONS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS)) #define NEMO_FILE_UNDO_INFO_PERMISSIONS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_PERMISSIONS, NemoFileUndoInfoPermissionsClass)) typedef struct _NemoFileUndoInfoPermissions NemoFileUndoInfoPermissions; typedef struct _NemoFileUndoInfoPermissionsClass NemoFileUndoInfoPermissionsClass; typedef struct _NemoFileUndoInfoPermissionsDetails NemoFileUndoInfoPermissionsDetails; struct _NemoFileUndoInfoPermissions { NemoFileUndoInfo parent; NemoFileUndoInfoPermissionsDetails *priv; }; struct _NemoFileUndoInfoPermissionsClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_permissions_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_permissions_new (GFile *file, guint32 current_permissions, guint32 new_permissions); /* group and owner change */ #define NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP (nemo_file_undo_info_ownership_get_type ()) #define NEMO_FILE_UNDO_INFO_OWNERSHIP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP, NemoFileUndoInfoOwnership)) #define NEMO_FILE_UNDO_INFO_OWNERSHIP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP, NemoFileUndoInfoOwnershipClass)) #define NEMO_IS_FILE_UNDO_INFO_OWNERSHIP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP)) #define NEMO_IS_FILE_UNDO_INFO_OWNERSHIP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP)) #define NEMO_FILE_UNDO_INFO_OWNERSHIP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_FILE_UNDO_INFO_OWNERSHIP, NemoFileUndoInfoOwnershipClass)) typedef struct _NemoFileUndoInfoOwnership NemoFileUndoInfoOwnership; typedef struct _NemoFileUndoInfoOwnershipClass NemoFileUndoInfoOwnershipClass; typedef struct _NemoFileUndoInfoOwnershipDetails NemoFileUndoInfoOwnershipDetails; struct _NemoFileUndoInfoOwnership { NemoFileUndoInfo parent; NemoFileUndoInfoOwnershipDetails *priv; }; struct _NemoFileUndoInfoOwnershipClass { NemoFileUndoInfoClass parent_class; }; GType nemo_file_undo_info_ownership_get_type (void) G_GNUC_CONST; NemoFileUndoInfo *nemo_file_undo_info_ownership_new (NemoFileUndoOp op_type, GFile *file, const char *current_data, const char *new_data); #endif /* __NEMO_FILE_UNDO_OPERATIONS_H__ */ nemo-4.4.2/libnemo-private/nemo-file-utilities.c000066400000000000000000001257601357442400300216210ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-utilities.c - implementation of file manipulation routines. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #include #include "nemo-file-utilities.h" #include "nemo-global-preferences.h" #include "nemo-lib-self-check-functions.h" #include "nemo-metadata.h" #include "nemo-file.h" #include "nemo-file-operations.h" #include "nemo-search-directory.h" #include "nemo-signaller.h" #include "nemo-statx.h" #include #include #include #include #include #include #include #include #include #include #define NEMO_USER_DIRECTORY_NAME "nemo" #define DESKTOP_DIRECTORY_NAME "Desktop" #define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop" static void update_xdg_dir_cache (void); static void schedule_user_dirs_changed (void); static void desktop_dir_changed (void); static GFile *nemo_find_file_insensitive_next (GFile *parent, const gchar *name); char * nemo_compute_title_for_location (GFile *location) { NemoFile *file; char *title; char *builder; /* TODO-gio: This doesn't really work all that great if the info about the file isn't known atm... */ if (nemo_is_home_directory (location)) { return g_strdup (_("Home")); } builder = NULL; if (location) { file = nemo_file_get (location); builder = nemo_file_get_description (file); if (builder == NULL) { builder = nemo_file_get_display_name (file); } nemo_file_unref (file); } if (builder == NULL) { builder = g_file_get_basename (location); } if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_FULL_PATH_TITLES)) { gchar *uri, *path; file = nemo_file_get (location); uri = nemo_file_get_uri (file); path = g_filename_from_uri (uri, NULL, NULL); g_free (uri); if (path != NULL) { title = g_strdup_printf("%s - %s", builder, path); } else { title = g_strdup(builder); } nemo_file_unref (file); g_free (path); g_free (builder); } else { title = g_strdup(builder); g_free (builder); } return title; } // TODO: Maybe this can replace nemo_compute_title_for_location() all around? char * nemo_compute_search_title_for_location (GFile *location) { GFile *home_file; gchar *location_string; if (nemo_is_home_directory (location)) { return g_strdup (_("Home")); } home_file = g_file_new_for_path (g_get_home_dir ()); location_string = NULL; location_string = g_file_get_relative_path (home_file, location); if (location_string == NULL) { if (g_file_is_native (location)) { location_string = g_file_get_path (location); } else { location_string = g_file_get_uri (location); } } g_object_unref (home_file); return location_string; } /** * nemo_get_user_directory: * * Get the path for the directory containing nemo settings. * * Return value: the directory path. **/ char * nemo_get_user_directory (void) { char *user_directory = NULL; user_directory = g_build_filename (g_get_user_config_dir (), NEMO_USER_DIRECTORY_NAME, NULL); if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) { g_mkdir_with_parents (user_directory, DEFAULT_NEMO_DIRECTORY_MODE); /* FIXME bugzilla.gnome.org 41286: * How should we handle the case where this mkdir fails? * Note that nemo_application_startup will refuse to launch if this * directory doesn't get created, so that case is OK. But the directory * could be deleted after Nemo was launched, and perhaps * there is some bad side-effect of not handling that case. */ } return user_directory; } /** * nemo_get_accel_map_file: * * Get the path for the filename containing nemo accelerator map. * The filename need not exist. * * Return value: the filename path, or NULL if the home directory could not be found **/ char * nemo_get_accel_map_file (void) { const gchar *override; override = g_getenv ("GNOME22_USER_DIR"); if (override) { return g_build_filename (override, "accels/nemo", NULL); } else { return g_build_filename (g_get_home_dir (), ".gnome2/accels/nemo", NULL); } } /** * nemo_get_scripts_directory_path: * * Get the path for the directory containing nemo scripts. * * Return value: the directory path containing nemo scripts **/ char * nemo_get_scripts_directory_path (void) { return g_build_filename (g_get_user_data_dir (), "nemo", "scripts", NULL); } typedef struct { char *type; char *path; NemoFile *file; } XdgDirEntry; static XdgDirEntry * parse_xdg_dirs (const char *config_file) { GArray *array; char *config_file_free = NULL; XdgDirEntry dir; char *data; char **lines; char *p, *d; int i; char *type_start, *type_end; char *value, *unescaped; gboolean relative; array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry)); if (config_file == NULL) { config_file_free = g_build_filename (g_get_user_config_dir (), "user-dirs.dirs", NULL); config_file = (const char *)config_file_free; } if (g_file_get_contents (config_file, &data, NULL, NULL)) { lines = g_strsplit (data, "\n", 0); g_free (data); for (i = 0; lines[i] != NULL; i++) { p = lines[i]; while (g_ascii_isspace (*p)) p++; if (*p == '#') continue; value = strchr (p, '='); if (value == NULL) continue; *value++ = 0; g_strchug (g_strchomp (p)); if (!g_str_has_prefix (p, "XDG_")) continue; if (!g_str_has_suffix (p, "_DIR")) continue; type_start = p + 4; type_end = p + strlen (p) - 4; while (g_ascii_isspace (*value)) value++; if (*value != '"') continue; value++; relative = FALSE; if (g_str_has_prefix (value, "$HOME")) { relative = TRUE; value += 5; while (*value == '/') value++; } else if (*value != '/') continue; d = unescaped = g_malloc (strlen (value) + 1); while (*value && *value != '"') { if ((*value == '\\') && (*(value + 1) != 0)) value++; *d++ = *value++; } *d = 0; *type_end = 0; dir.type = g_strdup (type_start); if (relative) { dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL); g_free (unescaped); } else dir.path = unescaped; g_array_append_val (array, dir); } g_strfreev (lines); } g_free (config_file_free); return (XdgDirEntry *)g_array_free (array, FALSE); } static XdgDirEntry *cached_xdg_dirs = NULL; static GFileMonitor *cached_xdg_dirs_monitor = NULL; static void xdg_dir_changed (NemoFile *file, XdgDirEntry *dir) { GFile *location, *dir_location; char *path; location = nemo_file_get_location (file); dir_location = g_file_new_for_path (dir->path); if (!g_file_equal (location, dir_location)) { path = g_file_get_path (location); if (path) { char *argv[5]; int i; g_free (dir->path); dir->path = path; i = 0; argv[i++] = (char *)"xdg-user-dirs-update"; argv[i++] = (char *)"--set"; argv[i++] = dir->type; argv[i++] = dir->path; argv[i++] = NULL; /* We do this sync, to avoid possible race-conditions if multiple dirs change at the same time. Its blocking the main thread, but these updates should be very rare and very fast. */ g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, NULL, NULL); g_reload_user_special_dirs_cache (); schedule_user_dirs_changed (); desktop_dir_changed (); /* Icon might have changed */ nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO); } } g_object_unref (location); g_object_unref (dir_location); } static void xdg_dir_cache_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type) { if (event_type == G_FILE_MONITOR_EVENT_CHANGED || event_type == G_FILE_MONITOR_EVENT_CREATED) { update_xdg_dir_cache (); } } static int user_dirs_changed_tag = 0; static gboolean emit_user_dirs_changed_idle (gpointer data) { g_signal_emit_by_name (nemo_signaller_get_current (), "user_dirs_changed"); user_dirs_changed_tag = 0; return FALSE; } static void schedule_user_dirs_changed (void) { if (user_dirs_changed_tag == 0) { user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL); } } static void unschedule_user_dirs_changed (void) { if (user_dirs_changed_tag != 0) { g_source_remove (user_dirs_changed_tag); user_dirs_changed_tag = 0; } } static void free_xdg_dir_cache (void) { int i; if (cached_xdg_dirs != NULL) { for (i = 0; cached_xdg_dirs[i].type != NULL; i++) { if (cached_xdg_dirs[i].file != NULL) { nemo_file_monitor_remove (cached_xdg_dirs[i].file, &cached_xdg_dirs[i]); g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file, G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]); nemo_file_unref (cached_xdg_dirs[i].file); } g_free (cached_xdg_dirs[i].type); g_free (cached_xdg_dirs[i].path); } g_free (cached_xdg_dirs); } } static void destroy_xdg_dir_cache (void) { free_xdg_dir_cache (); unschedule_user_dirs_changed (); desktop_dir_changed (); if (cached_xdg_dirs_monitor != NULL) { g_object_unref (cached_xdg_dirs_monitor); cached_xdg_dirs_monitor = NULL; } } static void update_xdg_dir_cache (void) { GFile *file; char *config_file, *uri; int i; free_xdg_dir_cache (); g_reload_user_special_dirs_cache (); schedule_user_dirs_changed (); desktop_dir_changed (); cached_xdg_dirs = parse_xdg_dirs (NULL); for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++) { cached_xdg_dirs[i].file = NULL; if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0) { uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL); cached_xdg_dirs[i].file = nemo_file_get_by_uri (uri); nemo_file_monitor_add (cached_xdg_dirs[i].file, &cached_xdg_dirs[i], NEMO_FILE_ATTRIBUTE_INFO); g_signal_connect (cached_xdg_dirs[i].file, "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]); g_free (uri); } } if (cached_xdg_dirs_monitor == NULL) { config_file = g_build_filename (g_get_user_config_dir (), "user-dirs.dirs", NULL); file = g_file_new_for_path (config_file); cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL, NULL); g_signal_connect (cached_xdg_dirs_monitor, "changed", G_CALLBACK (xdg_dir_cache_changed_cb), NULL); g_object_unref (file); g_free (config_file); eel_debug_call_at_shutdown (destroy_xdg_dir_cache); } } char * nemo_get_xdg_dir (const char *type) { int i; if (cached_xdg_dirs == NULL) { update_xdg_dir_cache (); } for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++) { if (strcmp (cached_xdg_dirs[i].type, type) == 0) { return g_strdup (cached_xdg_dirs[i].path); } } if (strcmp ("DESKTOP", type) == 0) { return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL); } if (strcmp ("TEMPLATES", type) == 0) { return g_build_filename (g_get_home_dir (), "Templates", NULL); } return g_strdup (g_get_home_dir ()); } static char * get_desktop_path (void) { if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) { return g_strdup (g_get_home_dir()); } else { return nemo_get_xdg_dir ("DESKTOP"); } } /** * nemo_get_desktop_directory: * * Get the path for the directory containing files on the desktop. * * Return value: the directory path. **/ char * nemo_get_desktop_directory (void) { char *desktop_directory; desktop_directory = get_desktop_path (); /* Don't try to create a home directory */ if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) { if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) { g_mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE); /* FIXME bugzilla.gnome.org 41286: * How should we handle the case where this mkdir fails? * Note that nemo_application_startup will refuse to launch if this * directory doesn't get created, so that case is OK. But the directory * could be deleted after Nemo was launched, and perhaps * there is some bad side-effect of not handling that case. */ } } return desktop_directory; } GFile * nemo_get_desktop_location (void) { char *desktop_directory; GFile *res; desktop_directory = get_desktop_path (); res = g_file_new_for_path (desktop_directory); g_free (desktop_directory); return res; } /** * nemo_get_desktop_directory_uri: * * Get the uri for the directory containing files on the desktop. * * Return value: the directory path. **/ char * nemo_get_desktop_directory_uri (void) { char *desktop_path; char *desktop_uri; desktop_path = nemo_get_desktop_directory (); desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL); g_free (desktop_path); return desktop_uri; } char * nemo_get_desktop_directory_uri_no_create (void) { char *desktop_path; char *desktop_uri; desktop_path = get_desktop_path (); desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL); g_free (desktop_path); return desktop_uri; } char * nemo_get_home_directory_uri (void) { return g_filename_to_uri (g_get_home_dir (), NULL, NULL); } gboolean nemo_should_use_templates_directory (void) { char *dir; gboolean res; dir = nemo_get_xdg_dir ("TEMPLATES"); res = strcmp (dir, g_get_home_dir ()) != 0; g_free (dir); return res; } char * nemo_get_templates_directory (void) { return nemo_get_xdg_dir ("TEMPLATES"); } void nemo_create_templates_directory (void) { char *dir; dir = nemo_get_templates_directory (); if (!g_file_test (dir, G_FILE_TEST_EXISTS)) { g_mkdir (dir, DEFAULT_NEMO_DIRECTORY_MODE); } g_free (dir); } char * nemo_get_templates_directory_uri (void) { char *directory, *uri; directory = nemo_get_templates_directory (); uri = g_filename_to_uri (directory, NULL, NULL); g_free (directory); return uri; } char * nemo_get_searches_directory (void) { char *user_dir; char *searches_dir; user_dir = nemo_get_user_directory (); searches_dir = g_build_filename (user_dir, "searches", NULL); g_free (user_dir); if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS)) g_mkdir (searches_dir, DEFAULT_NEMO_DIRECTORY_MODE); return searches_dir; } /* These need to be reset to NULL when desktop_is_home_dir changes */ static GFile *desktop_dir = NULL; static GFile *desktop_dir_dir = NULL; static char *desktop_dir_filename = NULL; static gboolean desktop_dir_changed_callback_installed = FALSE; static void desktop_dir_changed (void) { if (desktop_dir) { g_object_unref (desktop_dir); } if (desktop_dir_dir) { g_object_unref (desktop_dir_dir); } g_free (desktop_dir_filename); desktop_dir = NULL; desktop_dir_dir = NULL; desktop_dir_filename = NULL; } static void desktop_dir_changed_callback (gpointer callback_data) { desktop_dir_changed (); } static void update_desktop_dir (void) { char *path; char *dirname; path = get_desktop_path (); desktop_dir = g_file_new_for_path (path); dirname = g_path_get_dirname (path); desktop_dir_dir = g_file_new_for_path (dirname); g_free (dirname); desktop_dir_filename = g_path_get_basename (path); g_free (path); } gboolean nemo_is_home_directory_file (GFile *dir, const char *filename) { char *dirname; static GFile *home_dir_dir = NULL; static char *home_dir_filename = NULL; if (home_dir_dir == NULL) { dirname = g_path_get_dirname (g_get_home_dir ()); home_dir_dir = g_file_new_for_path (dirname); g_free (dirname); home_dir_filename = g_path_get_basename (g_get_home_dir ()); } return (g_file_equal (dir, home_dir_dir) && strcmp (filename, home_dir_filename) == 0); } gboolean nemo_is_home_directory (GFile *dir) { static GFile *home_dir = NULL; if (home_dir == NULL) { home_dir = g_file_new_for_path (g_get_home_dir ()); } return g_file_equal (dir, home_dir); } gboolean nemo_is_root_directory (GFile *dir) { static GFile *root_dir = NULL; if (root_dir == NULL) { root_dir = g_file_new_for_path ("/"); } return g_file_equal (dir, root_dir); } gboolean nemo_is_desktop_directory_file (GFile *dir, const char *file) { if (!desktop_dir_changed_callback_installed) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_dir_changed_callback), NULL); desktop_dir_changed_callback_installed = TRUE; } if (desktop_dir == NULL) { update_desktop_dir (); } return (g_file_equal (dir, desktop_dir_dir) && strcmp (file, desktop_dir_filename) == 0); } gboolean nemo_is_desktop_directory (GFile *dir) { if (!desktop_dir_changed_callback_installed) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_dir_changed_callback), NULL); desktop_dir_changed_callback_installed = TRUE; } if (desktop_dir == NULL) { update_desktop_dir (); } return g_file_equal (dir, desktop_dir); } /** * nemo_get_gmc_desktop_directory: * * Get the path for the directory containing the legacy gmc desktop. * * Return value: the directory path. **/ char * nemo_get_gmc_desktop_directory (void) { return g_build_filename (g_get_home_dir (), LEGACY_DESKTOP_DIRECTORY_NAME, NULL); } char * nemo_get_data_file_path (const char *partial_path) { char *path; char *user_directory; /* first try the user's home directory */ user_directory = nemo_get_user_directory (); path = g_build_filename (user_directory, partial_path, NULL); g_free (user_directory); if (g_file_test (path, G_FILE_TEST_EXISTS)) { return path; } g_free (path); /* next try the shared directory */ path = g_build_filename (NEMO_DATADIR, partial_path, NULL); if (g_file_test (path, G_FILE_TEST_EXISTS)) { return path; } g_free (path); return NULL; } char * nemo_ensure_unique_file_name (const char *directory_uri, const char *base_name, const char *extension) { GFileInfo *info; char *filename; GFile *dir, *child; int copy; char *res; dir = g_file_new_for_uri (directory_uri); info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL); if (info == NULL) { g_object_unref (dir); return NULL; } g_object_unref (info); filename = g_strdup_printf ("%s%s", base_name, extension); child = g_file_get_child (dir, filename); g_free (filename); copy = 1; while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL)) != NULL) { g_object_unref (info); g_object_unref (child); filename = g_strdup_printf ("%s-%d%s", base_name, copy, extension); child = g_file_get_child (dir, filename); g_free (filename); copy++; } res = g_file_get_uri (child); g_object_unref (child); g_object_unref (dir); return res; } char * nemo_unique_temporary_file_name (void) { const char *prefix = "/tmp/nemo-temp-file"; char *file_name; int fd; file_name = g_strdup_printf ("%sXXXXXX", prefix); fd = g_mkstemp (file_name); if (fd == -1) { g_free (file_name); file_name = NULL; } else { close (fd); } return file_name; } GFile * nemo_find_existing_uri_in_hierarchy (GFile *location) { GFileInfo *info; GFile *tmp; g_assert (location != NULL); location = g_object_ref (location); while (location != NULL) { info = g_file_query_info (location, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); g_object_unref (info); if (info != NULL) { return location; } tmp = location; location = g_file_get_parent (location); g_object_unref (tmp); } return location; } /** * nemo_find_file_insensitive * * Attempt to find a file case-insentively. If the path can be found, the * returned file maps directly to it. Otherwise, a file using the * originally-cased path is returned. This function performs might perform * I/O. * * Return value: a #GFile to a child specified by @name. **/ GFile * nemo_find_file_insensitive (GFile *parent, const gchar *name) { gchar **split_path; gchar *component; GFile *file, *next; gint i; split_path = g_strsplit (name, G_DIR_SEPARATOR_S, -1); file = g_object_ref (parent); for (i = 0; (component = split_path[i]) != NULL; i++) { if (!(next = nemo_find_file_insensitive_next (file, component))) { /* File does not exist */ g_object_unref (file); file = NULL; break; } g_object_unref (file); file = next; } g_strfreev (split_path); if (file) { return file; } return g_file_get_child (parent, name); } static GFile * nemo_find_file_insensitive_next (GFile *parent, const gchar *name) { GFileEnumerator *children; GFileInfo *info; gboolean use_utf8, found; char *filename, *case_folded_name, *utf8_collation_key, *ascii_collation_key, *child_key; GFile *file; const char *child_name, *compare_key; /* First check the given version */ file = g_file_get_child (parent, name); if (g_file_query_exists (file, NULL)) { return file; } g_object_unref (file); ascii_collation_key = g_ascii_strdown (name, -1); use_utf8 = g_utf8_validate (name, -1, NULL); utf8_collation_key = NULL; if (use_utf8) { case_folded_name = g_utf8_casefold (name, -1); utf8_collation_key = g_utf8_collate_key (case_folded_name, -1); g_free (case_folded_name); } /* Enumerate and compare insensitive */ filename = NULL; children = g_file_enumerate_children (parent, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); if (children != NULL) { while ((info = g_file_enumerator_next_file (children, NULL, NULL))) { child_name = g_file_info_get_name (info); if (use_utf8 && g_utf8_validate (child_name, -1, NULL)) { gchar *case_folded; case_folded = g_utf8_casefold (child_name, -1); child_key = g_utf8_collate_key (case_folded, -1); g_free (case_folded); compare_key = utf8_collation_key; } else { child_key = g_ascii_strdown (child_name, -1); compare_key = ascii_collation_key; } found = strcmp (child_key, compare_key) == 0; g_free (child_key); if (found) { filename = g_strdup (child_name); break; } } g_file_enumerator_close (children, NULL, NULL); g_object_unref (children); } g_free (ascii_collation_key); g_free (utf8_collation_key); if (filename) { file = g_file_get_child (parent, filename); g_free (filename); return file; } return NULL; } static gboolean have_program_in_path (const char *name) { char *path; gboolean result; path = g_find_program_in_path (name); result = (path != NULL); g_free (path); return result; } gboolean nemo_is_file_roller_installed (void) { static int installed = - 1; if (installed < 0) { if (have_program_in_path ("file-roller")) { installed = 1; } else { installed = 0; } } return installed > 0 ? TRUE : FALSE; } #define GSM_NAME "org.gnome.SessionManager" #define GSM_PATH "/org/gnome/SessionManager" #define GSM_INTERFACE "org.gnome.SessionManager" /* The following values come from * http://www.gnome.org/~mccann/gnome-session/docs/gnome-session.html#org.gnome.SessionManager.Inhibit */ #define INHIBIT_LOGOUT (1U) #define INHIBIT_SUSPEND (4U) static GDBusConnection * get_dbus_connection (void) { static GDBusConnection *conn = NULL; if (conn == NULL) { GError *error = NULL; conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (conn == NULL) { g_warning ("Could not connect to session bus: %s", error->message); g_error_free (error); } } return conn; } /** * nemo_inhibit_power_manager: * @message: a human readable message for the reason why power management * is being suspended. * * Inhibits the power manager from logging out or suspending the machine * (e.g. whenever Nemo is doing file operations). * * Returns: an integer cookie, which must be passed to * nemo_uninhibit_power_manager() to resume * normal power management. */ int nemo_inhibit_power_manager (const char *message) { GDBusConnection *connection; GVariant *result; GError *error = NULL; guint cookie = 0; g_return_val_if_fail (message != NULL, -1); connection = get_dbus_connection (); if (connection == NULL) { return -1; } result = g_dbus_connection_call_sync (connection, GSM_NAME, GSM_PATH, GSM_INTERFACE, "Inhibit", g_variant_new ("(susu)", "Nemo", (guint) 0, message, (guint) (INHIBIT_LOGOUT | INHIBIT_SUSPEND)), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, &error); if (error != NULL) { g_warning ("Could not inhibit power management: %s", error->message); g_error_free (error); return -1; } g_variant_get (result, "(u)", &cookie); g_variant_unref (result); return (int) cookie; } /** * nemo_uninhibit_power_manager: * @cookie: the cookie value returned by nemo_inhibit_power_manager() * * Uninhibits power management. This function must be called after the task * which inhibited power management has finished, or the system will not * return to normal power management. */ void nemo_uninhibit_power_manager (gint cookie) { GDBusConnection *connection; GVariant *result; GError *error = NULL; g_return_if_fail (cookie > 0); connection = get_dbus_connection (); if (connection == NULL) { return; } result = g_dbus_connection_call_sync (connection, GSM_NAME, GSM_PATH, GSM_INTERFACE, "Uninhibit", g_variant_new ("(u)", (guint) cookie), NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, &error); if (result == NULL) { g_warning ("Could not uninhibit power management: %s", error->message); g_error_free (error); return; } g_variant_unref (result); } /* Returns TRUE if the file is in XDG_DATA_DIRS or in "~/.gnome2/". This is used for deciding if a desktop file is "trusted" based on the path */ gboolean nemo_is_in_system_dir (GFile *file) { const char * const * data_dirs; char *path, *gnome2; int i; gboolean res; if (!g_file_is_native (file)) { return FALSE; } path = g_file_get_path (file); res = FALSE; data_dirs = g_get_system_data_dirs (); for (i = 0; path != NULL && data_dirs[i] != NULL; i++) { if (g_str_has_prefix (path, data_dirs[i])) { res = TRUE; break; } } if (!res) { /* Panel desktop files are here, trust them */ gnome2 = g_build_filename (g_get_home_dir (), ".gnome2", NULL); if (g_str_has_prefix (path, gnome2)) { res = TRUE; } g_free (gnome2); } g_free (path); return res; } GHashTable * nemo_trashed_files_get_original_directories (GList *files, GList **unhandled_files) { GHashTable *directories; NemoFile *file, *original_file, *original_dir; GList *l, *m; directories = NULL; if (unhandled_files != NULL) { *unhandled_files = NULL; } for (l = files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); original_file = nemo_file_get_trash_original_file (file); original_dir = NULL; if (original_file != NULL) { original_dir = nemo_file_get_parent (original_file); } if (original_dir != NULL) { if (directories == NULL) { directories = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) nemo_file_unref, (GDestroyNotify) nemo_file_list_free); } nemo_file_ref (original_dir); m = g_hash_table_lookup (directories, original_dir); if (m != NULL) { g_hash_table_steal (directories, original_dir); nemo_file_unref (original_dir); } m = g_list_append (m, nemo_file_ref (file)); g_hash_table_insert (directories, original_dir, m); } else if (unhandled_files != NULL) { *unhandled_files = g_list_append (*unhandled_files, nemo_file_ref (file)); } if (original_file != NULL) { nemo_file_unref (original_file); } if (original_dir != NULL) { nemo_file_unref (original_dir); } } return directories; } static GList * locations_from_file_list (GList *file_list) { NemoFile *file; GList *l, *ret; ret = NULL; for (l = file_list; l != NULL; l = l->next) { file = NEMO_FILE (l->data); ret = g_list_prepend (ret, nemo_file_get_location (file)); } return g_list_reverse (ret); } typedef struct { GHashTable *original_dirs_hash; GtkWindow *parent_window; } RestoreFilesData; static void ensure_dirs_task_ready_cb (GObject *_source, GAsyncResult *res, gpointer user_data) { NemoFile *original_dir; GFile *original_dir_location; GList *original_dirs, *files, *locations, *l; RestoreFilesData *data = user_data; original_dirs = g_hash_table_get_keys (data->original_dirs_hash); for (l = original_dirs; l != NULL; l = l->next) { original_dir = NEMO_FILE (l->data); original_dir_location = nemo_file_get_location (original_dir); files = g_hash_table_lookup (data->original_dirs_hash, original_dir); locations = locations_from_file_list (files); nemo_file_operations_move (locations, NULL, original_dir_location, data->parent_window, NULL, NULL); g_list_free_full (locations, g_object_unref); g_object_unref (original_dir_location); } g_list_free (original_dirs); g_hash_table_unref (data->original_dirs_hash); g_slice_free (RestoreFilesData, data); } static void ensure_dirs_task_thread_func (GTask *task, gpointer source, gpointer task_data, GCancellable *cancellable) { RestoreFilesData *data = task_data; NemoFile *original_dir; GFile *original_dir_location; GList *original_dirs, *l; original_dirs = g_hash_table_get_keys (data->original_dirs_hash); for (l = original_dirs; l != NULL; l = l->next) { original_dir = NEMO_FILE (l->data); original_dir_location = nemo_file_get_location (original_dir); g_file_make_directory_with_parents (original_dir_location, cancellable, NULL); g_object_unref (original_dir_location); } g_task_return_pointer (task, NULL, NULL); } static void restore_files_ensure_parent_directories (GHashTable *original_dirs_hash, GtkWindow *parent_window) { RestoreFilesData *data; GTask *ensure_dirs_task; data = g_slice_new0 (RestoreFilesData); data->parent_window = parent_window; data->original_dirs_hash = g_hash_table_ref (original_dirs_hash); ensure_dirs_task = g_task_new (NULL, NULL, ensure_dirs_task_ready_cb, data); g_task_set_task_data (ensure_dirs_task, data, NULL); g_task_run_in_thread (ensure_dirs_task, ensure_dirs_task_thread_func); g_object_unref (ensure_dirs_task); } void nemo_restore_files_from_trash (GList *files, GtkWindow *parent_window) { NemoFile *file; GHashTable *original_dirs_hash; GList *unhandled_files, *l; char *message, *file_name; original_dirs_hash = nemo_trashed_files_get_original_directories (files, &unhandled_files); for (l = unhandled_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); file_name = nemo_file_get_display_name (file); message = g_strdup_printf (_("Could not determine original location of \"%s\" "), file_name); g_free (file_name); eel_show_warning_dialog (message, _("The item cannot be restored from trash"), parent_window); g_free (message); } if (original_dirs_hash != NULL) { restore_files_ensure_parent_directories (original_dirs_hash, parent_window); g_hash_table_unref (original_dirs_hash); } nemo_file_list_unref (unhandled_files); } typedef struct { NemoMountGetContent callback; gpointer user_data; } GetContentTypesData; static void get_types_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GetContentTypesData *data; char **types; data = user_data; types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL); g_object_set_data_full (source_object, "nemo-content-type-cache", g_strdupv (types), (GDestroyNotify)g_strfreev); if (data->callback) { data->callback ((const char **) types, data->user_data); } g_strfreev (types); g_slice_free (GetContentTypesData, data); } void nemo_get_x_content_types_for_mount_async (GMount *mount, NemoMountGetContent callback, GCancellable *cancellable, gpointer user_data) { char **cached; GetContentTypesData *data; if (mount == NULL) { if (callback) { callback (NULL, user_data); } return; } cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache"); if (cached != NULL) { if (callback) { callback ((const char **) cached, user_data); } return; } data = g_slice_new0 (GetContentTypesData); data->callback = callback; data->user_data = user_data; g_mount_guess_content_type (mount, FALSE, cancellable, get_types_cb, data); } char ** nemo_get_cached_x_content_types_for_mount (GMount *mount) { char **cached; if (mount == NULL) { return NULL; } cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache"); if (cached != NULL) { return g_strdupv (cached); } return NULL; } static void debug_icon_names (const gchar *format, ...) { static gboolean debug_removable_device_icons = FALSE; static gsize once_init = 0; if (g_once_init_enter (&once_init)) { debug_removable_device_icons = g_getenv ("NEMO_DEBUG_DEVICE_ICONS") != NULL; g_once_init_leave (&once_init, 1); } if (!debug_removable_device_icons) { return; } va_list args; va_start (args, format); g_logv (NULL, G_LOG_LEVEL_MESSAGE, format, args); va_end(args); } static gboolean icon_name_is_non_specific (const gchar *icon_name) { gint i; static const char * non_specific_icon_names[] = { "drive-harddisk-usb-symbolic" }; for (i = 0; i < G_N_ELEMENTS (non_specific_icon_names); i++) { if (g_strcmp0 (icon_name, non_specific_icon_names[i]) == 0) { return TRUE; } } return FALSE; } gchar * nemo_get_mount_icon_name (GMount *mount) { GDrive *drive; GIcon *gicon; gchar *icon_name; gchar *mount_icon_name; gchar *dev_name; g_return_val_if_fail (mount != NULL, NULL); dev_name = g_mount_get_name (mount); icon_name = NULL; mount_icon_name = NULL; gicon = g_mount_get_symbolic_icon (mount); if (G_IS_THEMED_ICON (gicon)) { mount_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); if (icon_name_is_non_specific (mount_icon_name)) { debug_icon_names ("mount %s: icon name '%s' too non-specific", dev_name, mount_icon_name); } else { icon_name = g_strdup (mount_icon_name); } } g_clear_object (&gicon); if (icon_name != NULL) { debug_icon_names ("mount %s: icon name '%s' is being used", dev_name, icon_name); g_free (dev_name); g_free (mount_icon_name); return icon_name; } drive = g_mount_get_drive (mount); if (drive != NULL) { gicon = g_drive_get_symbolic_icon (drive); g_object_unref (drive); if (G_IS_THEMED_ICON (gicon)) { icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); } g_object_unref (gicon); } if (icon_name == NULL) { if (mount_icon_name) { icon_name = g_strdup (mount_icon_name); } else { icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?... } debug_icon_names ("mount %s: no other good icon name found, using fallback of '%s'", dev_name, icon_name); } g_free (dev_name); g_free (mount_icon_name); return icon_name; } gchar * nemo_get_volume_icon_name (GVolume *volume) { GDrive *drive; GIcon *gicon; gchar *icon_name; gchar *dev_name; gchar *volume_icon_name; g_return_val_if_fail (volume != NULL, NULL); dev_name = g_volume_get_name (volume); icon_name = NULL; volume_icon_name = NULL; gicon = g_volume_get_symbolic_icon (volume); if (G_IS_THEMED_ICON (gicon)) { volume_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); if (icon_name_is_non_specific (volume_icon_name)) { debug_icon_names ("volume %s: icon name '%s' too non-specific", dev_name, volume_icon_name); } else { icon_name = g_strdup (volume_icon_name); } } g_clear_object (&gicon); if (icon_name != NULL) { debug_icon_names ("volume %s: icon name '%s' is being used", dev_name, icon_name); g_free (dev_name); g_free (volume_icon_name); return icon_name; } drive = g_volume_get_drive (volume); if (drive != NULL) { gicon = g_drive_get_symbolic_icon (drive); g_object_unref (drive); if (G_IS_THEMED_ICON (gicon)) { icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); } g_object_unref (gicon); } if (icon_name == NULL) { if (volume_icon_name) { icon_name = g_strdup (volume_icon_name); } else { icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?... } debug_icon_names ("volume %s: no good icon name found, using fallback of '%s'", dev_name, icon_name); } g_free (dev_name); g_free (volume_icon_name); return icon_name; } gchar * nemo_get_drive_icon_name (GDrive *drive) { GIcon *gicon; gchar *icon_name; gchar *dev_name; g_return_val_if_fail (drive != NULL, NULL); dev_name = g_drive_get_name (drive); gicon = g_drive_get_symbolic_icon (drive); if (G_IS_THEMED_ICON (gicon)) { icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); } else { icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?... } g_object_unref (gicon); debug_icon_names ("drive %s: returning icon '%s'", dev_name, icon_name); g_free (dev_name); return icon_name; } gchar * nemo_get_best_guess_file_mimetype (const gchar *filename, GFileInfo *info, goffset size) { /* This is an attempt to do a better job at identifying file types than * the current gio implementation. * * The current behavior for empty (0 size) size files, is to return * "text/plain" so users can touch a file, or create an empty one in their * file manager, and immediately edit it. * * This behavior currently applies regardless of whether or not a file has * an extension. * * More discussion: https://bugzilla.gnome.org/show_bug.cgi?id=755795 * * What we do here instead is take a file's extension into account if the file * is zero-length. If, by doing so, we have a high confidence that a file is * a certain type, we go ahead and use that type. We only fall back to Gio's * zero-length implementation if the extension is unknown, or it has none. * * - Files that are NOT zero-length are treated the same as before. * - Files that we are not certain about are treated the same as before. * * Again, this only has an effect on zero-length, known-extension files. My * argument for this differing from the standing implementation is that if I * create a file with a particular extension, I did so for a reason, and I'm not * going to do something silly like make foo.mp3 and attempt to open it with my * media player. I do, however, expect that if I touch a foo.h file and open it, * it will open up in my source code editor, and *not* my general purpose plain- * text handler. */ g_return_val_if_fail (filename != NULL, g_strdup ("application/octet-stream")); g_return_val_if_fail (info != NULL, g_strdup ("application/octet-stream")); gchar *mime_type = NULL; if (size > 0) { /* Default behavior */ mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info)); } else { gboolean uncertain; gchar *guessed_type = NULL; /* Only give the file basename, not the full path. a) We may not have it yet, and * b) we don't want g_content_type_guess to keep going and snoop the file. This will * keep the guess based entirely on the extension, if there is one. */ guessed_type = g_content_type_guess (filename, NULL, 0, &uncertain); /* Uncertain means, it's not a registered extension, so we fall back to our (gio's) * normal behavior - text/plain (currently at least.) */ if (!uncertain) { mime_type = eel_ref_str_get_unique (guessed_type); } else { mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info)); } g_free (guessed_type); } return mime_type; } static void query_btime_async_thread (GTask *task, gpointer object, gpointer task_data, GCancellable *cancellable) { gchar *path; time_t btime; btime = 0; path = g_file_get_path (G_FILE (object)); if (path != NULL) { btime = get_file_btime (path); g_free (path); } if (btime > 0) { /* Conveniently, gssize is the same as time_t */ g_task_return_int (task, (gssize) btime); } else { g_task_return_error (task, g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED, "statx failed or not supported")); } } void nemo_query_btime_async (GFile *file, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (file, cancellable, callback, user_data); g_task_set_priority (task, G_PRIORITY_DEFAULT); g_task_run_in_thread (task, query_btime_async_thread); g_object_unref (task); } time_t nemo_query_btime_finish (GFile *file, GAsyncResult *res, GError **error) { g_return_val_if_fail (g_task_is_valid (res, file), -1); return (time_t) g_task_propagate_int (G_TASK (res), error); } /* End copied section */ #if !defined (NEMO_OMIT_SELF_CHECK) void nemo_self_check_file_utilities (void) { } #endif /* !NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/libnemo-private/nemo-file-utilities.h000066400000000000000000000122251357442400300216150ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-utilities.h - interface for file manipulation routines. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #ifndef NEMO_FILE_UTILITIES_H #define NEMO_FILE_UTILITIES_H #include #include #define NEMO_SAVED_SEARCH_EXTENSION ".savedSearch" #define NEMO_SAVED_SEARCH_MIMETYPE "application/x-gnome-saved-search" #define DEFAULT_NEMO_DIRECTORY_MODE (0755) #define DEFAULT_DESKTOP_DIRECTORY_MODE (0755) /* These functions all return something something that needs to be * freed with g_free, is not NULL, and is guaranteed to exist. */ char * nemo_get_xdg_dir (const char *type); char * nemo_get_user_directory (void); char * nemo_get_desktop_directory (void); GFile * nemo_get_desktop_location (void); char * nemo_get_desktop_directory_uri (void); char * nemo_get_home_directory_uri (void); gboolean nemo_is_desktop_directory_file (GFile *dir, const char *filename); gboolean nemo_is_root_directory (GFile *dir); gboolean nemo_is_desktop_directory (GFile *dir); gboolean nemo_is_home_directory (GFile *dir); gboolean nemo_is_home_directory_file (GFile *dir, const char *filename); gboolean nemo_is_in_system_dir (GFile *location); char * nemo_get_gmc_desktop_directory (void); gboolean nemo_should_use_templates_directory (void); char * nemo_get_templates_directory (void); char * nemo_get_templates_directory_uri (void); void nemo_create_templates_directory (void); char * nemo_get_searches_directory (void); char * nemo_compute_title_for_location (GFile *file); char * nemo_compute_search_title_for_location (GFile *location); /* This function returns something that needs to be freed with g_free, * is not NULL, but is not garaunteed to exist */ char * nemo_get_desktop_directory_uri_no_create (void); /* Locate a file in either the uers directory or the datadir. */ char * nemo_get_data_file_path (const char *partial_path); gboolean nemo_is_file_roller_installed (void); /* Inhibit/Uninhibit GNOME Power Manager */ int nemo_inhibit_power_manager (const char *message) G_GNUC_WARN_UNUSED_RESULT; void nemo_uninhibit_power_manager (int cookie); /* Return an allocated file name that is guranteed to be unique, but * tries to make the name readable to users. * This isn't race-free, so don't use for security-related things */ char * nemo_ensure_unique_file_name (const char *directory_uri, const char *base_name, const char *extension); char * nemo_unique_temporary_file_name (void); GFile * nemo_find_existing_uri_in_hierarchy (GFile *location); GFile * nemo_find_file_insensitive (GFile *parent, const gchar *name); char * nemo_get_accel_map_file (void); char * nemo_get_scripts_directory_path (void); GHashTable * nemo_trashed_files_get_original_directories (GList *files, GList **unhandled_files); void nemo_restore_files_from_trash (GList *files, GtkWindow *parent_window); typedef void (*NemoMountGetContent) (const char **content, gpointer user_data); char ** nemo_get_cached_x_content_types_for_mount (GMount *mount); void nemo_get_x_content_types_for_mount_async (GMount *mount, NemoMountGetContent callback, GCancellable *cancellable, gpointer user_data); gchar *nemo_get_mount_icon_name (GMount *mount); gchar *nemo_get_volume_icon_name (GVolume *volume); gchar *nemo_get_drive_icon_name (GDrive *drive); gchar *nemo_get_best_guess_file_mimetype (const gchar *filename, GFileInfo *info, goffset size); void nemo_query_btime_async (GFile *file, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); time_t nemo_query_btime_finish (GFile *file, GAsyncResult *res, GError **error); #endif /* NEMO_FILE_UTILITIES_H */ nemo-4.4.2/libnemo-private/nemo-file.c000066400000000000000000007123761357442400300176150ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- nemo-file.c: Nemo file model. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-file.h" #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-signaller.h" #include "nemo-desktop-directory.h" #include "nemo-desktop-directory-file.h" #include "nemo-desktop-icon-file.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-operations.h" #include "nemo-file-utilities.h" #include "nemo-global-preferences.h" #include "nemo-icon-names.h" #include "nemo-lib-self-check-functions.h" #include "nemo-link.h" #include "nemo-metadata.h" #include "nemo-module.h" #include "nemo-search-directory.h" #include "nemo-search-directory-file.h" #include "nemo-thumbnails.h" #include "nemo-trash-monitor.h" #include "nemo-vfs-file.h" #include "nemo-file-undo-operations.h" #include "nemo-file-undo-manager.h" #include "nemo-saved-search-file.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SELINUX #include #endif #define DEBUG_FLAG NEMO_DEBUG_FILE #include /* Time in seconds to cache getpwuid results */ #define GETPWUID_CACHE_TIME (5*60) #define ICON_NAME_THUMBNAIL_LOADING "image-loading" #undef NEMO_FILE_DEBUG_REF #undef NEMO_FILE_DEBUG_REF_VALGRIND #ifdef NEMO_FILE_DEBUG_REF_VALGRIND #include #define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE #else #define DEBUG_REF_PRINTF printf #endif /* Files that start with these characters sort after files that don't. */ #define SORT_LAST_CHAR1 '.' #define SORT_LAST_CHAR2 '#' /* Name of Nemo trash directories */ #define TRASH_DIRECTORY_NAME ".Trash" #define METADATA_ID_IS_LIST_MASK (1<<31) #define MAX_THUMBNAIL_TRIES 2 typedef enum { SHOW_HIDDEN = 1 << 0, } FilterOptions; typedef enum { NEMO_DATE_FORMAT_REGULAR = 0, NEMO_DATE_FORMAT_REGULAR_WITH_TIME = 1, NEMO_DATE_FORMAT_FULL = 2, } NemoDateCompactFormat; typedef void (* ModifyListFunction) (GList **list, NemoFile *file); enum { CHANGED, UPDATED_DEEP_COUNT_IN_PROGRESS, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static GHashTable *symbolic_links; static GQuark attribute_name_q, attribute_size_q, attribute_type_q, attribute_detailed_type_q, attribute_modification_date_q, attribute_date_modified_q, attribute_date_modified_full_q, attribute_date_modified_with_time_q, attribute_accessed_date_q, attribute_date_accessed_q, attribute_date_accessed_full_q, attribute_creation_date_q, attribute_date_created_q, attribute_date_created_full_q, attribute_date_created_with_time_q, attribute_mime_type_q, attribute_size_detail_q, attribute_deep_size_q, attribute_deep_file_count_q, attribute_deep_directory_count_q, attribute_deep_total_count_q, attribute_date_changed_q, attribute_date_changed_full_q, attribute_trashed_on_q, attribute_trashed_on_full_q, attribute_trash_orig_path_q, attribute_date_permissions_q, attribute_date_permissions_full_q, attribute_permissions_q, attribute_selinux_context_q, attribute_octal_permissions_q, attribute_owner_q, attribute_group_q, attribute_uri_q, attribute_where_q, attribute_link_target_q, attribute_volume_q, attribute_free_space_q; static void nemo_file_info_iface_init (NemoFileInfoInterface *iface); static gboolean update_info_and_name (NemoFile *file, GFileInfo *info); static const char * nemo_file_peek_display_name (NemoFile *file); static const char * nemo_file_peek_display_name_collation_key (NemoFile *file); static void file_mount_unmounted (GMount *mount, gpointer data); static void metadata_hash_free (GHashTable *hash); static void invalidate_thumbnail (NemoFile *file); G_DEFINE_TYPE_WITH_CODE (NemoFile, nemo_file, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (NEMO_TYPE_FILE_INFO, nemo_file_info_iface_init)); static void nemo_file_init (NemoFile *file) { file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NEMO_TYPE_FILE, NemoFileDetails); file->details->desktop_monitor = -1; file->details->cached_position_x = -1; file->details->cached_position_y = -1; file->details->pinning = FILE_PINNING_UNKNOWN; nemo_file_clear_info (file); nemo_file_invalidate_extension_info_internal (file); file->details->free_space = -1; } static GObject* nemo_file_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; NemoFile *file; object = (* G_OBJECT_CLASS (nemo_file_parent_class)->constructor) (type, n_construct_properties, construct_params); file = NEMO_FILE (object); /* Set to default type after full construction */ if (NEMO_FILE_GET_CLASS (file)->default_file_type != G_FILE_TYPE_UNKNOWN) { file->details->type = NEMO_FILE_GET_CLASS (file)->default_file_type; } return object; } gboolean nemo_file_set_display_name (NemoFile *file, const char *display_name, const char *edit_name, gboolean custom) { gboolean changed; if (custom && display_name == NULL) { /* We're re-setting a custom display name, invalidate it if we already set it so that the old one is re-read */ if (file->details->got_custom_display_name) { file->details->got_custom_display_name = FALSE; nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO); } return FALSE; } if (display_name == NULL || *display_name == 0) { return FALSE; } if (!custom && file->details->got_custom_display_name) { return FALSE; } if (edit_name == NULL) { edit_name = display_name; } changed = FALSE; if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), display_name) != 0) { changed = TRUE; eel_ref_str_unref (file->details->display_name); if (g_strcmp0 (eel_ref_str_peek (file->details->name), display_name) == 0) { file->details->display_name = eel_ref_str_ref (file->details->name); } else { file->details->display_name = eel_ref_str_new (display_name); } g_free (file->details->display_name_collation_key); file->details->display_name_collation_key = g_utf8_collate_key_for_filename (display_name, -1); } if (g_strcmp0 (eel_ref_str_peek (file->details->edit_name), edit_name) != 0) { changed = TRUE; eel_ref_str_unref (file->details->edit_name); if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), edit_name) == 0) { file->details->edit_name = eel_ref_str_ref (file->details->display_name); } else { file->details->edit_name = eel_ref_str_new (edit_name); } } file->details->got_custom_display_name = custom; return changed; } static void nemo_file_clear_display_name (NemoFile *file) { eel_ref_str_unref (file->details->display_name); file->details->display_name = NULL; g_free (file->details->display_name_collation_key); file->details->display_name_collation_key = NULL; eel_ref_str_unref (file->details->edit_name); file->details->edit_name = NULL; } static gboolean foreach_metadata_free (gpointer key, gpointer value, gpointer user_data) { guint id; id = GPOINTER_TO_UINT (key); if (id & METADATA_ID_IS_LIST_MASK) { g_strfreev ((char **)value); } else { g_free ((char *)value); } return TRUE; } static void metadata_hash_free (GHashTable *hash) { g_hash_table_foreach_remove (hash, foreach_metadata_free, NULL); g_hash_table_destroy (hash); } static gboolean metadata_hash_equal (GHashTable *hash1, GHashTable *hash2) { GHashTableIter iter; gpointer key1, value1, value2; guint id; if (hash1 == NULL && hash2 == NULL) { return TRUE; } if (hash1 == NULL || hash2 == NULL) { return FALSE; } if (g_hash_table_size (hash1) != g_hash_table_size (hash2)) { return FALSE; } g_hash_table_iter_init (&iter, hash1); while (g_hash_table_iter_next (&iter, &key1, &value1)) { value2 = g_hash_table_lookup (hash2, key1); if (value2 == NULL) { return FALSE; } id = GPOINTER_TO_UINT (key1); if (id & METADATA_ID_IS_LIST_MASK) { if (!eel_g_strv_equal ((char **)value1, (char **)value2)) { return FALSE; } } else { if (strcmp ((char *)value1, (char *)value2) != 0) { return FALSE; } } } return TRUE; } static void clear_metadata (NemoFile *file) { if (file->details->metadata) { metadata_hash_free (file->details->metadata); file->details->metadata = NULL; } } static GHashTable * get_metadata_from_info (GFileInfo *info) { GHashTable *metadata; char **attrs; guint id; int i; GFileAttributeType type; gpointer value; attrs = g_file_info_list_attributes (info, "metadata"); metadata = g_hash_table_new (NULL, NULL); for (i = 0; attrs[i] != NULL; i++) { id = nemo_metadata_get_id (attrs[i] + strlen ("metadata::")); if (id == 0) { continue; } if (!g_file_info_get_attribute_data (info, attrs[i], &type, &value, NULL)) { continue; } if (type == G_FILE_ATTRIBUTE_TYPE_STRING) { g_hash_table_insert (metadata, GUINT_TO_POINTER (id), g_strdup ((char *)value)); } else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV) { id |= METADATA_ID_IS_LIST_MASK; g_hash_table_insert (metadata, GUINT_TO_POINTER (id), g_strdupv ((char **)value)); } } g_strfreev (attrs); return metadata; } gboolean nemo_file_update_metadata_from_info (NemoFile *file, GFileInfo *info) { gboolean changed = FALSE; if (g_file_info_has_namespace (info, "metadata")) { GHashTable *metadata; metadata = get_metadata_from_info (info); if (!metadata_hash_equal (metadata, file->details->metadata)) { changed = TRUE; clear_metadata (file); file->details->metadata = metadata; } else { metadata_hash_free (metadata); } } else if (file->details->metadata) { changed = TRUE; clear_metadata (file); } return changed; } void nemo_file_clear_info (NemoFile *file) { file->details->got_file_info = FALSE; if (file->details->get_info_error) { g_error_free (file->details->get_info_error); file->details->get_info_error = NULL; } /* Reset to default type, which might be other than unknown for special kinds of files like the desktop or a search directory */ file->details->type = NEMO_FILE_GET_CLASS (file)->default_file_type; if (!file->details->got_custom_display_name) { nemo_file_clear_display_name (file); } if (!file->details->got_custom_activation_uri && file->details->activation_uri != NULL) { g_free (file->details->activation_uri); file->details->activation_uri = NULL; } if (file->details->icon != NULL) { g_object_unref (file->details->icon); file->details->icon = NULL; } g_clear_object (&file->details->thumbnail); g_free (file->details->thumbnail_path); file->details->thumbnail_path = NULL; file->details->thumbnailing_failed = FALSE; file->details->thumbnail_throttle_count = 1; file->details->last_thumbnail_try_mtime = 0; file->details->is_launcher = FALSE; file->details->is_foreign_link = FALSE; file->details->is_trusted_link = FALSE; file->details->is_symlink = FALSE; file->details->is_hidden = FALSE; file->details->is_mountpoint = FALSE; file->details->uid = -1; file->details->gid = -1; file->details->can_read = TRUE; file->details->can_write = TRUE; file->details->can_execute = TRUE; file->details->can_delete = TRUE; file->details->can_trash = TRUE; file->details->can_rename = TRUE; file->details->can_mount = FALSE; file->details->can_unmount = FALSE; file->details->can_eject = FALSE; file->details->can_start = FALSE; file->details->can_start_degraded = FALSE; file->details->can_stop = FALSE; file->details->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; file->details->can_poll_for_media = FALSE; file->details->is_media_check_automatic = FALSE; file->details->has_permissions = FALSE; file->details->permissions = 0; file->details->size = -1; file->details->sort_order = 0; file->details->mtime = 0; file->details->atime = 0; file->details->ctime = 0; file->details->btime = 0; file->details->trash_time = 0; g_free (file->details->symlink_name); file->details->symlink_name = NULL; eel_ref_str_unref (file->details->mime_type); file->details->mime_type = NULL; g_free (file->details->selinux_context); file->details->selinux_context = NULL; g_free (file->details->description); file->details->description = NULL; eel_ref_str_unref (file->details->owner); file->details->owner = NULL; eel_ref_str_unref (file->details->owner_real); file->details->owner_real = NULL; eel_ref_str_unref (file->details->group); file->details->group = NULL; eel_ref_str_unref (file->details->filesystem_id); file->details->filesystem_id = NULL; file->details->is_desktop_orphan = FALSE; file->details->desktop_monitor = -1; clear_metadata (file); } static NemoFile * nemo_file_new_from_filename (NemoDirectory *directory, const char *filename, gboolean self_owned) { NemoFile *file; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (filename != NULL); g_assert (filename[0] != '\0'); if (NEMO_IS_DESKTOP_DIRECTORY (directory)) { if (self_owned) { file = NEMO_FILE (g_object_new (NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NULL)); } else { /* This doesn't normally happen, unless the user somehow types in a uri * that references a file like this. (See #349840) */ file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL)); } } else if (NEMO_IS_SEARCH_DIRECTORY (directory)) { if (self_owned) { file = NEMO_FILE (g_object_new (NEMO_TYPE_SEARCH_DIRECTORY_FILE, NULL)); } else { /* This doesn't normally happen, unless the user somehow types in a uri * that references a file like this. (See #349840) */ file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL)); } } else if (g_str_has_suffix (filename, NEMO_SAVED_SEARCH_EXTENSION)) { file = NEMO_FILE (g_object_new (NEMO_TYPE_SAVED_SEARCH_FILE, NULL)); } else { file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL)); } file->details->directory = nemo_directory_ref (directory); file->details->name = eel_ref_str_new (filename); #ifdef NEMO_FILE_DEBUG_REF DEBUG_REF_PRINTF("%10p ref'd", file); #endif return file; } static void modify_link_hash_table (NemoFile *file, ModifyListFunction modify_function) { char *target_uri; gboolean found; gpointer original_key; GList **list_ptr; /* Check if there is a symlink name. If none, we are OK. */ if (file->details->symlink_name == NULL) { return; } /* Create the hash table first time through. */ if (symbolic_links == NULL) { symbolic_links = g_hash_table_new (g_str_hash, g_str_equal); } target_uri = nemo_file_get_symbolic_link_target_uri (file); /* Find the old contents of the hash table. */ found = g_hash_table_lookup_extended (symbolic_links, target_uri, &original_key, (gpointer *)&list_ptr); if (!found) { list_ptr = g_new0 (GList *, 1); original_key = g_strdup (target_uri); g_hash_table_insert (symbolic_links, original_key, list_ptr); } (* modify_function) (list_ptr, file); if (*list_ptr == NULL) { g_hash_table_remove (symbolic_links, target_uri); g_free (list_ptr); g_free (original_key); } g_free (target_uri); } static void symbolic_link_weak_notify (gpointer data, GObject *where_the_object_was) { GList **list = data; /* This really shouldn't happen, but we're seeing some strange things in bug #358172 where the symlink hashtable isn't correctly updated. */ *list = g_list_remove (*list, where_the_object_was); } static void add_to_link_hash_table_list (GList **list, NemoFile *file) { if (g_list_find (*list, file) != NULL) { g_warning ("Adding file to symlink_table multiple times. " "Please add feedback of what you were doing at http://bugzilla.gnome.org/show_bug.cgi?id=358172\n"); return; } g_object_weak_ref (G_OBJECT (file), symbolic_link_weak_notify, list); *list = g_list_prepend (*list, file); } static void add_to_link_hash_table (NemoFile *file) { modify_link_hash_table (file, add_to_link_hash_table_list); } static void remove_from_link_hash_table_list (GList **list, NemoFile *file) { if (g_list_find (*list, file) != NULL) { g_object_weak_unref (G_OBJECT (file), symbolic_link_weak_notify, list); *list = g_list_remove (*list, file); } } static void remove_from_link_hash_table (NemoFile *file) { modify_link_hash_table (file, remove_from_link_hash_table_list); } NemoFile * nemo_file_new_from_info (NemoDirectory *directory, GFileInfo *info) { NemoFile *file; const char *mime_type; g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL); g_return_val_if_fail (info != NULL, NULL); mime_type = g_file_info_get_content_type (info); if (mime_type && strcmp (mime_type, NEMO_SAVED_SEARCH_MIMETYPE) == 0) { g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY); file = NEMO_FILE (g_object_new (NEMO_TYPE_SAVED_SEARCH_FILE, NULL)); } else { file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL)); } file->details->directory = nemo_directory_ref (directory); update_info_and_name (file, info); #ifdef NEMO_FILE_DEBUG_REF DEBUG_REF_PRINTF("%10p ref'd", file); #endif return file; } static NemoFile * nemo_file_get_internal (GFile *location, gboolean create) { gboolean self_owned; NemoDirectory *directory; NemoFile *file; GFile *parent; char *basename; g_assert (location != NULL); parent = g_file_get_parent (location); self_owned = FALSE; if (parent == NULL) { self_owned = TRUE; parent = g_object_ref (location); } /* Get object that represents the directory. */ directory = nemo_directory_get_internal (parent, create); g_object_unref (parent); /* Get the name for the file. */ if (self_owned && directory != NULL) { basename = nemo_directory_get_name_for_self_as_new_file (directory); } else { basename = g_file_get_basename (location); } /* Check to see if it's a file that's already known. */ if (directory == NULL) { file = NULL; } else if (self_owned) { file = directory->details->as_file; } else { file = nemo_directory_find_file_by_name (directory, basename); } /* Ref or create the file. */ if (file != NULL) { nemo_file_ref (file); } else if (create && directory != NULL) { file = nemo_file_new_from_filename (directory, basename, self_owned); if (self_owned) { g_assert (directory->details->as_file == NULL); directory->details->as_file = file; } else { nemo_directory_add_file (directory, file); } } g_free (basename); nemo_directory_unref (directory); return file; } NemoFile * nemo_file_get (GFile *location) { return nemo_file_get_internal (location, TRUE); } NemoFile * nemo_file_get_existing (GFile *location) { return nemo_file_get_internal (location, FALSE); } NemoFile * nemo_file_get_existing_by_uri (const char *uri) { GFile *location; NemoFile *file; location = g_file_new_for_uri (uri); file = nemo_file_get_internal (location, FALSE); g_object_unref (location); return file; } NemoFile * nemo_file_get_by_uri (const char *uri) { GFile *location; NemoFile *file; location = g_file_new_for_uri (uri); file = nemo_file_get_internal (location, TRUE); g_object_unref (location); return file; } gboolean nemo_file_is_self_owned (NemoFile *file) { return file->details->directory->details->as_file == file; } static void finalize (GObject *object) { NemoDirectory *directory; NemoFile *file; char *uri; file = NEMO_FILE (object); g_assert (file->details->operations_in_progress == NULL); if (file->details->is_thumbnailing) { uri = nemo_file_get_uri (file); nemo_thumbnail_remove_from_queue (uri); g_free (uri); } nemo_async_destroying_file (file); remove_from_link_hash_table (file); directory = file->details->directory; if (nemo_file_is_self_owned (file)) { directory->details->as_file = NULL; } else { if (!file->details->is_gone) { nemo_directory_remove_file (directory, file); } } if (file->details->get_info_error) { g_error_free (file->details->get_info_error); } nemo_directory_unref (directory); eel_ref_str_unref (file->details->name); eel_ref_str_unref (file->details->display_name); g_free (file->details->display_name_collation_key); eel_ref_str_unref (file->details->edit_name); if (file->details->icon) { g_object_unref (file->details->icon); } g_free (file->details->thumbnail_path); g_free (file->details->symlink_name); eel_ref_str_unref (file->details->mime_type); eel_ref_str_unref (file->details->owner); eel_ref_str_unref (file->details->owner_real); eel_ref_str_unref (file->details->group); g_free (file->details->selinux_context); g_free (file->details->description); g_free (file->details->activation_uri); g_clear_object (&file->details->custom_icon); g_clear_object (&file->details->thumbnail); if (file->details->mount) { g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file); g_object_unref (file->details->mount); } eel_ref_str_unref (file->details->filesystem_id); g_free (file->details->trash_orig_path); g_list_free_full (file->details->mime_list, g_free); g_list_free_full (file->details->pending_extension_emblems, g_free); g_list_free_full (file->details->extension_emblems, g_free); g_list_free_full (file->details->pending_info_providers, g_object_unref); if (file->details->pending_extension_attributes) { g_hash_table_destroy (file->details->pending_extension_attributes); } if (file->details->extension_attributes) { g_hash_table_destroy (file->details->extension_attributes); } if (file->details->metadata) { metadata_hash_free (file->details->metadata); } G_OBJECT_CLASS (nemo_file_parent_class)->finalize (object); } NemoFile * nemo_file_ref (NemoFile *file) { if (file == NULL) { return NULL; } g_return_val_if_fail (NEMO_IS_FILE (file), NULL); #ifdef NEMO_FILE_DEBUG_REF DEBUG_REF_PRINTF("%10p ref'd", file); #endif return g_object_ref (file); } void nemo_file_unref (NemoFile *file) { if (file == NULL) { return; } g_return_if_fail (NEMO_IS_FILE (file)); #ifdef NEMO_FILE_DEBUG_REF DEBUG_REF_PRINTF("%10p unref'd", file); #endif g_object_unref (file); } /** * nemo_file_get_parent_uri_for_display: * * Get the uri for the parent directory. * * @file: The file in question. * * Return value: A string representing the parent's location, * formatted for user display (including stripping "file://"). * If the parent is NULL, returns the empty string. */ char * nemo_file_get_parent_uri_for_display (NemoFile *file) { GFile *parent; char *result; g_assert (NEMO_IS_FILE (file)); parent = nemo_file_get_parent_location (file); if (parent) { result = g_file_get_parse_name (parent); g_object_unref (parent); } else { result = g_strdup (""); } return result; } /** * nemo_file_get_parent_uri: * * Get the uri for the parent directory. * * @file: The file in question. * * Return value: A string for the parent's location, in "raw URI" form. * Use nemo_file_get_parent_uri_for_display instead if the * result is to be displayed on-screen. * If the parent is NULL, returns the empty string. */ char * nemo_file_get_parent_uri (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_self_owned (file)) { /* Callers expect an empty string, not a NULL. */ return g_strdup (""); } return nemo_directory_get_uri (file->details->directory); } GFile * nemo_file_get_parent_location (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_self_owned (file)) { /* Callers expect an empty string, not a NULL. */ return NULL; } return nemo_directory_get_location (file->details->directory); } NemoFile * nemo_file_get_parent (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_self_owned (file)) { return NULL; } return nemo_directory_get_corresponding_file (file->details->directory); } /** * nemo_file_can_read: * * Check whether the user is allowed to read the contents of this file. * * @file: The file to check. * * Return value: FALSE if the user is definitely not allowed to read * the contents of the file. If the user has read permission, or * the code can't tell whether the user has read permission, * returns TRUE (so failures must always be handled). */ gboolean nemo_file_can_read (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->can_read; } /** * nemo_file_can_write: * * Check whether the user is allowed to write to this file. * * @file: The file to check. * * Return value: FALSE if the user is definitely not allowed to write * to the file. If the user has write permission, or * the code can't tell whether the user has write permission, * returns TRUE (so failures must always be handled). */ gboolean nemo_file_can_write (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->can_write; } /** * nemo_file_can_execute: * * Check whether the user is allowed to execute this file. * * @file: The file to check. * * Return value: FALSE if the user is definitely not allowed to execute * the file. If the user has execute permission, or * the code can't tell whether the user has execute permission, * returns TRUE (so failures must always be handled). */ gboolean nemo_file_can_execute (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->can_execute; } gboolean nemo_file_can_mount (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->can_mount; } gboolean nemo_file_can_unmount (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (getenv("LTSP_CLIENT")) { return FALSE; } return file->details->can_unmount || (file->details->mount != NULL && g_mount_can_unmount (file->details->mount)); } gboolean nemo_file_can_eject (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (getenv("LTSP_CLIENT")) { return FALSE; } return file->details->can_eject || (file->details->mount != NULL && g_mount_can_eject (file->details->mount)); } gboolean nemo_file_can_start (NemoFile *file) { gboolean ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = FALSE; if (file->details->can_start) { ret = TRUE; goto out; } if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_can_start (drive); g_object_unref (drive); } } out: return ret; } gboolean nemo_file_can_start_degraded (NemoFile *file) { gboolean ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = FALSE; if (file->details->can_start_degraded) { ret = TRUE; goto out; } if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_can_start_degraded (drive); g_object_unref (drive); } } out: return ret; } gboolean nemo_file_can_poll_for_media (NemoFile *file) { gboolean ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = FALSE; if (file->details->can_poll_for_media) { ret = TRUE; goto out; } if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_can_poll_for_media (drive); g_object_unref (drive); } } out: return ret; } gboolean nemo_file_is_media_check_automatic (NemoFile *file) { gboolean ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = FALSE; if (file->details->is_media_check_automatic) { ret = TRUE; goto out; } if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_is_media_check_automatic (drive); g_object_unref (drive); } } out: return ret; } gboolean nemo_file_can_stop (NemoFile *file) { gboolean ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = FALSE; if (file->details->can_stop) { ret = TRUE; goto out; } if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_can_stop (drive); g_object_unref (drive); } } out: return ret; } GDriveStartStopType nemo_file_get_start_stop_type (NemoFile *file) { GDriveStartStopType ret; GDrive *drive; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); ret = file->details->start_stop_type; if (ret != G_DRIVE_START_STOP_TYPE_UNKNOWN) goto out; if (file->details->mount != NULL) { drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { ret = g_drive_get_start_stop_type (drive); g_object_unref (drive); } } out: return ret; } void nemo_file_mount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; if (NEMO_FILE_GET_CLASS (file)->mount == NULL) { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be mounted")); callback (file, NULL, error, callback_data); g_error_free (error); } } else { NEMO_FILE_GET_CLASS (file)->mount (file, mount_op, cancellable, callback, callback_data); } } typedef struct { NemoFile *file; NemoFileOperationCallback callback; gpointer callback_data; } UnmountData; static void unmount_done (void *callback_data) { UnmountData *data; data = (UnmountData *)callback_data; if (data->callback) { data->callback (data->file, NULL, NULL, data->callback_data); } nemo_file_unref (data->file); g_free (data); } void nemo_file_unmount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; UnmountData *data; if (file->details->can_unmount) { if (NEMO_FILE_GET_CLASS (file)->unmount != NULL) { NEMO_FILE_GET_CLASS (file)->unmount (file, mount_op, cancellable, callback, callback_data); } else { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be unmounted")); callback (file, NULL, error, callback_data); g_error_free (error); } } } else if (file->details->mount != NULL && g_mount_can_unmount (file->details->mount)) { data = g_new0 (UnmountData, 1); data->file = nemo_file_ref (file); data->callback = callback; data->callback_data = callback_data; nemo_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, FALSE, TRUE, unmount_done, data); } else if (callback) { callback (file, NULL, NULL, callback_data); } } void nemo_file_eject (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; UnmountData *data; if (file->details->can_eject) { if (NEMO_FILE_GET_CLASS (file)->eject != NULL) { NEMO_FILE_GET_CLASS (file)->eject (file, mount_op, cancellable, callback, callback_data); } else { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be ejected")); callback (file, NULL, error, callback_data); g_error_free (error); } } } else if (file->details->mount != NULL && g_mount_can_eject (file->details->mount)) { data = g_new0 (UnmountData, 1); data->file = nemo_file_ref (file); data->callback = callback; data->callback_data = callback_data; nemo_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, TRUE, TRUE, unmount_done, data); } else if (callback) { callback (file, NULL, NULL, callback_data); } } void nemo_file_start (NemoFile *file, GMountOperation *start_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; if ((file->details->can_start || file->details->can_start_degraded) && NEMO_FILE_GET_CLASS (file)->start != NULL) { NEMO_FILE_GET_CLASS (file)->start (file, start_op, cancellable, callback, callback_data); } else { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be started")); callback (file, NULL, error, callback_data); g_error_free (error); } } } static void file_stop_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean stopped; GError *error; op = callback_data; error = NULL; stopped = g_drive_stop_finish (G_DRIVE (source_object), res, &error); if (!stopped && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, NULL, error); if (error) { g_error_free (error); } } void nemo_file_stop (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; if (NEMO_FILE_GET_CLASS (file)->stop != NULL) { if (file->details->can_stop) { NEMO_FILE_GET_CLASS (file)->stop (file, mount_op, cancellable, callback, callback_data); } else { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be stopped")); callback (file, NULL, error, callback_data); g_error_free (error); } } } else { GDrive *drive; drive = NULL; if (file->details->mount != NULL) drive = g_mount_get_drive (file->details->mount); if (drive != NULL && g_drive_can_stop (drive)) { NemoFileOperation *op; op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, mount_op, op->cancellable, file_stop_callback, op); } else { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be stopped")); callback (file, NULL, error, callback_data); g_error_free (error); } } if (drive != NULL) { g_object_unref (drive); } } } void nemo_file_poll_for_media (NemoFile *file) { if (file->details->can_poll_for_media) { if (NEMO_FILE_GET_CLASS (file)->stop != NULL) { NEMO_FILE_GET_CLASS (file)->poll_for_media (file); } } else if (file->details->mount != NULL) { GDrive *drive; drive = g_mount_get_drive (file->details->mount); if (drive != NULL) { g_drive_poll_for_media (drive, NULL, /* cancellable */ NULL, /* GAsyncReadyCallback */ NULL); /* user_data */ g_object_unref (drive); } } } /** * nemo_file_is_desktop_directory: * * Check whether this file is the desktop directory. * * @file: The file to check. * * Return value: TRUE if this is the physical desktop directory. */ gboolean nemo_file_is_desktop_directory (NemoFile *file) { GFile *dir; dir = file->details->directory->details->location; if (dir == NULL) { return FALSE; } return nemo_is_desktop_directory_file (dir, eel_ref_str_peek (file->details->name)); } static gboolean is_desktop_file (NemoFile *file) { return nemo_file_is_mime_type (file, "application/x-desktop"); } static gboolean can_rename_desktop_file (NemoFile *file) { GFile *location; gboolean res; location = nemo_file_get_location (file); res = g_file_is_native (location); g_object_unref (location); return res; } /** * nemo_file_can_rename: * * Check whether the user is allowed to change the name of the file. * * @file: The file to check. * * Return value: FALSE if the user is definitely not allowed to change * the name of the file. If the user is allowed to change the name, or * the code can't tell whether the user is allowed to change the name, * returns TRUE (so rename failures must always be handled). */ gboolean nemo_file_can_rename (NemoFile *file) { gboolean can_rename; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); /* Nonexistent files can't be renamed. */ if (nemo_file_is_gone (file)) { return FALSE; } /* Self-owned files can't be renamed */ if (nemo_file_is_self_owned (file)) { return FALSE; } if ((is_desktop_file (file) && !can_rename_desktop_file (file)) || nemo_file_is_home (file)) { return FALSE; } can_rename = TRUE; /* Certain types of links can't be renamed */ if (NEMO_IS_DESKTOP_ICON_FILE (file)) { NemoDesktopLink *link; link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); if (link != NULL) { can_rename = nemo_desktop_link_can_rename (link); g_object_unref (link); } } if (!can_rename) { return FALSE; } return file->details->can_rename; } gboolean nemo_file_can_delete (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); /* Nonexistent files can't be deleted. */ if (nemo_file_is_gone (file)) { return FALSE; } /* Self-owned files can't be deleted */ if (nemo_file_is_self_owned (file)) { return FALSE; } return file->details->can_delete; } gboolean nemo_file_can_trash (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); /* Nonexistent files can't be deleted. */ if (nemo_file_is_gone (file)) { return FALSE; } /* Self-owned files can't be deleted */ if (nemo_file_is_self_owned (file)) { return FALSE; } return file->details->can_trash; } GFile * nemo_file_get_location (NemoFile *file) { GFile *dir; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); dir = file->details->directory->details->location; if (nemo_file_is_self_owned (file)) { return g_object_ref (dir); } return g_file_get_child (dir, eel_ref_str_peek (file->details->name)); } /* Return the actual uri associated with the passed-in file. */ char * nemo_file_get_uri (NemoFile *file) { char *uri; GFile *loc; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); loc = nemo_file_get_location (file); uri = g_file_get_uri (loc); g_object_unref (loc); return uri; } /* Return the actual path associated with the passed-in file. */ char * nemo_file_get_path (NemoFile *file) { char *path; GFile *loc; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); loc = nemo_file_get_location (file); path = g_file_get_path (loc); g_object_unref (loc); return path; } char * nemo_file_get_uri_scheme (NemoFile *file) { GFile *loc; char *scheme; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (file->details->directory == NULL || file->details->directory->details->location == NULL) { return NULL; } loc = nemo_directory_get_location (file->details->directory); scheme = g_file_get_uri_scheme (loc); g_object_unref (loc); return scheme; } NemoFileOperation * nemo_file_operation_new (NemoFile *file, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; op = g_new0 (NemoFileOperation, 1); op->file = nemo_file_ref (file); op->callback = callback; op->callback_data = callback_data; op->cancellable = g_cancellable_new (); op->file->details->operations_in_progress = g_list_prepend (op->file->details->operations_in_progress, op); return op; } static void nemo_file_operation_remove (NemoFileOperation *op) { op->file->details->operations_in_progress = g_list_remove (op->file->details->operations_in_progress, op); } void nemo_file_operation_free (NemoFileOperation *op) { nemo_file_operation_remove (op); nemo_file_unref (op->file); g_object_unref (op->cancellable); if (op->free_data) { op->free_data (op->data); } if (op->undo_info != NULL) { nemo_file_undo_manager_set_action (op->undo_info); } g_free (op); } void nemo_file_operation_complete (NemoFileOperation *op, GFile *result_file, GError *error) { /* Claim that something changed even if the operation failed. * This makes it easier for some clients who see the "reverting" * as "changing back". */ nemo_file_operation_remove (op); nemo_file_changed (op->file); if (op->callback) { (* op->callback) (op->file, result_file, error, op->callback_data); } nemo_file_operation_free (op); } void nemo_file_operation_cancel (NemoFileOperation *op) { /* Cancel the operation if it's still in progress. */ g_cancellable_cancel (op->cancellable); } static void rename_get_info_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; NemoDirectory *directory; NemoFile *existing_file; char *old_name; char *old_uri; char *new_uri; const char *new_name; GFileInfo *new_info; GError *error; op = callback_data; error = NULL; new_info = g_file_query_info_finish (G_FILE (source_object), res, &error); if (new_info != NULL) { directory = op->file->details->directory; new_name = g_file_info_get_name (new_info); /* If there was another file by the same name in this * directory and it is not the same file that we are * renaming, mark it gone. */ existing_file = nemo_directory_find_file_by_name (directory, new_name); if (existing_file != NULL && existing_file != op->file) { nemo_file_mark_gone (existing_file); nemo_file_changed (existing_file); } old_uri = nemo_file_get_uri (op->file); old_name = g_strdup (eel_ref_str_peek (op->file->details->name)); update_info_and_name (op->file, new_info); g_free (old_name); new_uri = nemo_file_get_uri (op->file); nemo_directory_moved (old_uri, new_uri); g_free (new_uri); g_free (old_uri); /* the rename could have affected the display name if e.g. * we're in a vfolder where the name comes from a desktop file * and a rename affects the contents of the desktop file. */ if (op->file->details->got_custom_display_name) { nemo_file_invalidate_attributes (op->file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO); } g_object_unref (new_info); } nemo_file_operation_complete (op, NULL, error); if (error) { g_error_free (error); } } static void rename_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; GFile *new_file; GError *error; op = callback_data; error = NULL; new_file = g_file_set_display_name_finish (G_FILE (source_object), res, &error); if (new_file != NULL) { if (op->undo_info != NULL) { nemo_file_undo_info_rename_set_data_post (NEMO_FILE_UNDO_INFO_RENAME (op->undo_info), new_file); } g_file_query_info_async (new_file, NEMO_FILE_DEFAULT_ATTRIBUTES, 0, G_PRIORITY_DEFAULT, op->cancellable, rename_get_info_callback, op); } else { nemo_file_operation_complete (op, NULL, error); g_error_free (error); } } static gboolean name_is (NemoFile *file, const char *new_name) { const char *old_name; old_name = eel_ref_str_peek (file->details->name); return strcmp (new_name, old_name) == 0; } void nemo_file_rename (NemoFile *file, const char *new_name, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; char *uri; char *old_name; char *new_file_name; gboolean success, name_changed; gboolean is_renameable_desktop_file; GFile *location; GError *error; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (new_name != NULL); g_return_if_fail (callback != NULL); is_renameable_desktop_file = is_desktop_file (file) && can_rename_desktop_file (file); /* Return an error for incoming names containing path separators. * But not for .desktop files as '/' are allowed for them */ if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) { error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Slashes are not allowed in filenames")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* Can't rename a file that's already gone. * We need to check this here because there may be a new * file with the same name. */ if (nemo_file_is_gone (file)) { /* Claim that something changed even if the rename * failed. This makes it easier for some clients who * see the "reverting" to the old name as "changing * back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("File not found")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* Test the name-hasn't-changed case explicitly, for two reasons. * (1) rename returns an error if new & old are same. * (2) We don't want to send file-changed signal if nothing changed. */ if (!NEMO_IS_DESKTOP_ICON_FILE (file) && !is_renameable_desktop_file && name_is (file, new_name)) { (* callback) (file, NULL, NULL, callback_data); return; } /* Self-owned files can't be renamed. Test the name-not-actually-changing * case before this case. */ if (nemo_file_is_self_owned (file)) { /* Claim that something changed even if the rename * failed. This makes it easier for some clients who * see the "reverting" to the old name as "changing * back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Toplevel files cannot be renamed")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } if (NEMO_IS_DESKTOP_ICON_FILE (file)) { NemoDesktopLink *link; link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); old_name = nemo_file_get_display_name (file); if ((old_name != NULL && strcmp (new_name, old_name) == 0)) { success = TRUE; } else { success = (link != NULL && nemo_desktop_link_rename (link, new_name)); } if (success) { (* callback) (file, NULL, NULL, callback_data); } else { error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unable to rename desktop icon")); (* callback) (file, NULL, error, callback_data); g_error_free (error); } g_free (old_name); g_object_unref (link); return; } if (is_renameable_desktop_file) { /* Don't actually change the name if the new name is the same. * This helps for the vfolder method where this can happen and * we want to minimize actual changes */ uri = nemo_file_get_uri (file); old_name = nemo_link_local_get_text (uri); if (old_name != NULL && strcmp (new_name, old_name) == 0) { success = TRUE; name_changed = FALSE; } else { success = nemo_link_local_set_text (uri, new_name); name_changed = TRUE; } g_free (old_name); g_free (uri); if (!success) { error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unable to rename desktop file")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } if (g_str_has_suffix (new_name, ".desktop")) { new_file_name = g_strdup (new_name); } else { new_file_name = g_strdup_printf ("%s.desktop", new_name); } new_file_name = g_strdelimit (new_file_name, "/", '-'); if (name_is (file, new_file_name)) { if (name_changed) { nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO); } (* callback) (file, NULL, NULL, callback_data); g_free (new_file_name); return; } } else { new_file_name = g_strdup (new_name); } /* Set up a renaming operation. */ op = nemo_file_operation_new (file, callback, callback_data); op->is_rename = TRUE; location = nemo_file_get_location (file); /* Tell the undo manager a rename is taking place */ if (!nemo_file_undo_manager_pop_flag ()) { op->undo_info = nemo_file_undo_info_rename_new (); old_name = nemo_file_get_display_name (file); nemo_file_undo_info_rename_set_data_pre (NEMO_FILE_UNDO_INFO_RENAME (op->undo_info), location, old_name, new_file_name); g_free (old_name); } /* Do the renaming. */ g_file_set_display_name_async (location, new_file_name, G_PRIORITY_DEFAULT, op->cancellable, rename_callback, op); g_free (new_file_name); g_object_unref (location); } gboolean nemo_file_rename_in_progress (NemoFile *file) { GList *node; NemoFileOperation *op; for (node = file->details->operations_in_progress; node != NULL; node = node->next) { op = node->data; if (op->is_rename) { return TRUE; } } return FALSE; } void nemo_file_cancel (NemoFile *file, NemoFileOperationCallback callback, gpointer callback_data) { GList *node, *next; NemoFileOperation *op; for (node = file->details->operations_in_progress; node != NULL; node = next) { next = node->next; op = node->data; g_assert (op->file == file); if (op->callback == callback && op->callback_data == callback_data) { nemo_file_operation_cancel (op); } } } gboolean nemo_file_matches_uri (NemoFile *file, const char *match_uri) { GFile *match_file, *location; gboolean result; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); g_return_val_if_fail (match_uri != NULL, FALSE); location = nemo_file_get_location (file); match_file = g_file_new_for_uri (match_uri); result = g_file_equal (location, match_file); g_object_unref (location); g_object_unref (match_file); return result; } int nemo_file_compare_location (NemoFile *file_1, NemoFile *file_2) { GFile *loc_a, *loc_b; gboolean res; loc_a = nemo_file_get_location (file_1); loc_b = nemo_file_get_location (file_2); res = !g_file_equal (loc_a, loc_b); g_object_unref (loc_a); g_object_unref (loc_b); return (gint) res; } gboolean nemo_file_is_local (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return nemo_directory_is_local (file->details->directory); } static void update_link (NemoFile *link_file, NemoFile *target_file) { g_assert (NEMO_IS_FILE (link_file)); g_assert (NEMO_IS_FILE (target_file)); /* FIXME bugzilla.gnome.org 42044: If we don't put any code * here then the hash table is a waste of time. */ } static GList * get_link_files (NemoFile *target_file) { char *uri; GList **link_files; if (symbolic_links == NULL) { link_files = NULL; } else { uri = nemo_file_get_uri (target_file); link_files = g_hash_table_lookup (symbolic_links, uri); g_free (uri); if (link_files) { if (!nemo_file_is_symbolic_link (target_file)) { return nemo_file_list_copy (*link_files); } else { /* We keep a hash table of uri keys with lists of NemoFiles attached, to keep * track of what files point to a particular uri. * * When a file gets updated, it fetches the potential list of any files that * are actually links to itself. If our original file is also actually a symbolic * link that points to to one of these link files, we'll end up triggering a cyclic * update - one file triggers an update for the other, which in turn triggers an update * back to the original file, and so on. * * So we check if target_file is itself a link. If it is, we compare its symbolic * target location with the location of the returned link_files. We skip any that match * (meaning, any link-back files that are themselves the target of the current symbolic link * file. */ GList *derecursed = NULL; GList *l; l = *link_files; while (l != NULL) { NemoFile *link_file; gboolean add; add = TRUE; link_file = NEMO_FILE (l->data); if (nemo_file_is_symbolic_link (target_file)) { gchar *target_symlink_uri = nemo_file_get_symbolic_link_target_uri (target_file); gchar *link_uri = nemo_file_get_uri (link_file); GFile *target_symlink_gfile = g_file_new_for_uri (target_symlink_uri); GFile *link_gfile = g_file_new_for_uri (link_uri); if (g_file_equal (target_symlink_gfile, link_gfile)) { add = FALSE; } g_object_unref (target_symlink_gfile); g_object_unref (link_gfile); g_free (target_symlink_uri); g_free (link_uri); } if (add) { derecursed = g_list_prepend (derecursed, nemo_file_ref (link_file)); } l = l->next; } return derecursed; } } } return NULL; } static void update_links_if_target (NemoFile *target_file) { GList *link_files, *p; link_files = get_link_files (target_file); for (p = link_files; p != NULL; p = p->next) { update_link (NEMO_FILE (p->data), target_file); } nemo_file_list_free (link_files); } static guint64 cached_thumbnail_limit; int cached_thumbnail_size; double scaled_cached_thumbnail_size; static int show_image_thumbs; static gboolean access_ok (const gchar *path) { if (g_access (path, R_OK|W_OK) != 0) { if (errno != ENOENT && errno != EFAULT) { return FALSE; } } return TRUE; } static gboolean update_info_internal (NemoFile *file, GFileInfo *info, gboolean update_name) { GList *node; gboolean changed; gboolean is_symlink, is_hidden, is_mountpoint; gboolean has_permissions; guint32 permissions; gboolean can_read, can_write, can_execute, can_delete, can_trash, can_rename, can_mount, can_unmount, can_eject; gboolean can_start, can_start_degraded, can_stop, can_poll_for_media, is_media_check_automatic; GDriveStartStopType start_stop_type; gboolean thumbnailing_failed; int uid, gid; goffset size; int sort_order; time_t atime, mtime, ctime; time_t trash_time; GTimeVal g_trash_time; const char * time_string; const char *symlink_name, *selinux_context, *name, *thumbnail_path; char *mime_type; GFileType file_type; GIcon *icon; char *old_activation_uri; const char *activation_uri; const char *description; const char *filesystem_id; const char *trash_orig_path; const char *group, *owner, *owner_real; gboolean free_owner, free_group; if (file->details->is_gone) { return FALSE; } if (info == NULL) { nemo_file_mark_gone (file); return TRUE; } file->details->file_info_is_up_to_date = TRUE; file->details->thumbnail_access_problem = FALSE; file->details->pinning = FILE_PINNING_UNKNOWN; /* FIXME bugzilla.gnome.org 42044: Need to let links that * point to the old name know that the file has been renamed. */ remove_from_link_hash_table (file); changed = FALSE; if (!file->details->got_file_info) { changed = TRUE; } file->details->got_file_info = TRUE; changed |= nemo_file_set_display_name (file, g_file_info_get_display_name (info), g_file_info_get_edit_name (info), FALSE); file_type = g_file_info_get_file_type (info); if (file->details->type != file_type) { changed = TRUE; } file->details->type = file_type; if (!file->details->got_custom_activation_uri && !nemo_file_is_in_trash (file)) { activation_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); if (activation_uri == NULL) { if (file->details->activation_uri) { g_free (file->details->activation_uri); file->details->activation_uri = NULL; changed = TRUE; } } else { old_activation_uri = file->details->activation_uri; file->details->activation_uri = g_strdup (activation_uri); if (old_activation_uri) { if (strcmp (old_activation_uri, file->details->activation_uri) != 0) { changed = TRUE; } g_free (old_activation_uri); } else { changed = TRUE; } } } is_symlink = g_file_info_get_is_symlink (info); if (file->details->is_symlink != is_symlink) { changed = TRUE; } file->details->is_symlink = is_symlink; is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info); if (file->details->is_hidden != is_hidden) { changed = TRUE; } file->details->is_hidden = is_hidden; is_mountpoint = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT); if (file->details->is_mountpoint != is_mountpoint) { changed = TRUE; } file->details->is_mountpoint = is_mountpoint; has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE); permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);; if (file->details->has_permissions != has_permissions || file->details->permissions != permissions) { changed = TRUE; } file->details->has_permissions = has_permissions; file->details->permissions = permissions; /* We default to TRUE for this if we can't know */ can_read = TRUE; can_write = TRUE; can_execute = TRUE; can_delete = TRUE; can_trash = TRUE; can_rename = TRUE; can_mount = FALSE; can_unmount = FALSE; can_eject = FALSE; can_start = FALSE; can_start_degraded = FALSE; can_stop = FALSE; can_poll_for_media = FALSE; is_media_check_automatic = FALSE; start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) { can_read = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) { can_write = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) { can_execute = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) { can_delete = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) { can_trash = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)) { can_rename = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT)) { can_mount = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT)) { can_unmount = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT)) { can_eject = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START)) { can_start = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED)) { can_start_degraded = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP)) { can_stop = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE)) { start_stop_type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL)) { can_poll_for_media = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC)) { is_media_check_automatic = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC); } if (file->details->can_read != can_read || file->details->can_write != can_write || file->details->can_execute != can_execute || file->details->can_delete != can_delete || file->details->can_trash != can_trash || file->details->can_rename != can_rename || file->details->can_mount != can_mount || file->details->can_unmount != can_unmount || file->details->can_eject != can_eject || file->details->can_start != can_start || file->details->can_start_degraded != can_start_degraded || file->details->can_stop != can_stop || file->details->start_stop_type != start_stop_type || file->details->can_poll_for_media != can_poll_for_media || file->details->is_media_check_automatic != is_media_check_automatic) { changed = TRUE; } file->details->can_read = can_read; file->details->can_write = can_write; file->details->can_execute = can_execute; file->details->can_delete = can_delete; file->details->can_trash = can_trash; file->details->can_rename = can_rename; file->details->can_mount = can_mount; file->details->can_unmount = can_unmount; file->details->can_eject = can_eject; file->details->can_start = can_start; file->details->can_start_degraded = can_start_degraded; file->details->can_stop = can_stop; file->details->start_stop_type = start_stop_type; file->details->can_poll_for_media = can_poll_for_media; file->details->is_media_check_automatic = is_media_check_automatic; free_owner = FALSE; owner = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER); owner_real = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL); free_group = FALSE; group = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP); uid = -1; gid = -1; if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID)) { uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID); if (owner == NULL) { free_owner = TRUE; owner = g_strdup_printf ("%d", uid); } } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID)) { gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID); if (group == NULL) { free_group = TRUE; group = g_strdup_printf ("%d", gid); } } if (file->details->uid != uid || file->details->gid != gid) { changed = TRUE; } file->details->uid = uid; file->details->gid = gid; if (g_strcmp0 (eel_ref_str_peek (file->details->owner), owner) != 0) { changed = TRUE; eel_ref_str_unref (file->details->owner); file->details->owner = eel_ref_str_get_unique (owner); } if (g_strcmp0 (eel_ref_str_peek (file->details->owner_real), owner_real) != 0) { changed = TRUE; eel_ref_str_unref (file->details->owner_real); file->details->owner_real = eel_ref_str_get_unique (owner_real); } if (g_strcmp0 (eel_ref_str_peek (file->details->group), group) != 0) { changed = TRUE; eel_ref_str_unref (file->details->group); file->details->group = eel_ref_str_get_unique (group); } if (free_owner) { g_free ((char *)owner); } if (free_group) { g_free ((char *)group); } size = -1; if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) { size = g_file_info_get_size (info); } if (file->details->size != size) { changed = TRUE; } file->details->size = size; sort_order = g_file_info_get_sort_order (info); if (file->details->sort_order != sort_order) { changed = TRUE; } file->details->sort_order = sort_order; atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS); ctime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED); mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); if (file->details->atime != atime || file->details->mtime != mtime || file->details->ctime != ctime) { if (file->details->thumbnail == NULL) { file->details->thumbnail_is_up_to_date = FALSE; } changed = TRUE; } file->details->atime = atime; file->details->ctime = ctime; file->details->mtime = mtime; if (file->details->thumbnail != NULL && file->details->thumbnail_mtime != 0 && file->details->thumbnail_mtime != mtime) { file->details->thumbnail_is_up_to_date = FALSE; changed = TRUE; } icon = g_file_info_get_icon (info); if (!g_icon_equal (icon, file->details->icon)) { changed = TRUE; if (file->details->icon) { g_object_unref (file->details->icon); } file->details->icon = g_object_ref (icon); } thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH); if (g_strcmp0 (file->details->thumbnail_path, thumbnail_path) != 0) { changed = TRUE; g_free (file->details->thumbnail_path); if (show_image_thumbs != NEMO_SPEED_TRADEOFF_NEVER && thumbnail_path != NULL && !access_ok (thumbnail_path)) { file->details->thumbnail_access_problem = TRUE; file->details->thumbnail_path = NULL; } else { file->details->thumbnail_path = g_strdup (thumbnail_path); } } thumbnailing_failed = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED); if (file->details->thumbnailing_failed != thumbnailing_failed) { changed = TRUE; file->details->thumbnailing_failed = thumbnailing_failed; } symlink_name = g_file_info_get_symlink_target (info); if (g_strcmp0 (file->details->symlink_name, symlink_name) != 0) { changed = TRUE; g_free (file->details->symlink_name); file->details->symlink_name = g_strdup (symlink_name); } selinux_context = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT); if (g_strcmp0 (file->details->selinux_context, selinux_context) != 0) { changed = TRUE; g_free (file->details->selinux_context); file->details->selinux_context = g_strdup (selinux_context); } description = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION); if (g_strcmp0 (file->details->description, description) != 0) { changed = TRUE; g_free (file->details->description); file->details->description = g_strdup (description); } filesystem_id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if (g_strcmp0 (eel_ref_str_peek (file->details->filesystem_id), filesystem_id) != 0) { changed = TRUE; eel_ref_str_unref (file->details->filesystem_id); file->details->filesystem_id = eel_ref_str_get_unique (filesystem_id); } trash_time = 0; time_string = g_file_info_get_attribute_string (info, "trash::deletion-date"); if (time_string != NULL) { g_time_val_from_iso8601 (time_string, &g_trash_time); trash_time = g_trash_time.tv_sec; } if (file->details->trash_time != trash_time) { changed = TRUE; file->details->trash_time = trash_time; } trash_orig_path = g_file_info_get_attribute_byte_string (info, "trash::orig-path"); if (g_strcmp0 (file->details->trash_orig_path, trash_orig_path) != 0) { changed = TRUE; g_free (file->details->trash_orig_path); file->details->trash_orig_path = g_strdup (trash_orig_path); } changed |= nemo_file_update_metadata_from_info (file, info); if (update_name) { name = g_file_info_get_name (info); if (file->details->name == NULL || strcmp (eel_ref_str_peek (file->details->name), name) != 0) { changed = TRUE; node = nemo_directory_begin_file_name_change (file->details->directory, file); eel_ref_str_unref (file->details->name); if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), name) == 0) { file->details->name = eel_ref_str_ref (file->details->display_name); } else { file->details->name = eel_ref_str_new (name); } if (!file->details->got_custom_display_name && g_file_info_get_display_name (info) == NULL) { /* If the file info's display name is NULL, * nemo_file_set_display_name() did * not unset the display name. */ nemo_file_clear_display_name (file); } nemo_directory_end_file_name_change (file->details->directory, file, node); } } mime_type = nemo_get_best_guess_file_mimetype (file->details->name, info, size); if (g_strcmp0 (eel_ref_str_peek (file->details->mime_type), eel_ref_str_peek (mime_type)) != 0) { changed = TRUE; eel_ref_str_unref (file->details->mime_type); file->details->mime_type = mime_type; } if (changed) { add_to_link_hash_table (file); update_links_if_target (file); } return changed; } static gboolean update_info_and_name (NemoFile *file, GFileInfo *info) { return update_info_internal (file, info, TRUE); } gboolean nemo_file_update_info (NemoFile *file, GFileInfo *info) { return update_info_internal (file, info, FALSE); } static gboolean update_name_internal (NemoFile *file, const char *name, gboolean in_directory) { GList *node; g_assert (name != NULL); if (file->details->is_gone) { return FALSE; } if (name_is (file, name)) { return FALSE; } node = NULL; if (in_directory) { node = nemo_directory_begin_file_name_change (file->details->directory, file); } eel_ref_str_unref (file->details->name); file->details->name = eel_ref_str_new (name); if (!file->details->got_custom_display_name) { nemo_file_clear_display_name (file); } if (in_directory) { nemo_directory_end_file_name_change (file->details->directory, file, node); } return TRUE; } gboolean nemo_file_update_name (NemoFile *file, const char *name) { gboolean ret; ret = update_name_internal (file, name, TRUE); if (ret) { update_links_if_target (file); } return ret; } gboolean nemo_file_update_name_and_directory (NemoFile *file, const char *name, NemoDirectory *new_directory) { NemoDirectory *old_directory; FileMonitors *monitors; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); g_return_val_if_fail (NEMO_IS_DIRECTORY (file->details->directory), FALSE); g_return_val_if_fail (!file->details->is_gone, FALSE); g_return_val_if_fail (!nemo_file_is_self_owned (file), FALSE); g_return_val_if_fail (NEMO_IS_DIRECTORY (new_directory), FALSE); old_directory = file->details->directory; if (old_directory == new_directory) { if (name) { return update_name_internal (file, name, TRUE); } else { return FALSE; } } nemo_file_ref (file); /* FIXME bugzilla.gnome.org 42044: Need to let links that * point to the old name know that the file has been moved. */ remove_from_link_hash_table (file); monitors = nemo_directory_remove_file_monitors (old_directory, file); nemo_directory_remove_file (old_directory, file); file->details->directory = nemo_directory_ref (new_directory); nemo_directory_unref (old_directory); if (name) { update_name_internal (file, name, FALSE); } nemo_directory_add_file (new_directory, file); nemo_directory_add_file_monitors (new_directory, file, monitors); add_to_link_hash_table (file); update_links_if_target (file); nemo_file_unref (file); return TRUE; } void nemo_file_set_directory (NemoFile *file, NemoDirectory *new_directory) { nemo_file_update_name_and_directory (file, NULL, new_directory); } static Knowledge get_item_count (NemoFile *file, guint *count) { gboolean known, unreadable; known = nemo_file_get_directory_item_count (file, count, &unreadable); if (!known) { return UNKNOWN; } if (unreadable) { return UNKNOWABLE; } return KNOWN; } static Knowledge get_size (NemoFile *file, goffset *size) { /* If we tried and failed, then treat it like there is no size * to know. */ if (file->details->get_info_failed) { return UNKNOWABLE; } /* If the info is NULL that means we haven't even tried yet, * so it's just unknown, not unknowable. */ if (!file->details->got_file_info) { return UNKNOWN; } /* If we got info with no size in it, it means there is no * such thing as a size as far as gnome-vfs is concerned, * so "unknowable". */ if (file->details->size == -1) { return UNKNOWABLE; } /* We have a size! */ *size = file->details->size; return KNOWN; } static Knowledge get_time (NemoFile *file, time_t *time_out, NemoDateType type) { time_t time; /* If we tried and failed, then treat it like there is no size * to know. */ if (file->details->get_info_failed) { return UNKNOWABLE; } /* If the info is NULL that means we haven't even tried yet, * so it's just unknown, not unknowable. */ if (!file->details->got_file_info) { return UNKNOWN; } time = 0; switch (type) { case NEMO_DATE_TYPE_MODIFIED: time = file->details->mtime; break; case NEMO_DATE_TYPE_ACCESSED: time = file->details->atime; break; case NEMO_DATE_TYPE_CREATED: time = file->details->btime; break; case NEMO_DATE_TYPE_TRASHED: time = file->details->trash_time; break; case NEMO_DATE_TYPE_CHANGED: case NEMO_DATE_TYPE_PERMISSIONS_CHANGED: /* FIXME is some logic needed here ? */ default: g_assert_not_reached (); break; } *time_out = time; /* If we got info with no modification time in it, it means * there is no such thing as a modification time as far as * gnome-vfs is concerned, so "unknowable". */ if (time == 0) { return UNKNOWABLE; } return KNOWN; } static int compare_directories_by_count (NemoFile *file_1, NemoFile *file_2) { /* Sort order: * Directories with unknown # of items * Directories with "unknowable" # of items * Directories with 0 items * Directories with n items */ Knowledge count_known_1, count_known_2; guint count_1, count_2; count_known_1 = get_item_count (file_1, &count_1); count_known_2 = get_item_count (file_2, &count_2); if (count_known_1 > count_known_2) { return -1; } if (count_known_1 < count_known_2) { return +1; } /* count_known_1 and count_known_2 are equal now. Check if count * details are UNKNOWABLE or UNKNOWN. */ if (count_known_1 == UNKNOWABLE || count_known_1 == UNKNOWN) { return 0; } if (count_1 < count_2) { return -1; } if (count_1 > count_2) { return +1; } return 0; } static int compare_files_by_size (NemoFile *file_1, NemoFile *file_2) { /* Sort order: * Files with unknown size. * Files with "unknowable" size. * Files with smaller sizes. * Files with large sizes. */ Knowledge size_known_1, size_known_2; goffset size_1 = 0, size_2 = 0; size_known_1 = get_size (file_1, &size_1); size_known_2 = get_size (file_2, &size_2); if (size_known_1 > size_known_2) { return -1; } if (size_known_1 < size_known_2) { return +1; } /* size_known_1 and size_known_2 are equal now. Check if size * details are UNKNOWABLE or UNKNOWN */ if (size_known_1 == UNKNOWABLE || size_known_1 == UNKNOWN) { return 0; } if (size_1 < size_2) { return -1; } if (size_1 > size_2) { return +1; } return 0; } static int compare_by_size (NemoFile *file_1, NemoFile *file_2) { /* Sort order: * Directories with n items * Directories with 0 items * Directories with "unknowable" # of items * Directories with unknown # of items * Files with large sizes. * Files with smaller sizes. * Files with "unknowable" size. * Files with unknown size. */ gboolean is_directory_1, is_directory_2; is_directory_1 = nemo_file_is_directory (file_1); is_directory_2 = nemo_file_is_directory (file_2); if (is_directory_1 && !is_directory_2) { return -1; } if (is_directory_2 && !is_directory_1) { return +1; } if (is_directory_1) { return compare_directories_by_count (file_1, file_2); } else { return compare_files_by_size (file_1, file_2); } } static int compare_by_display_name (NemoFile *file_1, NemoFile *file_2) { const char *name_1, *name_2; const char *key_1, *key_2; gboolean sort_last_1, sort_last_2; int compare=0; name_1 = nemo_file_peek_display_name (file_1); name_2 = nemo_file_peek_display_name (file_2); sort_last_1 = name_1 && (name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2); sort_last_2 = name_2 && (name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2); if (sort_last_1 && !sort_last_2) { compare = +1; } else if (!sort_last_1 && sort_last_2) { compare = -1; } else if (name_1 == NULL || name_2 == NULL) { if (name_1 && !name_2) compare = +1; else if (!name_1 && name_2) compare = -1; } else { key_1 = nemo_file_peek_display_name_collation_key (file_1); key_2 = nemo_file_peek_display_name_collation_key (file_2); compare = g_strcmp0 (key_1, key_2); } return compare; } static int compare_by_directory_name (NemoFile *file_1, NemoFile *file_2) { char *directory_1, *directory_2; int compare; if (file_1->details->directory == file_2->details->directory) { return 0; } directory_1 = nemo_file_get_parent_uri_for_display (file_1); directory_2 = nemo_file_get_parent_uri_for_display (file_2); compare = g_utf8_collate (directory_1, directory_2); g_free (directory_1); g_free (directory_2); return compare; } static gboolean file_has_note (NemoFile *file) { char *note; gboolean res; note = nemo_file_get_metadata (file, NEMO_METADATA_KEY_ANNOTATION, NULL); res = note != NULL && note[0] != 0; g_free (note); return res; } static GList * prepend_automatic_keywords (NemoFile *file, GList *names) { /* Prepend in reverse order. */ if (file_has_note (file)) { names = g_list_prepend (names, g_strdup (NEMO_FILE_EMBLEM_NAME_NOTE)); } if (!nemo_file_can_read (file)) { names = g_list_prepend (names, g_strdup (NEMO_FILE_EMBLEM_NAME_CANT_READ)); } if (nemo_file_is_symbolic_link (file)) { names = g_list_prepend (names, g_strdup (NEMO_FILE_EMBLEM_NAME_SYMBOLIC_LINK)); } return names; } static int compare_by_type (NemoFile *file_1, NemoFile *file_2, gboolean detailed) { gboolean is_directory_1; gboolean is_directory_2; char *type_string_1; char *type_string_2; int result; /* Directories go first. Then, if mime types are identical, * don't bother getting strings (for speed). This assumes * that the string is dependent entirely on the mime type, * which is true now but might not be later. */ is_directory_1 = nemo_file_is_directory (file_1); is_directory_2 = nemo_file_is_directory (file_2); if (is_directory_1 && is_directory_2) { return 0; } if (is_directory_1) { return -1; } if (is_directory_2) { return +1; } if (detailed) { type_string_1 = nemo_file_get_detailed_type_as_string (file_1); type_string_2 = nemo_file_get_detailed_type_as_string (file_2); } else { type_string_1 = nemo_file_get_type_as_string (file_1); type_string_2 = nemo_file_get_type_as_string (file_2); } if (type_string_1 == NULL || type_string_2 == NULL) { if (type_string_1 != NULL) { return -1; } if (type_string_2 != NULL) { return 1; } return 0; } result = g_utf8_collate (type_string_1, type_string_2); g_free (type_string_1); g_free (type_string_2); return result; } static int compare_by_time (NemoFile *file_1, NemoFile *file_2, NemoDateType type) { /* Sort order: * Files with unknown times. * Files with "unknowable" times. * Files with older times. * Files with newer times. */ Knowledge time_known_1, time_known_2; time_t time_1, time_2; time_1 = 0; time_2 = 0; time_known_1 = get_time (file_1, &time_1, type); time_known_2 = get_time (file_2, &time_2, type); if (time_known_1 > time_known_2) { return -1; } if (time_known_1 < time_known_2) { return +1; } /* Now time_known_1 is equal to time_known_2. Check whether * we failed to get modification times for files */ if(time_known_1 == UNKNOWABLE || time_known_1 == UNKNOWN) { return 0; } if (time_1 < time_2) { return -1; } if (time_1 > time_2) { return +1; } return 0; } static int compare_by_full_path (NemoFile *file_1, NemoFile *file_2) { int compare; compare = compare_by_directory_name (file_1, file_2); if (compare != 0) { return compare; } return compare_by_display_name (file_1, file_2); } static int nemo_file_compare_for_sort_internal (NemoFile *file_1, NemoFile *file_2, gboolean directories_first, gboolean reversed) { gboolean is_directory_1, is_directory_2; gboolean pinned_1, pinned_2; pinned_1 = nemo_file_get_pinning (file_1); pinned_2 = nemo_file_get_pinning (file_2); if (pinned_1 && !pinned_2) { return -1; } if (pinned_2 && !pinned_1) { return +1; } if (directories_first) { is_directory_1 = nemo_file_is_directory (file_1); is_directory_2 = nemo_file_is_directory (file_2); if (is_directory_1 && !is_directory_2) { return -1; } if (is_directory_2 && !is_directory_1) { return +1; } } if (file_1->details->sort_order < file_2->details->sort_order) { return reversed ? 1 : -1; } else if (file_1->details->sort_order > file_2->details->sort_order) { return reversed ? -1 : 1; } return 0; } /** * nemo_file_compare_for_sort: * @file_1: A file object * @file_2: Another file object * @sort_type: Sort criterion * @directories_first: Put all directories before any non-directories * @reversed: Reverse the order of the items, except that * the directories_first flag is still respected. * * Return value: int < 0 if @file_1 should come before file_2 in a * sorted list; int > 0 if @file_2 should come before file_1 in a * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note * that each named sort type may actually break ties several ways, with the name * of the sort criterion being the primary but not only differentiator. **/ int nemo_file_compare_for_sort (NemoFile *file_1, NemoFile *file_2, NemoFileSortType sort_type, gboolean directories_first, gboolean reversed) { int result; if (file_1 == file_2) { return 0; } result = nemo_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed); if (result == 0) { switch (sort_type) { case NEMO_FILE_SORT_BY_DISPLAY_NAME: result = compare_by_display_name (file_1, file_2); if (result == 0) { result = compare_by_directory_name (file_1, file_2); } break; case NEMO_FILE_SORT_BY_SIZE: /* Compare directory sizes ourselves, then if necessary * use GnomeVFS to compare file sizes. */ result = compare_by_size (file_1, file_2); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_TYPE: result = compare_by_type (file_1, file_2, FALSE); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_DETAILED_TYPE: result = compare_by_type (file_1, file_2, TRUE); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_MTIME: result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_MODIFIED); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_ATIME: result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_ACCESSED); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_BTIME: result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_CREATED); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_BY_TRASHED_TIME: result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_TRASHED); if (result == 0) { result = compare_by_full_path (file_1, file_2); } break; case NEMO_FILE_SORT_NONE: default: g_return_val_if_reached (0); } if (reversed) { result = -result; } } return result; } int nemo_file_compare_for_sort_by_attribute_q (NemoFile *file_1, NemoFile *file_2, GQuark attribute, gboolean directories_first, gboolean reversed) { int result; if (file_1 == file_2) { return 0; } /* Convert certain attributes into NemoFileSortTypes and use * nemo_file_compare_for_sort() */ if (attribute == 0 || attribute == attribute_name_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DISPLAY_NAME, directories_first, reversed); } else if (attribute == attribute_size_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_SIZE, directories_first, reversed); } else if (attribute == attribute_type_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_TYPE, directories_first, reversed); } else if (attribute == attribute_detailed_type_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DETAILED_TYPE, directories_first, reversed); } else if (attribute == attribute_modification_date_q || attribute == attribute_date_modified_q || attribute == attribute_date_modified_with_time_q || attribute == attribute_date_modified_full_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_MTIME, directories_first, reversed); } else if (attribute == attribute_accessed_date_q || attribute == attribute_date_accessed_q || attribute == attribute_date_accessed_full_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_ATIME, directories_first, reversed); } else if (attribute == attribute_creation_date_q || attribute == attribute_date_created_q || attribute == attribute_date_created_with_time_q || attribute == attribute_date_created_full_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_BTIME, directories_first, reversed); } else if (attribute == attribute_trashed_on_q || attribute == attribute_trashed_on_full_q) { return nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_TRASHED_TIME, directories_first, reversed); } /* it is a normal attribute, compare by strings */ result = nemo_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed); if (result == 0) { char *value_1; char *value_2; value_1 = nemo_file_get_string_attribute_q (file_1, attribute); value_2 = nemo_file_get_string_attribute_q (file_2, attribute); if (value_1 != NULL && value_2 != NULL) { result = strcmp (value_1, value_2); } g_free (value_1); g_free (value_2); if (reversed) { result = -result; } } return result; } int nemo_file_compare_for_sort_by_attribute (NemoFile *file_1, NemoFile *file_2, const char *attribute, gboolean directories_first, gboolean reversed) { return nemo_file_compare_for_sort_by_attribute_q (file_1, file_2, g_quark_from_string (attribute), directories_first, reversed); } /** * nemo_file_compare_name: * @file: A file object * @pattern: A string we are comparing it with * * Return value: result of a comparison of the file name and the given pattern, * using the same sorting order as sort by name. **/ int nemo_file_compare_display_name (NemoFile *file, const char *pattern) { const char *name; int result; g_return_val_if_fail (pattern != NULL, -1); name = nemo_file_peek_display_name (file); result = g_utf8_collate (name, pattern); return result; } gboolean nemo_file_is_hidden_file (NemoFile *file) { return file->details->is_hidden; } static gboolean is_file_hidden (NemoFile *file) { return file->details->directory->details->hidden_file_hash != NULL && g_hash_table_lookup (file->details->directory->details->hidden_file_hash, eel_ref_str_peek (file->details->name)) != NULL; } /** * nemo_file_should_show: * @file: the file to check. * @show_hidden: whether we want to show hidden files or not. * * Determines if a #NemoFile should be shown. Note that when browsing * a trash directory, this function will always return %TRUE. * * Returns: %TRUE if the file should be shown, %FALSE if it shouldn't. */ gboolean nemo_file_should_show (NemoFile *file, gboolean show_hidden, gboolean show_foreign) { /* Never hide any files in trash. */ if (nemo_file_is_in_trash (file)) { return TRUE; } else { return (show_hidden || (!nemo_file_is_hidden_file (file) && !is_file_hidden (file))) && (show_foreign || !(nemo_file_is_in_desktop (file) && nemo_file_is_foreign_link (file))); } } gboolean nemo_file_is_home (NemoFile *file) { GFile *dir; dir = file->details->directory->details->location; if (dir == NULL) { return FALSE; } return nemo_is_home_directory_file (dir, eel_ref_str_peek (file->details->name)); } gboolean nemo_file_is_in_desktop (NemoFile *file) { if (file->details->directory->details->location) { return nemo_is_desktop_directory (file->details->directory->details->location); } return FALSE; } static gboolean filter_hidden_partition_callback (gpointer data, gpointer callback_data) { NemoFile *file; FilterOptions options; file = NEMO_FILE (data); options = GPOINTER_TO_INT (callback_data); return nemo_file_should_show (file, options & SHOW_HIDDEN, TRUE); } GList * nemo_file_list_filter_hidden (GList *files, gboolean show_hidden) { GList *filtered_files; GList *removed_files; /* FIXME bugzilla.gnome.org 40653: * Eventually this should become a generic filtering thingy. */ filtered_files = nemo_file_list_copy (files); filtered_files = eel_g_list_partition (filtered_files, filter_hidden_partition_callback, GINT_TO_POINTER ((show_hidden ? SHOW_HIDDEN : 0)), &removed_files); nemo_file_list_free (removed_files); return filtered_files; } char * nemo_file_get_metadata (NemoFile *file, const char *key, const char *default_metadata) { guint id; char *value; g_return_val_if_fail (key != NULL, g_strdup (default_metadata)); g_return_val_if_fail (key[0] != '\0', g_strdup (default_metadata)); if (file == NULL || file->details->metadata == NULL) { return g_strdup (default_metadata); } g_return_val_if_fail (NEMO_IS_FILE (file), g_strdup (default_metadata)); if (NEMO_FILE_GET_CLASS (file)->get_metadata) { value = NEMO_FILE_GET_CLASS (file)->get_metadata (file, key); if (value) { return value; } else { return g_strdup (default_metadata); } } id = nemo_metadata_get_id (key); value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id)); if (value) { return g_strdup (value); } return g_strdup (default_metadata); } GList * nemo_file_get_metadata_list (NemoFile *file, const char *key) { GList *res; guint id; char **value; g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (key[0] != '\0', NULL); if (file == NULL || file->details->metadata == NULL) { return NULL; } g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (NEMO_FILE_GET_CLASS (file)->get_metadata_as_list) { gchar **meta_strv = NEMO_FILE_GET_CLASS (file)->get_metadata_as_list (file, key); res = eel_strv_to_glist (meta_strv); g_strfreev (meta_strv); return res; } id = nemo_metadata_get_id (key); id |= METADATA_ID_IS_LIST_MASK; value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id)); if (value) { return eel_strv_to_glist (value); } return NULL; } void nemo_file_set_metadata (NemoFile *file, const char *key, const char *default_metadata, const char *metadata) { const char *val; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); val = metadata; if (val == NULL) { val = default_metadata; } NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata (file, key, val); } void nemo_file_set_metadata_list (NemoFile *file, const char *key, GList *list) { char **val; int len, i; GList *l; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); len = g_list_length (list); val = g_new (char *, len + 1); for (l = list, i = 0; l != NULL; l = l->next, i++) { val[i] = l->data; } val[i] = NULL; NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata_as_list (file, key, val); g_free (val); } void nemo_file_set_desktop_grid_adjusts (NemoFile *file, const char *key, int int_a, int int_b) { char **val; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); val = g_new (char *, 3); val[0] = g_strdup_printf ("%d", int_a); val[1] = g_strdup_printf ("%d", int_b); val[2] = NULL; NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata_as_list (file, key, val); g_strfreev ((gchar **) val); } void nemo_file_get_desktop_grid_adjusts (NemoFile *file, const char *key, int *int_a, int *int_b) { char c; gint result; g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); if (file == NULL || file->details->metadata == NULL) { return; } g_return_if_fail (NEMO_IS_FILE (file)); if (NEMO_FILE_GET_CLASS (file)->get_metadata_as_list) { gchar **meta_strv = NEMO_FILE_GET_CLASS (file)->get_metadata_as_list (file, key); if (!meta_strv) { if (int_a) *int_a = 100; if (int_b) *int_b = 100; return; } if (int_a) { if (sscanf (meta_strv[0], " %d %c", &result, &c) == 1) { *int_a = result; } } if (int_b) { if (sscanf (meta_strv[1], " %d %c", &result, &c) == 1) { *int_b = result; } } g_strfreev (meta_strv); } } gboolean nemo_file_get_boolean_metadata (NemoFile *file, const char *key, gboolean default_metadata) { char *result_as_string; gboolean result; g_return_val_if_fail (key != NULL, default_metadata); g_return_val_if_fail (key[0] != '\0', default_metadata); if (file == NULL) { return default_metadata; } g_return_val_if_fail (NEMO_IS_FILE (file), default_metadata); result_as_string = nemo_file_get_metadata (file, key, default_metadata ? "true" : "false"); g_assert (result_as_string != NULL); if (g_ascii_strcasecmp (result_as_string, "true") == 0) { result = TRUE; } else if (g_ascii_strcasecmp (result_as_string, "false") == 0) { result = FALSE; } else { g_error ("boolean metadata with value other than true or false"); result = default_metadata; } g_free (result_as_string); return result; } int nemo_file_get_integer_metadata (NemoFile *file, const char *key, int default_metadata) { char *result_as_string; char default_as_string[32]; int result; char c; g_return_val_if_fail (key != NULL, default_metadata); g_return_val_if_fail (key[0] != '\0', default_metadata); if (file == NULL) { return default_metadata; } g_return_val_if_fail (NEMO_IS_FILE (file), default_metadata); g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata); result_as_string = nemo_file_get_metadata (file, key, default_as_string); /* Normally we can't get a a NULL, but we check for it here to * handle the oddball case of a non-existent directory. */ if (result_as_string == NULL) { result = default_metadata; } else { if (sscanf (result_as_string, " %d %c", &result, &c) != 1) { result = default_metadata; } g_free (result_as_string); } return result; } static gboolean get_time_from_time_string (const char *time_string, time_t *time) { long scanned_time; char c; g_assert (time != NULL); /* Only accept string if it has one integer with nothing * afterwards. */ if (time_string == NULL || sscanf (time_string, "%ld%c", &scanned_time, &c) != 1) { return FALSE; } *time = (time_t) scanned_time; return TRUE; } time_t nemo_file_get_time_metadata (NemoFile *file, const char *key) { time_t time; char *time_string; time_string = nemo_file_get_metadata (file, key, NULL); if (!get_time_from_time_string (time_string, &time)) { time = UNDEFINED_TIME; } g_free (time_string); return time; } void nemo_file_set_time_metadata (NemoFile *file, const char *key, time_t time) { char time_str[21]; char *metadata; if (time != UNDEFINED_TIME) { /* 2^64 turns out to be 20 characters */ g_snprintf (time_str, 20, "%ld", (long int)time); time_str[20] = '\0'; metadata = time_str; } else { metadata = NULL; } nemo_file_set_metadata (file, key, NULL, metadata); } void nemo_file_set_boolean_metadata (NemoFile *file, const char *key, gboolean default_metadata, gboolean metadata) { g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); nemo_file_set_metadata (file, key, default_metadata ? "true" : "false", metadata ? "true" : "false"); } void nemo_file_set_integer_metadata (NemoFile *file, const char *key, int default_metadata, int metadata) { char value_as_string[32]; char default_as_string[32]; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (key != NULL); g_return_if_fail (key[0] != '\0'); g_snprintf (value_as_string, sizeof (value_as_string), "%d", metadata); g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata); nemo_file_set_metadata (file, key, default_as_string, value_as_string); } static const char * nemo_file_peek_display_name_collation_key (NemoFile *file) { const char *res; res = file->details->display_name_collation_key; if (res == NULL) res = ""; return res; } static const char * nemo_file_peek_display_name (NemoFile *file) { const char *name; char *escaped_name; /* FIXME: for some reason we can get a NemoFile instance which is * no longer valid or could be freed somewhere else in the same time. * There's race condition somewhere. See bug 602500. */ if (file == NULL || nemo_file_is_gone (file)) return ""; /* Default to display name based on filename if its not set yet */ if (file->details->display_name == NULL) { name = eel_ref_str_peek (file->details->name); if (g_utf8_validate (name, -1, NULL)) { nemo_file_set_display_name (file, name, NULL, FALSE); } else { escaped_name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); nemo_file_set_display_name (file, escaped_name, NULL, FALSE); g_free (escaped_name); } } return eel_ref_str_peek (file->details->display_name); } char * nemo_file_get_display_name (NemoFile *file) { return g_strdup (nemo_file_peek_display_name (file)); } char * nemo_file_get_edit_name (NemoFile *file) { const char *res; res = eel_ref_str_peek (file->details->edit_name); if (res == NULL) res = ""; return g_strdup (res); } const char * nemo_file_peek_name (NemoFile *file) { return file->details->name; } char * nemo_file_get_name (NemoFile *file) { return g_strdup (eel_ref_str_peek (file->details->name)); } /** * nemo_file_get_description: * @file: a #NemoFile. * * Gets the standard::description key from @file, if * it has been cached. * * Returns: a string containing the value of the standard::description * key, or %NULL. */ char * nemo_file_get_description (NemoFile *file) { return g_strdup (file->details->description); } void nemo_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes) { g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (client != NULL); NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_add (file, client, attributes); } void nemo_file_monitor_remove (NemoFile *file, gconstpointer client) { g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (client != NULL); NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_remove (file, client); } gboolean nemo_file_is_launcher (NemoFile *file) { return file->details->is_launcher; } gboolean nemo_file_is_foreign_link (NemoFile *file) { return file->details->is_foreign_link; } gboolean nemo_file_is_trusted_link (NemoFile *file) { return file->details->is_trusted_link; } gboolean nemo_file_has_activation_uri (NemoFile *file) { return file->details->activation_uri != NULL; } /* Return the uri associated with the passed-in file, which may not be * the actual uri if the file is an desktop file or a nemo * xml link file. */ char * nemo_file_get_activation_uri (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (file->details->activation_uri != NULL) { return g_strdup (file->details->activation_uri); } return nemo_file_get_uri (file); } GFile * nemo_file_get_activation_location (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (file->details->activation_uri != NULL) { return g_file_new_for_uri (file->details->activation_uri); } return nemo_file_get_location (file); } char * nemo_file_get_drop_target_uri (NemoFile *file) { char *uri, *target_uri; GFile *location; NemoDesktopLink *link; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (NEMO_IS_DESKTOP_ICON_FILE (file)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); if (link != NULL) { location = nemo_desktop_link_get_activation_location (link); g_object_unref (link); if (location != NULL) { uri = g_file_get_uri (location); g_object_unref (location); return uri; } } } uri = nemo_file_get_uri (file); /* Check for Nemo link */ if (nemo_file_is_nemo_link (file)) { location = nemo_file_get_location (file); /* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */ if (g_file_is_native (location)) { target_uri = nemo_link_local_get_link_uri (uri); if (target_uri != NULL) { g_free (uri); uri = target_uri; } } g_object_unref (location); } return uri; } static gboolean is_uri_relative (const char *uri) { char *scheme; gboolean ret; scheme = g_uri_parse_scheme (uri); ret = (scheme == NULL); g_free (scheme); return ret; } static char * get_custom_icon_metadata_uri (NemoFile *file) { char *custom_icon_uri; char *uri; char *dir_uri; uri = nemo_file_get_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL); if (uri != NULL && nemo_file_is_directory (file) && is_uri_relative (uri)) { dir_uri = nemo_file_get_uri (file); custom_icon_uri = g_build_filename (dir_uri, uri, NULL); g_free (dir_uri); g_free (uri); } else { custom_icon_uri = uri; } return custom_icon_uri; } static char * get_custom_icon_metadata_name (NemoFile *file) { char *icon_name; icon_name = nemo_file_get_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL); return icon_name; } static GIcon * get_custom_icon (NemoFile *file) { char *custom_icon_uri, *custom_icon_name; GFile *icon_file; GIcon *icon; if (file == NULL) { return NULL; } icon = NULL; /* Metadata takes precedence; first we look at the custom * icon URI, then at the custom icon name. */ custom_icon_uri = get_custom_icon_metadata_uri (file); if (custom_icon_uri) { icon_file = g_file_new_for_uri (custom_icon_uri); icon = g_file_icon_new (icon_file); g_object_unref (icon_file); g_free (custom_icon_uri); } if (icon == NULL) { custom_icon_name = get_custom_icon_metadata_name (file); if (custom_icon_name != NULL) { icon = g_themed_icon_new (custom_icon_name); g_free (custom_icon_name); } } if (icon == NULL && file->details->got_link_info && file->details->custom_icon != NULL) { icon = g_object_ref (file->details->custom_icon); } return icon; } GFilesystemPreviewType nemo_file_get_filesystem_use_preview (NemoFile *file) { GFilesystemPreviewType use_preview; NemoFile *parent; parent = nemo_file_get_parent (file); if (parent != NULL) { use_preview = parent->details->filesystem_use_preview; g_object_unref (parent); } else { use_preview = 0; } return use_preview; } gboolean nemo_file_should_show_thumbnail (NemoFile *file) { GFilesystemPreviewType use_preview; NemoFile *dir; char* metadata_str = NULL; if (!NEMO_IS_FILE (file)) { return FALSE; } use_preview = nemo_file_get_filesystem_use_preview (file); if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) { /* file system says to never thumbnail anything */ return FALSE; } /* Only care about the file size, if the thumbnail has not been created yet */ if (file->details->thumbnail_path == NULL && nemo_file_get_size (file) > cached_thumbnail_limit) { return FALSE; } if (file->details->thumbnail_access_problem) { return FALSE; } if (!nemo_global_preferences_get_ignore_view_metadata ()) { dir = nemo_file_is_directory(file) ? file : nemo_file_get_parent(file); if (nemo_global_preferences_get_inherit_show_thumbnails_preference ()) { while (dir != NULL) { metadata_str = nemo_file_get_metadata(dir, NEMO_METADATA_KEY_SHOW_THUMBNAILS, NULL); if (metadata_str == NULL) { // do this here to avoid string comparisons with a NULL string dir = nemo_file_get_parent(dir); } else if (g_ascii_strcasecmp (metadata_str, "true") == 0) { g_free(metadata_str); return TRUE; } else if (g_ascii_strcasecmp (metadata_str, "false") == 0) { g_free(metadata_str); return FALSE; } else { g_free(metadata_str); dir = nemo_file_get_parent(dir); } } } else { metadata_str = nemo_file_get_metadata(dir, NEMO_METADATA_KEY_SHOW_THUMBNAILS, NULL); if (metadata_str != NULL ) { if (g_ascii_strcasecmp (metadata_str, "true") == 0) { g_free(metadata_str); return TRUE; } else if (g_ascii_strcasecmp (metadata_str, "false") == 0) { g_free(metadata_str); return FALSE; } } } } /* Use global preference */ if (show_image_thumbs == NEMO_SPEED_TRADEOFF_ALWAYS) { return TRUE; } if (show_image_thumbs == NEMO_SPEED_TRADEOFF_NEVER) { return FALSE; } if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) { /* file system says we should treat file as if it's local */ return TRUE; } /* local files is the only left to check */ return nemo_file_is_local (file); } void nemo_file_delete_thumbnail (NemoFile *file) { if (file->details->thumbnail_path == NULL) { return; } gint success; invalidate_thumbnail (file); success = g_unlink (file->details->thumbnail_path); if (success != 0) { g_warning ("Could not remove thumb for '%s'. The thumbnail path is '%s'", file->details->display_name, file->details->thumbnail_path); } } static void prepend_icon_name (const char *name, GThemedIcon *icon) { g_themed_icon_prepend_name(icon, name); } GIcon * nemo_file_get_gicon (NemoFile *file, NemoFileIconFlags flags) { const char * const * names; const char *name; GPtrArray *prepend_array; GMount *mount; GIcon *icon, *mount_icon = NULL, *emblemed_icon; GEmblem *emblem; int i; gboolean is_folder = FALSE, is_inode_directory = FALSE; if (file == NULL) { return NULL; } icon = get_custom_icon (file); if (icon != NULL) { return icon; } if (file->details->icon) { icon = NULL; /* fetch the mount icon here, we'll use it later */ if (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON || flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) { mount = nemo_file_get_mount (file); if (mount != NULL) { mount_icon = g_mount_get_icon (mount); g_object_unref (mount); } } if (((flags & NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT) || (flags & NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER) || (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON) || (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) || ((flags & NEMO_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 && nemo_file_has_open_window (file))) && G_IS_THEMED_ICON (file->details->icon)) { names = g_themed_icon_get_names (G_THEMED_ICON (file->details->icon)); prepend_array = g_ptr_array_new (); for (i = 0; names[i] != NULL; i++) { name = names[i]; if (strcmp (name, "folder") == 0) { is_folder = TRUE; } if (strcmp (name, "inode-directory") == 0) { is_inode_directory = TRUE; } } /* Here, we add icons in reverse order of precedence, * because they are later prepended */ /* "folder" should override "inode-directory", not the other way around */ if (is_inode_directory) { g_ptr_array_add (prepend_array, (char *)"folder"); } if (is_folder && (flags & NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER)) { g_ptr_array_add (prepend_array, (char *)"folder-open"); } if (is_folder && (flags & NEMO_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 && nemo_file_has_open_window (file)) { g_ptr_array_add (prepend_array, (char *)"folder-visiting"); } if (is_folder && (flags & NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT)) { g_ptr_array_add (prepend_array, (char *)"folder-drag-accept"); } if (prepend_array->len) { /* When constructing GThemed Icon, pointers from the array * are reused, but not the array itself, so the cast is safe */ icon = g_themed_icon_new_from_names ((char**) names, -1); g_ptr_array_foreach (prepend_array, (GFunc) prepend_icon_name, icon); } g_ptr_array_free (prepend_array, TRUE); } if (icon == NULL) { icon = g_object_ref (file->details->icon); } if ((flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON) && mount_icon != NULL) { g_object_unref (icon); icon = mount_icon; } else if ((flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) && mount_icon != NULL && !g_icon_equal (mount_icon, icon)) { emblem = g_emblem_new (mount_icon); emblemed_icon = g_emblemed_icon_new (icon, emblem); g_object_unref (emblem); g_object_unref (icon); g_object_unref (mount_icon); icon = emblemed_icon; } else if (mount_icon != NULL) { g_object_unref (mount_icon); } return icon; } return g_themed_icon_new ("text-x-generic"); } static const gchar * get_symbolic_icon_name_for_file (NemoFile *file) { if (nemo_file_is_home (file)) { return NEMO_ICON_SYMBOLIC_HOME; } // Special folders (XDG) if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP)) { return NEMO_ICON_SYMBOLIC_DESKTOP; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOCUMENTS)) { return NEMO_ICON_SYMBOLIC_FOLDER_DOCUMENTS; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOWNLOAD)) { return NEMO_ICON_SYMBOLIC_FOLDER_DOWNLOAD; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_MUSIC)) { return NEMO_ICON_SYMBOLIC_FOLDER_MUSIC; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_PICTURES)) { return NEMO_ICON_SYMBOLIC_FOLDER_PICTURES; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_PUBLIC_SHARE)) { return NEMO_ICON_SYMBOLIC_FOLDER_PUBLIC_SHARE; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_TEMPLATES)) { return NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_VIDEOS)) { return NEMO_ICON_SYMBOLIC_FOLDER_VIDEOS; } if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_TEMPLATES)) { return NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES; } return NULL; } gchar * nemo_file_get_control_icon_name (NemoFile *file) { gchar *uri; gchar *icon_name; icon_name = NULL; uri = nemo_file_get_uri (file); if (eel_uri_is_search (uri)) { icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_SAVED_SEARCH); } else if (eel_uri_is_trash (uri)) { icon_name = nemo_trash_monitor_get_symbolic_icon_name (); } else if (eel_uri_is_recent (uri)) { icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_RECENT); } else if (eel_uri_is_network (uri)) { icon_name = g_strdup (NEMO_ICON_SYMBOLIC_NETWORK); } else { const gchar *static_name; static_name = get_symbolic_icon_name_for_file (file); if (static_name != NULL) { icon_name = g_strdup (static_name); } else { GFile *location; location = nemo_file_get_location (file); if (!g_file_is_native (location)) { icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_REMOTE); } else if (file->details->mime_type != NULL) { GIcon *gicon; gicon = g_content_type_get_symbolic_icon (file->details->mime_type); if (G_IS_THEMED_ICON (gicon)) { icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]); } g_object_unref (gicon); } g_object_unref (location); } } g_free (uri); if (icon_name == NULL) { icon_name = g_strdup ("text-x-generic"); } return icon_name; } gboolean nemo_file_get_pinning (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (file->details->pinning == FILE_PINNING_UNKNOWN) { file->details->pinning = nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_PINNED, FALSE); } return file->details->pinning; } void nemo_file_set_pinning (NemoFile *file, gboolean pin) { g_return_if_fail (NEMO_IS_FILE (file)); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_PINNED, TRUE, pin); } static gint get_throttle_count (NemoFile *file) { NemoFileDetails *details = file->details; gint diff = (gint)(details->mtime - details->last_thumbnail_try_mtime); if (diff != 0 && diff <= (THUMBNAIL_CREATION_DELAY_SECS * (details->thumbnail_throttle_count + 1))) { details->thumbnail_throttle_count++; } else { details->thumbnail_throttle_count = 1; } details->last_thumbnail_try_mtime = details->mtime; return details->thumbnail_throttle_count; } NemoIconInfo * nemo_file_get_icon (NemoFile *file, int size, int max_width, int scale, NemoFileIconFlags flags) { NemoIconInfo *icon; GIcon *gicon; GdkPixbuf *raw_pixbuf, *scaled_pixbuf; int modified_size; if (file == NULL) { return NULL; } gicon = get_custom_icon (file); if (gicon != NULL) { icon = nemo_icon_info_lookup (gicon, size, scale); g_object_unref (gicon); return icon; } DEBUG ("Called file_get_icon(), at size %d, force thumbnail %d", size, flags & NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE); if (flags & NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS && nemo_file_should_show_thumbnail (file)) { if (flags & NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE) { modified_size = size * scale; } else { modified_size = size * scale * scaled_cached_thumbnail_size; DEBUG ("Modifying icon size to %d, as our cached thumbnail size is %d", modified_size, cached_thumbnail_size); } if (file->details->thumbnail) { int w, h, s; double thumb_scale; raw_pixbuf = g_object_ref (file->details->thumbnail); w = gdk_pixbuf_get_width (raw_pixbuf); h = gdk_pixbuf_get_height (raw_pixbuf); if (flags & NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP) { g_assert (max_width > 0); thumb_scale = (gdouble) modified_size / h; if (w * thumb_scale > max_width) { thumb_scale = (gdouble) max_width / w; } s = thumb_scale * h; } else { s = MAX (w, h); /* Don't scale up small thumbnails in the standard view */ if (s <= cached_thumbnail_size) { thumb_scale = (double)size / NEMO_ICON_SIZE_STANDARD; } else { thumb_scale = (double)modified_size / s; } /* Make sure that icons don't get smaller than NEMO_ICON_SIZE_SMALLEST */ if (s*thumb_scale <= NEMO_ICON_SIZE_SMALLEST) { thumb_scale = (double) NEMO_ICON_SIZE_SMALLEST / s; } } scaled_pixbuf = gdk_pixbuf_scale_simple (raw_pixbuf, MAX (w * thumb_scale, 1), MAX (h * thumb_scale, 1), GDK_INTERP_BILINEAR); /* We don't want frames around small icons */ if (!gdk_pixbuf_get_has_alpha (raw_pixbuf) || s >= 128 * scale) { nemo_thumbnail_frame_image (&scaled_pixbuf); } if (flags & NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP) { gint check_height; check_height = gdk_pixbuf_get_height (scaled_pixbuf); if (check_height < size) { nemo_thumbnail_pad_top_and_bottom (&scaled_pixbuf, size - check_height); } } g_object_unref (raw_pixbuf); /* Don't scale up if more than 25%, then read the original image instead. We don't want to compare to exactly 100%, since the zoom level 150% gives thumbnails at 144, which is ok to scale up from 128. */ if (modified_size > 128 * 1.25 * scale && !file->details->thumbnail_wants_original && nemo_can_thumbnail_internally (file)) { /* Invalidate if we resize upward */ file->details->thumbnail_wants_original = TRUE; nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_THUMBNAIL); } DEBUG ("Returning thumbnailed image, at size %d %d", (int) (w * thumb_scale), (int) (h * thumb_scale)); icon = nemo_icon_info_new_for_pixbuf (scaled_pixbuf, scale); g_object_unref (scaled_pixbuf); return icon; } else if (file->details->thumbnail_path == NULL && file->details->can_read && !file->details->is_thumbnailing && !file->details->thumbnailing_failed) { if (nemo_can_thumbnail (file)) { nemo_create_thumbnail (file, get_throttle_count (file)); } } } if (file->details->is_thumbnailing && flags & NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS) gicon = g_themed_icon_new (ICON_NAME_THUMBNAIL_LOADING); else gicon = nemo_file_get_gicon (file, flags); if (gicon) { icon = nemo_icon_info_lookup (gicon, size, scale); g_object_unref (gicon); return icon; } else { /* This is inefficient, but *very* unlikely to be hit */ GIcon *generic = g_themed_icon_new ("text-x-generic"); icon = nemo_icon_info_lookup (generic, size, scale); g_object_unref (generic); return icon; } } GdkPixbuf * nemo_file_get_icon_pixbuf (NemoFile *file, int size, gboolean force_size, int scale, NemoFileIconFlags flags) { NemoIconInfo *info; GdkPixbuf *pixbuf; info = nemo_file_get_icon (file, size, 0, scale, flags); if (force_size) { pixbuf = nemo_icon_info_get_pixbuf_at_size (info, size); } else { pixbuf = nemo_icon_info_get_pixbuf (info); } nemo_icon_info_unref (info); return pixbuf; } gboolean nemo_file_get_date (NemoFile *file, NemoDateType date_type, time_t *date) { if (date != NULL) { *date = 0; } g_return_val_if_fail (date_type == NEMO_DATE_TYPE_CHANGED || date_type == NEMO_DATE_TYPE_ACCESSED || date_type == NEMO_DATE_TYPE_MODIFIED || date_type == NEMO_DATE_TYPE_CREATED || date_type == NEMO_DATE_TYPE_TRASHED || date_type == NEMO_DATE_TYPE_PERMISSIONS_CHANGED, FALSE); if (file == NULL) { return FALSE; } g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_date (file, date_type, date); } static char * nemo_file_get_where_string (NemoFile *file) { if (file == NULL) { return NULL; } g_return_val_if_fail (NEMO_IS_FILE (file), NULL); return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_where_string (file); } static char * nemo_file_get_trash_original_file_parent_as_string (NemoFile *file) { NemoFile *orig_file, *parent; GFile *location; char *filename; if (file->details->trash_orig_path != NULL) { orig_file = nemo_file_get_trash_original_file (file); parent = nemo_file_get_parent (orig_file); location = nemo_file_get_location (parent); filename = g_file_get_parse_name (location); g_object_unref (location); nemo_file_unref (parent); nemo_file_unref (orig_file); return filename; } return NULL; } static const gchar * nemo_date_type_to_string (NemoDateType type) { switch (type) { case NEMO_DATE_TYPE_MODIFIED: return "NEMO_DATE_TYPE_MODIFIED"; case NEMO_DATE_TYPE_CHANGED: return "NEMO_DATE_TYPE_CHANGED"; case NEMO_DATE_TYPE_ACCESSED: return "NEMO_DATE_TYPE_ACCESSED"; case NEMO_DATE_TYPE_PERMISSIONS_CHANGED: return "NEMO_DATE_TYPE_PERMISSIONS_CHANGED"; case NEMO_DATE_TYPE_TRASHED: return "NEMO_DATE_TYPE_TRASHED"; case NEMO_DATE_TYPE_CREATED: return "NEMO_DATE_TYPE_CREATED"; } return "(unknown)"; } /** * nemo_file_get_date_as_string: * * Get a user-displayable string representing a file modification date. * The caller is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_date_as_string (NemoFile *file, NemoDateType date_type, NemoDateCompactFormat date_format) { time_t file_time_raw; GDateTime *file_date_time, *file_date_time_utc; GDateTime *today_midnight, *now; GTimeZone *current_timezone; gint days_ago; gboolean use_24; const gchar *format; gchar *result; gchar *result_with_ratio; int date_format_pref; if (!nemo_file_get_date (file, date_type, &file_time_raw)) return NULL; current_timezone = prefs_current_timezone; file_date_time_utc = g_date_time_new_from_unix_utc (file_time_raw); if (!file_date_time_utc) { DEBUG ("File '%s' has invalid time for %s", nemo_file_peek_name (file), nemo_date_type_to_string (date_type)); return NULL; } file_date_time = g_date_time_to_timezone (file_date_time_utc, current_timezone); g_date_time_unref (file_date_time_utc); date_format_pref = prefs_current_date_format; if (date_format_pref == NEMO_DATE_FORMAT_LOCALE) { result = g_date_time_format (file_date_time, "%c"); goto out; } else if (date_format_pref == NEMO_DATE_FORMAT_ISO) { result = g_date_time_format (file_date_time, "%Y-%m-%d %H:%M:%S"); goto out; } if (date_format != NEMO_DATE_FORMAT_FULL) { GDateTime *file_date; now = g_date_time_new_now (current_timezone); today_midnight = g_date_time_new (current_timezone, g_date_time_get_year (now), g_date_time_get_month (now), g_date_time_get_day_of_month (now), 0, 0, 0); file_date = g_date_time_new (current_timezone, g_date_time_get_year (file_date_time), g_date_time_get_month (file_date_time), g_date_time_get_day_of_month (file_date_time), 0, 0, 0); days_ago = g_date_time_difference (today_midnight, file_date) / G_TIME_SPAN_DAY; use_24 = prefs_current_24h_time_format; // Show only the time if date is on today if (days_ago < 1) { if (use_24) { /* Translators: Time in 24h format */ format = _("%H:%M"); } else { /* Translators: Time in 12h format */ format = _("%l:%M %p"); } } // Show the word "Yesterday" and time if date is on yesterday else if (days_ago < 2) { if (date_format == NEMO_DATE_FORMAT_REGULAR) { // xgettext:no-c-format format = _("Yesterday"); } else { if (use_24) { /* Translators: this is the word Yesterday followed by * a time in 24h format. i.e. "Yesterday 23:04" */ // xgettext:no-c-format format = _("Yesterday %H:%M"); } else { /* Translators: this is the word Yesterday followed by * a time in 12h format. i.e. "Yesterday 9:04 PM" */ // xgettext:no-c-format format = _("Yesterday %l:%M %p"); } } } // Show a week day and time if date is in the last week else if (days_ago < 7) { if (date_format == NEMO_DATE_FORMAT_REGULAR) { // xgettext:no-c-format format = _("%A"); } else { if (use_24) { /* Translators: this is the name of the week day followed by * a time in 24h format. i.e. "Monday 23:04" */ // xgettext:no-c-format format = _("%A %H:%M"); } else { /* Translators: this is the week day name followed by * a time in 12h format. i.e. "Monday 9:04 PM" */ // xgettext:no-c-format format = _("%A %l:%M %p"); } } } else if (g_date_time_get_year (file_date) == g_date_time_get_year (now)) { if (date_format == NEMO_DATE_FORMAT_REGULAR) { /* Translators: this is the day of the month followed * by the abbreviated month name i.e. "3 February" */ // xgettext:no-c-format format = _("%-e %B"); } else { if (use_24) { /* Translators: this is the day of the month followed * by the abbreviated month name followed by a time in * 24h format i.e. "3 February 23:04" */ // xgettext:no-c-format format = _("%-e %B %H:%M"); } else { /* Translators: this is the day of the month followed * by the abbreviated month name followed by a time in * 12h format i.e. "3 February 9:04" */ // xgettext:no-c-format format = _("%-e %B %l:%M %p"); } } } else { if (date_format == NEMO_DATE_FORMAT_REGULAR) { /* Translators: this is the day of the month followed by the abbreviated * month name followed by the year i.e. "3 Feb 2015" */ // xgettext:no-c-format format = _("%-e %b %Y"); } else { if (use_24) { /* Translators: this is the day number followed * by the abbreviated month name followed by the year followed * by a time in 24h format i.e. "3 Feb 2015 23:04" */ // xgettext:no-c-format format = _("%-e %b %Y %H:%M"); } else { /* Translators: this is the day number followed * by the abbreviated month name followed by the year followed * by a time in 12h format i.e. "3 Feb 2015 9:04 PM" */ // xgettext:no-c-format format = _("%-e %b %Y %l:%M %p"); } } } g_date_time_unref (file_date); g_date_time_unref (now); g_date_time_unref (today_midnight); } else { // xgettext:no-c-format format = _("%c"); } result = g_date_time_format (file_date_time, format); out: g_date_time_unref (file_date_time); /* Replace ":" with ratio. Replacement is done afterward because g_date_time_format * may fail with utf8 chars in some locales */ result_with_ratio = eel_str_replace_substring (result, ":", "∶"); g_free (result); return result_with_ratio; } static NemoSpeedTradeoffValue show_directory_item_count; static void show_directory_item_count_changed_callback (gpointer callback_data) { show_directory_item_count = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS); } static gboolean get_speed_tradeoff_preference_for_file (NemoFile *file, NemoSpeedTradeoffValue value) { GFilesystemPreviewType use_preview; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); use_preview = nemo_file_get_filesystem_use_preview (file); if (value == NEMO_SPEED_TRADEOFF_ALWAYS) { if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) { return FALSE; } else { return TRUE; } } if (value == NEMO_SPEED_TRADEOFF_NEVER) { return FALSE; } g_assert (value == NEMO_SPEED_TRADEOFF_LOCAL_ONLY); if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) { /* file system says to never preview anything */ return FALSE; } else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) { /* file system says we should treat file as if it's local */ return TRUE; } else { /* only local files */ return nemo_file_is_local (file); } } gboolean nemo_file_should_show_directory_item_count (NemoFile *file) { static gboolean show_directory_item_count_callback_added = FALSE; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (file->details->mime_type && strcmp (eel_ref_str_peek (file->details->mime_type), "x-directory/smb-share") == 0) { return FALSE; } /* Add the callback once for the life of our process */ if (!show_directory_item_count_callback_added) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS, G_CALLBACK(show_directory_item_count_changed_callback), NULL); show_directory_item_count_callback_added = TRUE; /* Peek for the first time */ show_directory_item_count_changed_callback (NULL); } return get_speed_tradeoff_preference_for_file (file, show_directory_item_count); } gboolean nemo_file_should_show_type (NemoFile *file) { char *uri; gboolean ret; g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); uri = nemo_file_get_uri (file); ret = ((strcmp (uri, "computer:///") != 0) && (strcmp (uri, "network:///") != 0) && (strcmp (uri, "smb:///") != 0)); g_free (uri); return ret; } /** * nemo_file_get_directory_item_count * * Get the number of items in a directory. * @file: NemoFile representing a directory. * @count: Place to put count. * @count_unreadable: Set to TRUE (if non-NULL) if permissions prevent * the item count from being read on this directory. Otherwise set to FALSE. * * Returns: TRUE if count is available. * **/ gboolean nemo_file_get_directory_item_count (NemoFile *file, guint *count, gboolean *count_unreadable) { if (count != NULL) { *count = 0; } if (count_unreadable != NULL) { *count_unreadable = FALSE; } g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); if (!nemo_file_is_directory (file)) { return FALSE; } if (!nemo_file_should_show_directory_item_count (file)) { return FALSE; } return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_item_count (file, count, count_unreadable); } /** * nemo_file_get_deep_counts * * Get the statistics about items inside a directory. * @file: NemoFile representing a directory or file. * @directory_count: Place to put count of directories inside. * @files_count: Place to put count of files inside. * @unreadable_directory_count: Number of directories encountered * that were unreadable. * @total_size: Total size of all files and directories visited. * @force: Whether the deep counts should even be collected if * nemo_file_should_show_directory_item_count returns FALSE * for this file. * * Returns: Status to indicate whether sizes are available. * **/ NemoRequestStatus nemo_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size, gboolean force) { if (directory_count != NULL) { *directory_count = 0; } if (file_count != NULL) { *file_count = 0; } if (unreadable_directory_count != NULL) { *unreadable_directory_count = 0; } if (total_size != NULL) { *total_size = 0; } if (hidden_count != NULL) { *hidden_count = 0; } g_return_val_if_fail (NEMO_IS_FILE (file), NEMO_REQUEST_DONE); if (!force && !nemo_file_should_show_directory_item_count (file)) { /* Set field so an existing value isn't treated as up-to-date * when preference changes later. */ file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED; return file->details->deep_counts_status; } return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_deep_counts (file, directory_count, file_count, unreadable_directory_count, hidden_count, total_size); } void nemo_file_recompute_deep_counts (NemoFile *file) { if (file->details->deep_counts_status != NEMO_REQUEST_IN_PROGRESS) { file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED; if (file->details->directory != NULL) { nemo_directory_add_file_to_work_queue (file->details->directory, file); nemo_directory_async_state_changed (file->details->directory); } } } /** * nemo_file_get_directory_item_mime_types * * Get the list of mime-types present in a directory. * @file: NemoFile representing a directory. It is an error to * call this function on a file that is not a directory. * @mime_list: Place to put the list of mime-types. * * Returns: TRUE if mime-type list is available. * **/ gboolean nemo_file_get_directory_item_mime_types (NemoFile *file, GList **mime_list) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); g_return_val_if_fail (mime_list != NULL, FALSE); if (!nemo_file_is_directory (file) || !file->details->got_mime_list) { *mime_list = NULL; return FALSE; } *mime_list = eel_g_str_list_copy (file->details->mime_list); return TRUE; } gboolean nemo_file_can_get_size (NemoFile *file) { return file->details->size == -1; } /** * nemo_file_get_size * * Get the file size. * @file: NemoFile representing the file in question. * * Returns: Size in bytes. * **/ goffset nemo_file_get_size (NemoFile *file) { /* Before we have info on the file, we don't know the size. */ if (file->details->size == -1) return 0; return file->details->size; } time_t nemo_file_get_mtime (NemoFile *file) { return file->details->mtime; } time_t nemo_file_get_ctime (NemoFile *file) { return file->details->ctime; } static void set_attributes_get_info_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; GFileInfo *new_info; GError *error; op = callback_data; error = NULL; new_info = g_file_query_info_finish (G_FILE (source_object), res, &error); if (new_info != NULL) { if (nemo_file_update_info (op->file, new_info)) { nemo_file_changed (op->file); } g_object_unref (new_info); } nemo_file_operation_complete (op, NULL, error); if (error) { g_error_free (error); } } static void set_attributes_callback (GObject *source_object, GAsyncResult *result, gpointer callback_data) { NemoFileOperation *op; GError *error; gboolean res; op = callback_data; error = NULL; res = g_file_set_attributes_finish (G_FILE (source_object), result, NULL, &error); if (res) { g_file_query_info_async (G_FILE (source_object), NEMO_FILE_DEFAULT_ATTRIBUTES, 0, G_PRIORITY_DEFAULT, op->cancellable, set_attributes_get_info_callback, op); } else { nemo_file_operation_complete (op, NULL, error); g_error_free (error); } } void nemo_file_set_attributes (NemoFile *file, GFileInfo *attributes, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GFile *location; op = nemo_file_operation_new (file, callback, callback_data); location = nemo_file_get_location (file); g_file_set_attributes_async (location, attributes, 0, G_PRIORITY_DEFAULT, op->cancellable, set_attributes_callback, op); g_object_unref (location); } /** * nemo_file_can_get_permissions: * * Check whether the permissions for a file are determinable. * This might not be the case for files on non-UNIX file systems. * * @file: The file in question. * * Return value: TRUE if the permissions are valid. */ gboolean nemo_file_can_get_permissions (NemoFile *file) { return file->details->has_permissions; } /** * nemo_file_can_set_permissions: * * Check whether the current user is allowed to change * the permissions of a file. * * @file: The file in question. * * Return value: TRUE if the current user can change the * permissions of @file, FALSE otherwise. It's always possible * that when you actually try to do it, you will fail. */ gboolean nemo_file_can_set_permissions (NemoFile *file) { uid_t user_id; if (file->details->uid != -1 && nemo_file_is_local (file)) { /* Check the user. */ user_id = geteuid(); /* Owner is allowed to set permissions. */ if (user_id == (uid_t) file->details->uid) { return TRUE; } /* Root is also allowed to set permissions. */ if (user_id == 0) { return TRUE; } /* Nobody else is allowed. */ return FALSE; } /* pretend to have full chmod rights when no info is available, relevant when * the FS can't provide ownership info, for instance for FTP */ return TRUE; } guint nemo_file_get_permissions (NemoFile *file) { g_return_val_if_fail (nemo_file_can_get_permissions (file), 0); return file->details->permissions; } /** * nemo_file_set_permissions: * * Change a file's permissions. This should only be called if * nemo_file_can_set_permissions returned TRUE. * * @file: NemoFile representing the file in question. * @new_permissions: New permissions value. This is the whole * set of permissions, not a delta. **/ void nemo_file_set_permissions (NemoFile *file, guint32 new_permissions, NemoFileOperationCallback callback, gpointer callback_data) { GFileInfo *info; GError *error; if (!nemo_file_can_set_permissions (file)) { /* Claim that something changed even if the permission change failed. * This makes it easier for some clients who see the "reverting" * to the old permissions as "changing back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, _("Not allowed to set permissions")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* Test the permissions-haven't-changed case explicitly * because we don't want to send the file-changed signal if * nothing changed. */ if (new_permissions == file->details->permissions) { (* callback) (file, NULL, NULL, callback_data); return; } if (!nemo_file_undo_manager_pop_flag ()) { NemoFileUndoInfo *undo_info; undo_info = nemo_file_undo_info_permissions_new (nemo_file_get_location (file), file->details->permissions, new_permissions); nemo_file_undo_manager_set_action (undo_info); } info = g_file_info_new (); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, new_permissions); nemo_file_set_attributes (file, info, callback, callback_data); g_object_unref (info); } /** * nemo_file_can_get_selinux_context: * * Check whether the selinux context for a file are determinable. * This might not be the case for files on non-UNIX file systems, * files without a context or systems that don't support selinux. * * @file: The file in question. * * Return value: TRUE if the permissions are valid. */ gboolean nemo_file_can_get_selinux_context (NemoFile *file) { return file->details->selinux_context != NULL; } /** * nemo_file_get_selinux_context: * * Get a user-displayable string representing a file's selinux * context * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ char * nemo_file_get_selinux_context (NemoFile *file) { char *translated; char *raw; g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (!nemo_file_can_get_selinux_context (file)) { return NULL; } raw = file->details->selinux_context; #ifdef HAVE_SELINUX if (selinux_raw_to_trans_context (raw, &translated) == 0) { char *tmp; tmp = g_strdup (translated); freecon (translated); translated = tmp; } else #endif { translated = g_strdup (raw); } return translated; } static char * get_real_name (const char *name, const char *gecos) { char *locale_string, *part_before_comma, *capitalized_login_name, *real_name; if (gecos == NULL) { return NULL; } locale_string = eel_str_strip_substring_and_after (gecos, ","); if (!g_utf8_validate (locale_string, -1, NULL)) { part_before_comma = g_locale_to_utf8 (locale_string, -1, NULL, NULL, NULL); g_free (locale_string); } else { part_before_comma = locale_string; } if (!g_utf8_validate (name, -1, NULL)) { locale_string = g_locale_to_utf8 (name, -1, NULL, NULL, NULL); } else { locale_string = g_strdup (name); } capitalized_login_name = eel_str_capitalize (locale_string); g_free (locale_string); if (capitalized_login_name == NULL) { real_name = part_before_comma; } else { real_name = eel_str_replace_substring (part_before_comma, "&", capitalized_login_name); g_free (part_before_comma); } if (g_strcmp0 (real_name, NULL) == 0 || g_strcmp0 (name, real_name) == 0 || g_strcmp0 (capitalized_login_name, real_name) == 0) { g_free (real_name); real_name = NULL; } g_free (capitalized_login_name); return real_name; } static gboolean get_group_id_from_group_name (const char *group_name, uid_t *gid) { struct group *group; g_assert (gid != NULL); group = getgrnam (group_name); if (group == NULL) { return FALSE; } *gid = group->gr_gid; return TRUE; } static gboolean get_ids_from_user_name (const char *user_name, uid_t *uid, uid_t *gid) { struct passwd *password_info; g_assert (uid != NULL || gid != NULL); password_info = getpwnam (user_name); if (password_info == NULL) { return FALSE; } if (uid != NULL) { *uid = password_info->pw_uid; } if (gid != NULL) { *gid = password_info->pw_gid; } return TRUE; } static gboolean get_user_id_from_user_name (const char *user_name, uid_t *id) { return get_ids_from_user_name (user_name, id, NULL); } static gboolean get_id_from_digit_string (const char *digit_string, uid_t *id) { long scanned_id; char c; g_assert (id != NULL); /* Only accept string if it has one integer with nothing * afterwards. */ if (sscanf (digit_string, "%ld%c", &scanned_id, &c) != 1) { return FALSE; } *id = scanned_id; return TRUE; } /** * nemo_file_can_get_owner: * * Check whether the owner a file is determinable. * This might not be the case for files on non-UNIX file systems. * * @file: The file in question. * * Return value: TRUE if the owner is valid. */ gboolean nemo_file_can_get_owner (NemoFile *file) { /* Before we have info on a file, the owner is unknown. */ return file->details->uid != -1; } /** * nemo_file_get_owner_name: * * Get the user name of the file's owner. If the owner has no * name, returns the userid as a string. The caller is responsible * for g_free-ing this string. * * @file: The file in question. * * Return value: A newly-allocated string. */ char * nemo_file_get_owner_name (NemoFile *file) { return nemo_file_get_owner_as_string (file, FALSE); } /** * nemo_file_can_set_owner: * * Check whether the current user is allowed to change * the owner of a file. * * @file: The file in question. * * Return value: TRUE if the current user can change the * owner of @file, FALSE otherwise. It's always possible * that when you actually try to do it, you will fail. */ gboolean nemo_file_can_set_owner (NemoFile *file) { /* Not allowed to set the owner if we can't * even read it. This can happen on non-UNIX file * systems. */ if (!nemo_file_can_get_owner (file)) { return FALSE; } /* Only root is also allowed to set the owner. */ return geteuid() == 0; } /** * nemo_file_set_owner: * * Set the owner of a file. This will only have any effect if * nemo_file_can_set_owner returns TRUE. * * @file: The file in question. * @user_name_or_id: The user name to set the owner to. * If the string does not match any user name, and the * string is an integer, the owner will be set to the * userid represented by that integer. * @callback: Function called when asynch owner change succeeds or fails. * @callback_data: Parameter passed back with callback function. */ void nemo_file_set_owner (NemoFile *file, const char *user_name_or_id, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; GFileInfo *info; uid_t new_id; if (!nemo_file_can_set_owner (file)) { /* Claim that something changed even if the permission * change failed. This makes it easier for some * clients who see the "reverting" to the old owner as * "changing back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, _("Not allowed to set owner")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* If no match treating user_name_or_id as name, try treating * it as id. */ if (!get_user_id_from_user_name (user_name_or_id, &new_id) && !get_id_from_digit_string (user_name_or_id, &new_id)) { /* Claim that something changed even if the permission * change failed. This makes it easier for some * clients who see the "reverting" to the old owner as * "changing back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Specified owner '%s' doesn't exist"), user_name_or_id); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* Test the owner-hasn't-changed case explicitly because we * don't want to send the file-changed signal if nothing * changed. */ if (new_id == (uid_t) file->details->uid) { (* callback) (file, NULL, NULL, callback_data); return; } if (!nemo_file_undo_manager_pop_flag ()) { NemoFileUndoInfo *undo_info; char* current_owner; current_owner = nemo_file_get_owner_as_string (file, FALSE); undo_info = nemo_file_undo_info_ownership_new (NEMO_FILE_UNDO_OP_CHANGE_OWNER, nemo_file_get_location (file), current_owner, user_name_or_id); nemo_file_undo_manager_set_action (undo_info); g_free (current_owner); } info = g_file_info_new (); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, new_id); nemo_file_set_attributes (file, info, callback, callback_data); g_object_unref (info); } /** * nemo_get_user_names: * * Get a list of user names. For users with a different associated * "real name", the real name follows the standard user name, separated * by a carriage return. The caller is responsible for freeing this list * and its contents. */ GList * nemo_get_user_names (void) { GList *list; char *real_name, *name; struct passwd *user; list = NULL; setpwent (); while ((user = getpwent ()) != NULL) { real_name = get_real_name (user->pw_name, user->pw_gecos); if (real_name != NULL) { name = g_strconcat (user->pw_name, "\n", real_name, NULL); } else { name = g_strdup (user->pw_name); } g_free (real_name); list = g_list_prepend (list, name); } endpwent (); return g_list_sort (list, (GCompareFunc) g_utf8_collate); } /** * nemo_file_can_get_group: * * Check whether the group a file is determinable. * This might not be the case for files on non-UNIX file systems. * * @file: The file in question. * * Return value: TRUE if the group is valid. */ gboolean nemo_file_can_get_group (NemoFile *file) { /* Before we have info on a file, the group is unknown. */ return file->details->gid != -1; } /** * nemo_file_get_group_name: * * Get the name of the file's group. If the group has no * name, returns the groupid as a string. The caller is responsible * for g_free-ing this string. * * @file: The file in question. * * Return value: A newly-allocated string. **/ char * nemo_file_get_group_name (NemoFile *file) { return g_strdup (eel_ref_str_peek (file->details->group)); } /** * nemo_file_can_set_group: * * Check whether the current user is allowed to change * the group of a file. * * @file: The file in question. * * Return value: TRUE if the current user can change the * group of @file, FALSE otherwise. It's always possible * that when you actually try to do it, you will fail. */ gboolean nemo_file_can_set_group (NemoFile *file) { uid_t user_id; /* Not allowed to set the permissions if we can't * even read them. This can happen on non-UNIX file * systems. */ if (!nemo_file_can_get_group (file)) { return FALSE; } /* Check the user. */ user_id = geteuid(); /* Owner is allowed to set group (with restrictions). */ if (user_id == (uid_t) file->details->uid) { return TRUE; } /* Root is also allowed to set group. */ if (user_id == 0) { return TRUE; } /* Nobody else is allowed. */ return FALSE; } /* Get a list of group names, filtered to only the ones * that contain the given username. If the username is * NULL, returns a list of all group names. */ static GList * nemo_get_group_names_for_user (void) { GList *list; struct group *group; int count, i; gid_t gid_list[NGROUPS_MAX + 1]; list = NULL; count = getgroups (NGROUPS_MAX + 1, gid_list); for (i = 0; i < count; i++) { group = getgrgid (gid_list[i]); if (group == NULL) break; list = g_list_prepend (list, g_strdup (group->gr_name)); } return g_list_sort (list, (GCompareFunc) g_utf8_collate); } /** * nemo_get_group_names: * * Get a list of all group names. */ GList * nemo_get_all_group_names (void) { GList *list; struct group *group; list = NULL; setgrent (); while ((group = getgrent ()) != NULL) list = g_list_prepend (list, g_strdup (group->gr_name)); endgrent (); return g_list_sort (list, (GCompareFunc) g_utf8_collate); } /** * nemo_file_get_settable_group_names: * * Get a list of all group names that the current user * can set the group of a specific file to. * * @file: The NemoFile in question. */ GList * nemo_file_get_settable_group_names (NemoFile *file) { uid_t user_id; GList *result; if (!nemo_file_can_set_group (file)) { return NULL; } /* Check the user. */ user_id = geteuid(); if (user_id == 0) { /* Root is allowed to set group to anything. */ result = nemo_get_all_group_names (); } else if (user_id == (uid_t) file->details->uid) { /* Owner is allowed to set group to any that owner is member of. */ result = nemo_get_group_names_for_user (); } else { g_warning ("unhandled case in nemo_get_settable_group_names"); result = NULL; } return result; } /** * nemo_file_set_group: * * Set the group of a file. This will only have any effect if * nemo_file_can_set_group returns TRUE. * * @file: The file in question. * @group_name_or_id: The group name to set the owner to. * If the string does not match any group name, and the * string is an integer, the group will be set to the * group id represented by that integer. * @callback: Function called when asynch group change succeeds or fails. * @callback_data: Parameter passed back with callback function. */ void nemo_file_set_group (NemoFile *file, const char *group_name_or_id, NemoFileOperationCallback callback, gpointer callback_data) { GError *error; GFileInfo *info; uid_t new_id; if (!nemo_file_can_set_group (file)) { /* Claim that something changed even if the group * change failed. This makes it easier for some * clients who see the "reverting" to the old group as * "changing back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, _("Not allowed to set group")); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } /* If no match treating group_name_or_id as name, try treating * it as id. */ if (!get_group_id_from_group_name (group_name_or_id, &new_id) && !get_id_from_digit_string (group_name_or_id, &new_id)) { /* Claim that something changed even if the group * change failed. This makes it easier for some * clients who see the "reverting" to the old group as * "changing back". */ nemo_file_changed (file); error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Specified group '%s' doesn't exist"), group_name_or_id); (* callback) (file, NULL, error, callback_data); g_error_free (error); return; } if (new_id == (gid_t) file->details->gid) { (* callback) (file, NULL, NULL, callback_data); return; } if (!nemo_file_undo_manager_pop_flag ()) { NemoFileUndoInfo *undo_info; char *current_group; current_group = nemo_file_get_group_name (file); undo_info = nemo_file_undo_info_ownership_new (NEMO_FILE_UNDO_OP_CHANGE_GROUP, nemo_file_get_location (file), current_group, group_name_or_id); nemo_file_undo_manager_set_action (undo_info); g_free (current_group); } info = g_file_info_new (); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, new_id); nemo_file_set_attributes (file, info, callback, callback_data); g_object_unref (info); } /** * nemo_file_get_octal_permissions_as_string: * * Get a user-displayable string representing a file's permissions * as an octal number. The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_octal_permissions_as_string (NemoFile *file) { guint32 permissions; g_assert (NEMO_IS_FILE (file)); if (!nemo_file_can_get_permissions (file)) { return NULL; } permissions = file->details->permissions; return g_strdup_printf ("%03o", permissions); } /** * nemo_file_get_permissions_as_string: * * Get a user-displayable string representing a file's permissions. The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_permissions_as_string (NemoFile *file) { guint32 permissions; gboolean is_directory; gboolean is_link; gboolean suid, sgid, sticky; if (!nemo_file_can_get_permissions (file)) { return NULL; } g_assert (NEMO_IS_FILE (file)); permissions = file->details->permissions; is_directory = nemo_file_is_directory (file); is_link = nemo_file_is_symbolic_link (file); /* We use ls conventions for displaying these three obscure flags */ suid = permissions & S_ISUID; sgid = permissions & S_ISGID; sticky = permissions & S_ISVTX; return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", is_link ? 'l' : is_directory ? 'd' : '-', permissions & S_IRUSR ? 'r' : '-', permissions & S_IWUSR ? 'w' : '-', permissions & S_IXUSR ? (suid ? 's' : 'x') : (suid ? 'S' : '-'), permissions & S_IRGRP ? 'r' : '-', permissions & S_IWGRP ? 'w' : '-', permissions & S_IXGRP ? (sgid ? 's' : 'x') : (sgid ? 'S' : '-'), permissions & S_IROTH ? 'r' : '-', permissions & S_IWOTH ? 'w' : '-', permissions & S_IXOTH ? (sticky ? 't' : 'x') : (sticky ? 'T' : '-')); } /** * nemo_file_get_owner_as_string: * * Get a user-displayable string representing a file's owner. The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * @include_real_name: Whether or not to append the real name (if any) * for this user after the user name. * * Returns: Newly allocated string ready to display to the user. * **/ char * nemo_file_get_owner_as_string (NemoFile *file, gboolean include_real_name) { char *user_name; /* Before we have info on a file, the owner is unknown. */ if (file->details->owner == NULL && file->details->owner_real == NULL) { return NULL; } if (file->details->owner_real == NULL) { user_name = g_strdup (eel_ref_str_peek (file->details->owner)); } else if (file->details->owner == NULL) { user_name = g_strdup (eel_ref_str_peek (file->details->owner_real)); } else if (include_real_name && strcmp (eel_ref_str_peek (file->details->owner), eel_ref_str_peek (file->details->owner_real)) != 0) { user_name = g_strdup_printf ("%s - %s", eel_ref_str_peek (file->details->owner), eel_ref_str_peek (file->details->owner_real)); } else { user_name = g_strdup (eel_ref_str_peek (file->details->owner)); } return user_name; } static char * format_item_count_for_display (guint item_count, gboolean includes_directories, gboolean includes_files) { g_assert (includes_directories || includes_files); return g_strdup_printf (includes_directories ? (includes_files ? ngettext ("%'u item", "%'u items", item_count) : ngettext ("%'u folder", "%'u folders", item_count)) : ngettext ("%'u file", "%'u files", item_count), item_count); } /** * nemo_file_get_size_as_string: * * Get a user-displayable string representing a file size. The caller * is responsible for g_free-ing this string. The string is an item * count for directories. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_size_as_string (NemoFile *file) { guint item_count; gboolean count_unreadable; if (file == NULL) { return NULL; } g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_directory (file)) { if (!nemo_file_get_directory_item_count (file, &item_count, &count_unreadable)) { return NULL; } return format_item_count_for_display (item_count, TRUE, TRUE); } if (file->details->size == -1) { return NULL; } return g_format_size_full (file->details->size, nemo_global_preferences_get_size_prefix_preference ()); } /** * nemo_file_get_size_as_string_with_real_size: * * Get a user-displayable string representing a file size. The caller * is responsible for g_free-ing this string. The string is an item * count for directories. * This function adds the real size in the string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_size_as_string_with_real_size (NemoFile *file) { guint item_count; gboolean count_unreadable; int prefix; if (file == NULL) { return NULL; } g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_directory (file)) { if (!nemo_file_get_directory_item_count (file, &item_count, &count_unreadable)) { return NULL; } return format_item_count_for_display (item_count, TRUE, TRUE); } if (file->details->size == -1) { return NULL; } /* If base-2 or base-2-full, then prefix will be 2 (i.e. base-2), if base-10 or base-10-long then prefix will be 0 (i.e. base-0). Prefix will be added to LONG_FORMAT */ prefix = nemo_global_preferences_get_size_prefix_preference () * 2; return g_format_size_full (file->details->size, G_FORMAT_SIZE_LONG_FORMAT + prefix); } static char * nemo_file_get_deep_count_as_string_internal (NemoFile *file, gboolean report_size, gboolean report_directory_count, gboolean report_file_count) { NemoRequestStatus status; guint directory_count; guint file_count; guint unreadable_count; guint hidden_count; guint total_count; goffset total_size; int prefix; /* Must ask for size or some kind of count, but not both. */ g_assert (!report_size || (!report_directory_count && !report_file_count)); g_assert (report_size || report_directory_count || report_file_count); if (file == NULL) { return NULL; } g_assert (NEMO_IS_FILE (file)); g_assert (nemo_file_is_directory (file)); status = nemo_file_get_deep_counts (file, &directory_count, &file_count, &unreadable_count, &hidden_count, &total_size, FALSE); /* Check whether any info is available. */ if (status == NEMO_REQUEST_NOT_STARTED) { return NULL; } total_count = file_count + directory_count; if (total_count == 0) { switch (status) { case NEMO_REQUEST_IN_PROGRESS: /* Don't return confident "zero" until we're finished looking, * because of next case. */ return NULL; case NEMO_REQUEST_DONE: /* Don't return "zero" if we there were contents but we couldn't read them. */ if (unreadable_count != 0) { return NULL; } case NEMO_REQUEST_NOT_STARTED: default: break; } } /* Note that we don't distinguish the "everything was readable" case * from the "some things but not everything was readable" case here. * Callers can distinguish them using nemo_file_get_deep_counts * directly if desired. */ if (report_size) { prefix = nemo_global_preferences_get_size_prefix_preference (); return g_format_size_full (total_size, prefix); } return format_item_count_for_display (report_directory_count ? (report_file_count ? total_count : directory_count) : file_count, report_directory_count, report_file_count); } /** * nemo_file_get_deep_size_as_string: * * Get a user-displayable string representing the size of all contained * items (only makes sense for directories). The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_deep_size_as_string (NemoFile *file) { return nemo_file_get_deep_count_as_string_internal (file, TRUE, FALSE, FALSE); } /** * nemo_file_get_deep_total_count_as_string: * * Get a user-displayable string representing the count of all contained * items (only makes sense for directories). The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_deep_total_count_as_string (NemoFile *file) { return nemo_file_get_deep_count_as_string_internal (file, FALSE, TRUE, TRUE); } /** * nemo_file_get_deep_file_count_as_string: * * Get a user-displayable string representing the count of all contained * items, not including directories. It only makes sense to call this * function on a directory. The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_deep_file_count_as_string (NemoFile *file) { return nemo_file_get_deep_count_as_string_internal (file, FALSE, FALSE, TRUE); } /** * nemo_file_get_deep_directory_count_as_string: * * Get a user-displayable string representing the count of all contained * directories. It only makes sense to call this * function on a directory. The caller * is responsible for g_free-ing this string. * @file: NemoFile representing the file in question. * * Returns: Newly allocated string ready to display to the user. * **/ static char * nemo_file_get_deep_directory_count_as_string (NemoFile *file) { return nemo_file_get_deep_count_as_string_internal (file, FALSE, TRUE, FALSE); } /** * nemo_file_get_string_attribute: * * Get a user-displayable string from a named attribute. Use g_free to * free this string. If the value is unknown, returns NULL. You can call * nemo_file_get_string_attribute_with_default if you want a non-NULL * default. * * @file: NemoFile representing the file in question. * @attribute_name: The name of the desired attribute. The currently supported * set includes "name", "type", "detailed_type", "mime_type", "size", "deep_size", "deep_directory_count", * "deep_file_count", "deep_total_count", "date_modified", "date_changed", "date_accessed", * "date_permissions", "owner", "group", "permissions", "octal_permissions", "uri", "where", * "link_target", "volume", "free_space", "selinux_context", "trashed_on", "trashed_orig_path" * * Returns: Newly allocated string ready to display to the user, or NULL * if the value is unknown or @attribute_name is not supported. * **/ char * nemo_file_get_string_attribute_q (NemoFile *file, GQuark attribute_q) { char *extension_attribute; if (attribute_q == attribute_name_q) { return nemo_file_get_display_name (file); } if (attribute_q == attribute_type_q) { return nemo_file_get_type_as_string (file); } if (attribute_q == attribute_detailed_type_q) { return nemo_file_get_detailed_type_as_string (file); } if (attribute_q == attribute_mime_type_q) { return nemo_file_get_mime_type (file); } if (attribute_q == attribute_size_q) { return nemo_file_get_size_as_string (file); } if (attribute_q == attribute_size_detail_q) { return nemo_file_get_size_as_string_with_real_size (file); } if (attribute_q == attribute_deep_size_q) { return nemo_file_get_deep_size_as_string (file); } if (attribute_q == attribute_deep_file_count_q) { return nemo_file_get_deep_file_count_as_string (file); } if (attribute_q == attribute_deep_directory_count_q) { return nemo_file_get_deep_directory_count_as_string (file); } if (attribute_q == attribute_deep_total_count_q) { return nemo_file_get_deep_total_count_as_string (file); } if (attribute_q == attribute_trash_orig_path_q) { return nemo_file_get_trash_original_file_parent_as_string (file); } if (attribute_q == attribute_date_modified_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_MODIFIED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_date_modified_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_MODIFIED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_date_modified_with_time_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_MODIFIED, NEMO_DATE_FORMAT_REGULAR_WITH_TIME); } if (attribute_q == attribute_date_changed_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CHANGED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_date_changed_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CHANGED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_date_accessed_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_ACCESSED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_date_accessed_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_ACCESSED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_date_created_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CREATED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_date_created_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CREATED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_date_created_with_time_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CREATED, NEMO_DATE_FORMAT_REGULAR_WITH_TIME); } if (attribute_q == attribute_trashed_on_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_TRASHED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_trashed_on_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_TRASHED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_date_permissions_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_PERMISSIONS_CHANGED, NEMO_DATE_FORMAT_FULL); } if (attribute_q == attribute_date_permissions_full_q) { return nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_PERMISSIONS_CHANGED, NEMO_DATE_FORMAT_REGULAR); } if (attribute_q == attribute_permissions_q) { return nemo_file_get_permissions_as_string (file); } if (attribute_q == attribute_selinux_context_q) { return nemo_file_get_selinux_context (file); } if (attribute_q == attribute_octal_permissions_q) { return nemo_file_get_octal_permissions_as_string (file); } if (attribute_q == attribute_owner_q) { return nemo_file_get_owner_as_string (file, TRUE); } if (attribute_q == attribute_group_q) { return nemo_file_get_group_name (file); } if (attribute_q == attribute_uri_q) { return nemo_file_get_uri (file); } if (attribute_q == attribute_where_q) { return nemo_file_get_where_string (file); } if (attribute_q == attribute_link_target_q) { return nemo_file_get_symbolic_link_target_path (file); } if (attribute_q == attribute_volume_q) { return nemo_file_get_volume_name (file); } if (attribute_q == attribute_free_space_q) { return nemo_file_get_volume_free_space (file); } extension_attribute = NULL; if (file->details->pending_extension_attributes) { extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes, GINT_TO_POINTER (attribute_q)); } if (extension_attribute == NULL && file->details->extension_attributes) { extension_attribute = g_hash_table_lookup (file->details->extension_attributes, GINT_TO_POINTER (attribute_q)); } return g_strdup (extension_attribute); } char * nemo_file_get_string_attribute (NemoFile *file, const char *attribute_name) { return nemo_file_get_string_attribute_q (file, g_quark_from_string (attribute_name)); } /** * nemo_file_get_string_attribute_with_default: * * Get a user-displayable string from a named attribute. Use g_free to * free this string. If the value is unknown, returns a string representing * the unknown value, which varies with attribute. You can call * nemo_file_get_string_attribute if you want NULL instead of a default * result. * * @file: NemoFile representing the file in question. * @attribute_name: The name of the desired attribute. See the description of * nemo_file_get_string for the set of available attributes. * * Returns: Newly allocated string ready to display to the user, or a string * such as "unknown" if the value is unknown or @attribute_name is not supported. * **/ char * nemo_file_get_string_attribute_with_default_q (NemoFile *file, GQuark attribute_q) { char *result; guint item_count; gboolean count_unreadable; NemoRequestStatus status; result = nemo_file_get_string_attribute_q (file, attribute_q); if (result != NULL) { return result; } /* Supply default values for the ones we know about. */ /* FIXME bugzilla.gnome.org 40646: * Use hash table and switch statement or function pointers for speed? */ if (attribute_q == attribute_size_q) { if (!nemo_file_should_show_directory_item_count (file)) { return g_strdup ("--"); } count_unreadable = FALSE; if (nemo_file_is_directory (file)) { nemo_file_get_directory_item_count (file, &item_count, &count_unreadable); } return g_strdup (count_unreadable ? _("? items") : "..."); } if (attribute_q == attribute_deep_size_q) { status = nemo_file_get_deep_counts (file, NULL, NULL, NULL, NULL, NULL, FALSE); if (status == NEMO_REQUEST_DONE) { /* This means no contents at all were readable */ return g_strdup (_("? bytes")); } return g_strdup ("..."); } if (attribute_q == attribute_deep_file_count_q || attribute_q == attribute_deep_directory_count_q || attribute_q == attribute_deep_total_count_q) { status = nemo_file_get_deep_counts (file, NULL, NULL, NULL, NULL, NULL, FALSE); if (status == NEMO_REQUEST_DONE) { /* This means no contents at all were readable */ return g_strdup (_("? items")); } return g_strdup ("..."); } if (attribute_q == attribute_type_q || attribute_q == attribute_detailed_type_q || attribute_q == attribute_mime_type_q) { return g_strdup (_("Unknown")); } if (attribute_q == attribute_trashed_on_q) { /* If n/a */ return g_strdup (""); } if (attribute_q == attribute_trash_orig_path_q) { /* If n/a */ return g_strdup (""); } /* Fallback, use for both unknown attributes and attributes * for which we have no more appropriate default. */ return g_strdup (_("unknown")); } char * nemo_file_get_string_attribute_with_default (NemoFile *file, const char *attribute_name) { return nemo_file_get_string_attribute_with_default_q (file, g_quark_from_string (attribute_name)); } gboolean nemo_file_is_date_sort_attribute_q (GQuark attribute_q) { if (attribute_q == attribute_modification_date_q || attribute_q == attribute_date_modified_q || attribute_q == attribute_date_modified_full_q || attribute_q == attribute_date_modified_with_time_q || attribute_q == attribute_accessed_date_q || attribute_q == attribute_date_accessed_q || attribute_q == attribute_date_accessed_full_q || attribute_q == attribute_date_changed_q || attribute_q == attribute_date_changed_full_q || attribute_q == attribute_trashed_on_q || attribute_q == attribute_trashed_on_full_q || attribute_q == attribute_date_permissions_q || attribute_q == attribute_date_permissions_full_q || attribute_q == attribute_creation_date_q || attribute_q == attribute_date_created_q || attribute_q == attribute_date_created_full_q || attribute_q == attribute_date_created_with_time_q) { return TRUE; } return FALSE; } struct { const char *icon_name; const char *display_name; } mime_type_map[] = { { "application-x-executable", N_("Program") }, { "audio-x-generic", N_("Audio") }, { "font-x-generic", N_("Font") }, { "image-x-generic", N_("Image") }, { "package-x-generic", N_("Archive") }, { "text-html", N_("Markup") }, { "text-x-generic", N_("Text") }, { "text-x-generic-template", N_("Text") }, { "text-x-script", N_("Program") }, { "video-x-generic", N_("Video") }, { "x-office-address-book", N_("Contacts") }, { "x-office-calendar", N_("Calendar") }, { "x-office-document", N_("Document") }, { "x-office-presentation", N_("Presentation") }, { "x-office-spreadsheet", N_("Spreadsheet") }, }; static char * get_basic_type_for_mime_type (const char *mime_type) { char *icon_name; char *basic_type = NULL; icon_name = g_content_type_get_generic_icon_name (mime_type); if (icon_name != NULL) { guint i; for (i = 0; i < G_N_ELEMENTS (mime_type_map); i++) { if (strcmp (mime_type_map[i].icon_name, icon_name) == 0) { basic_type = g_strdup (gettext (mime_type_map[i].display_name)); break; } } } if (basic_type == NULL) { basic_type = g_strdup (_("Unknown")); } g_free (icon_name); return basic_type; } static char * get_description (NemoFile *file, gboolean detailed) { const char *mime_type; g_assert (NEMO_IS_FILE (file)); mime_type = eel_ref_str_peek (file->details->mime_type); if (mime_type == NULL) { return NULL; } if (g_content_type_is_unknown (mime_type)) { if (nemo_file_is_executable (file)) { return g_strdup (_("Program")); } return g_strdup (_("Binary")); } if (strcmp (mime_type, "inode/directory") == 0) { return g_strdup (_("Folder")); } if (detailed) { char *description; description = g_content_type_get_description (mime_type); if (description != NULL) { return description; } } else { char *category; category = get_basic_type_for_mime_type (mime_type); if (category != NULL) { return category; } } return g_strdup (mime_type); } /* Takes ownership of string */ static char * update_description_for_link (NemoFile *file, char *string) { char *res; if (nemo_file_is_symbolic_link (file)) { g_assert (!nemo_file_is_broken_symbolic_link (file)); if (string == NULL) { return g_strdup (_("link")); } /* Note to localizers: convert file type string for file * (e.g. "folder", "plain text") to file type for symbolic link * to that kind of file (e.g. "link to folder"). */ res = g_strdup_printf (_("Link to %s"), string); g_free (string); return res; } return string; } char * nemo_file_get_type_as_string (NemoFile *file) { if (file == NULL) { return NULL; } if (nemo_file_is_broken_symbolic_link (file)) { return g_strdup (_("link (broken)")); } return update_description_for_link (file, get_description (file, FALSE)); } char * nemo_file_get_detailed_type_as_string (NemoFile *file) { if (file == NULL) { return NULL; } if (nemo_file_is_broken_symbolic_link (file)) { return g_strdup (_("link (broken)")); } return update_description_for_link (file, get_description (file, TRUE)); } /** * nemo_file_get_file_type * * Return this file's type. * @file: NemoFile representing the file in question. * * Returns: The type. * **/ GFileType nemo_file_get_file_type (NemoFile *file) { if (file == NULL) { return G_FILE_TYPE_UNKNOWN; } return file->details->type; } /** * nemo_file_get_mime_type * * Return this file's default mime type. * @file: NemoFile representing the file in question. * * Returns: The mime type. * **/ char * nemo_file_get_mime_type (NemoFile *file) { if (file != NULL) { g_return_val_if_fail (NEMO_IS_FILE (file), NULL); if (file->details->mime_type != NULL) { return g_strdup (eel_ref_str_peek (file->details->mime_type)); } } return g_strdup ("application/octet-stream"); } /** * nemo_file_is_mime_type * * Check whether a file is of a particular MIME type, or inherited * from it. * @file: NemoFile representing the file in question. * @mime_type: The MIME-type string to test (e.g. "text/plain") * * Return value: TRUE if @mime_type exactly matches the * file's MIME type. * **/ gboolean nemo_file_is_mime_type (NemoFile *file, const char *mime_type) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); g_return_val_if_fail (mime_type != NULL, FALSE); if (file->details->mime_type == NULL) { return FALSE; } return g_content_type_is_a (eel_ref_str_peek (file->details->mime_type), mime_type); } gboolean nemo_file_is_launchable (NemoFile *file) { gboolean type_can_be_executable; type_can_be_executable = FALSE; if (file->details->mime_type != NULL) { type_can_be_executable = g_content_type_can_be_executable (eel_ref_str_peek (file->details->mime_type)); } return type_can_be_executable && nemo_file_can_get_permissions (file) && nemo_file_can_execute (file) && nemo_file_is_executable (file) && !nemo_file_is_directory (file); } /** * nemo_file_get_emblem_icons * * Return the list of names of emblems that this file should display, * in canonical order. * @file: NemoFile representing the file in question. * @view_file: NemoFile representing the view's directory_as_file. * * Returns: A list of emblem names. * **/ GList * nemo_file_get_emblem_icons (NemoFile *file, NemoFile *view_file) { GList *keywords, *l; GList *icons; char *icon_names[2]; char *keyword; GIcon *icon; if (file == NULL) { return NULL; } g_return_val_if_fail (NEMO_IS_FILE (file), NULL); keywords = nemo_file_get_keywords (file); keywords = prepend_automatic_keywords (file, keywords); if (view_file && nemo_file_can_write (view_file)) { if (!nemo_file_can_write (file) && !nemo_file_is_in_trash (file)) { keywords = g_list_prepend (keywords, g_strdup (NEMO_FILE_EMBLEM_NAME_CANT_WRITE)); } } icons = NULL; for (l = keywords; l != NULL; l = l->next) { keyword = l->data; icon_names[0] = g_strconcat ("emblem-", keyword, NULL); icon_names[1] = keyword; icon = g_themed_icon_new_from_names (icon_names, 2); g_free (icon_names[0]); icons = g_list_prepend (icons, icon); } g_list_free_full (keywords, g_free); return icons; } static GList * sort_keyword_list_and_remove_duplicates (GList *keywords) { GList *p; GList *duplicate_link; if (keywords != NULL) { keywords = g_list_sort (keywords, (GCompareFunc) g_utf8_collate); p = keywords; while (p->next != NULL) { if (strcmp ((const char *) p->data, (const char *) p->next->data) == 0) { duplicate_link = p->next; keywords = g_list_remove_link (keywords, duplicate_link); g_list_free_full (duplicate_link, g_free); } else { p = p->next; } } } return keywords; } /** * nemo_file_get_keywords * * Return this file's keywords. * @file: NemoFile representing the file in question. * * Returns: A list of keywords. * **/ GList * nemo_file_get_keywords (NemoFile *file) { GList *keywords; if (file == NULL) { return NULL; } g_return_val_if_fail (NEMO_IS_FILE (file), NULL); keywords = eel_g_str_list_copy (file->details->extension_emblems); keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems)); keywords = g_list_concat (keywords, nemo_file_get_metadata_list (file, NEMO_METADATA_KEY_EMBLEMS)); return sort_keyword_list_and_remove_duplicates (keywords); } /** * nemo_file_is_symbolic_link * * Check if this file is a symbolic link. * @file: NemoFile representing the file in question. * * Returns: True if the file is a symbolic link. * **/ gboolean nemo_file_is_symbolic_link (NemoFile *file) { return file->details->is_symlink; } gboolean nemo_file_is_mountpoint (NemoFile *file) { return file->details->is_mountpoint; } GMount * nemo_file_get_mount (NemoFile *file) { if (file->details->mount) { return g_object_ref (file->details->mount); } return NULL; } static void file_mount_unmounted (GMount *mount, gpointer data) { NemoFile *file; file = NEMO_FILE (data); nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_MOUNT); } void nemo_file_set_mount (NemoFile *file, GMount *mount) { if (file->details->mount) { g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file); g_object_unref (file->details->mount); file->details->mount = NULL; } if (mount) { file->details->mount = g_object_ref (mount); g_signal_connect (mount, "unmounted", G_CALLBACK (file_mount_unmounted), file); } } /** * nemo_file_is_broken_symbolic_link * * Check if this file is a symbolic link with a missing target. * @file: NemoFile representing the file in question. * * Returns: True if the file is a symbolic link with a missing target. * **/ gboolean nemo_file_is_broken_symbolic_link (NemoFile *file) { if (file == NULL) { return FALSE; } g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); /* Non-broken symbolic links return the target's type for get_file_type. */ return nemo_file_get_file_type (file) == G_FILE_TYPE_SYMBOLIC_LINK; } static void get_fs_free_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoFile *file; guint64 free_space; GFileInfo *info; file = NEMO_FILE (user_data); free_space = (guint64)-1; info = g_file_query_filesystem_info_finish (G_FILE (source_object), res, NULL); if (info) { if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) { free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); } g_object_unref (info); } if (file->details->free_space != free_space) { file->details->free_space = free_space; nemo_file_emit_changed (file); } nemo_file_unref (file); } /** * nemo_file_get_volume_free_space * Get a nicely formatted char with free space on the file's volume * @file: NemoFile representing the file in question. * * Returns: newly-allocated copy of file size in a formatted string */ char * nemo_file_get_volume_free_space (NemoFile *file) { GFile *location; char *res; time_t now; int prefix; now = time (NULL); /* Update first time and then every 2 seconds */ if (file->details->free_space_read == 0 || (now - file->details->free_space_read) > 2) { file->details->free_space_read = now; location = nemo_file_get_location (file); g_file_query_filesystem_info_async (location, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, 0, NULL, get_fs_free_cb, nemo_file_ref (file)); g_object_unref (location); } res = NULL; if (file->details->free_space != (guint64)-1) { prefix = nemo_global_preferences_get_size_prefix_preference (); res = g_format_size_full (file->details->free_space, prefix); } return res; } /** * nemo_file_get_volume_name * Get the path of the volume the file resides on * @file: NemoFile representing the file in question. * * Returns: newly-allocated copy of the volume name of the target file, * if the volume name isn't set, it returns the mount path of the volume */ char * nemo_file_get_volume_name (NemoFile *file) { GFile *location; char *res; GMount *mount; res = NULL; location = nemo_file_get_location (file); mount = g_file_find_enclosing_mount (location, NULL, NULL); if (mount) { res = g_strdup (g_mount_get_name (mount)); g_object_unref (mount); } g_object_unref (location); return res; } /** * nemo_file_get_symbolic_link_target_path * * Get the file path of the target of a symbolic link. It is an error * to call this function on a file that isn't a symbolic link. * @file: NemoFile representing the symbolic link in question. * * Returns: newly-allocated copy of the file path of the target of the symbolic link. */ char * nemo_file_get_symbolic_link_target_path (NemoFile *file) { if (!nemo_file_is_symbolic_link (file)) { g_warning ("File has symlink target, but is not marked as symlink"); } return g_strdup (file->details->symlink_name); } /** * nemo_file_get_symbolic_link_target_uri * * Get the uri of the target of a symbolic link. It is an error * to call this function on a file that isn't a symbolic link. * @file: NemoFile representing the symbolic link in question. * * Returns: newly-allocated copy of the uri of the target of the symbolic link. */ char * nemo_file_get_symbolic_link_target_uri (NemoFile *file) { GFile *location, *parent, *target; char *target_uri; if (!nemo_file_is_symbolic_link (file)) { g_warning ("File has symlink target, but is not marked as symlink"); } if (file->details->symlink_name == NULL) { return NULL; } else { target = NULL; location = nemo_file_get_location (file); parent = g_file_get_parent (location); g_object_unref (location); if (parent) { target = g_file_resolve_relative_path (parent, file->details->symlink_name); g_object_unref (parent); } target_uri = NULL; if (target) { target_uri = g_file_get_uri (target); g_object_unref (target); } return target_uri; } } /** * nemo_file_is_nemo_link * * Check if this file is a "nemo link", meaning a historical * nemo xml link file or a desktop file. * @file: NemoFile representing the file in question. * * Returns: True if the file is a nemo link. * **/ gboolean nemo_file_is_nemo_link (NemoFile *file) { if (file->details->mime_type == NULL) { return FALSE; } return g_content_type_equals (eel_ref_str_peek (file->details->mime_type), "application/x-desktop"); } /** * nemo_file_is_directory * * Check if this file is a directory. * @file: NemoFile representing the file in question. * * Returns: TRUE if @file is a directory. * **/ gboolean nemo_file_is_directory (NemoFile *file) { return nemo_file_get_file_type (file) == G_FILE_TYPE_DIRECTORY; } /** * nemo_file_is_user_special_directory * * Check if this file is a special platform directory. * @file: NemoFile representing the file in question. * @special_directory: GUserDirectory representing the type to test for * * Returns: TRUE if @file is a special directory of the given kind. */ gboolean nemo_file_is_user_special_directory (NemoFile *file, GUserDirectory special_directory) { gboolean is_special_dir; const gchar *special_dir; special_dir = g_get_user_special_dir (special_directory); is_special_dir = FALSE; if (special_dir) { GFile *loc; GFile *special_gfile; loc = nemo_file_get_location (file); special_gfile = g_file_new_for_path (special_dir); is_special_dir = g_file_equal (loc, special_gfile); g_object_unref (special_gfile); g_object_unref (loc); } return is_special_dir; } static const char * fallback_mime_types[] = { "application/x-gtar", "application/x-zip", "application/x-zip-compressed", "application/zip", "application/x-zip", "application/x-tar", "application/x-7z-compressed", "application/x-rar", "application/x-rar-compressed", "application/x-jar", "application/x-java-archive", "application/x-war", "application/x-ear", "application/x-arj", "application/x-gzip", "application/x-bzip-compressed-tar", "application/x-compressed-tar", "application/x-xz-compressed-tar" }; gboolean nemo_file_is_archive (NemoFile *file) { gchar *mime_type; gchar **file_roller_mimetypes; guint i; g_return_val_if_fail (file != NULL, FALSE); mime_type = nemo_file_get_mime_type (file); file_roller_mimetypes = nemo_global_preferences_get_fileroller_mimetypes (); if (file_roller_mimetypes != NULL) { for (i = 0; i < g_strv_length (file_roller_mimetypes); i++) { if (!strcmp (mime_type, file_roller_mimetypes[i])) { g_free (mime_type); return TRUE; } } } else { for (i = 0; i < G_N_ELEMENTS (fallback_mime_types); i++) { if (!strcmp (mime_type, fallback_mime_types[i])) { g_free (mime_type); return TRUE; } } } g_free (mime_type); return FALSE; } /** * nemo_file_is_in_trash * * Check if this file is a file in trash. * @file: NemoFile representing the file in question. * * Returns: TRUE if @file is in a trash. * **/ gboolean nemo_file_is_in_trash (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); return nemo_directory_is_in_trash (file->details->directory); } /** * nemo_file_is_in_recent * * Check if this file is a file in Recent. * @file: NemoFile representing the file in question. * * Returns: TRUE if @file is in Recent. * **/ gboolean nemo_file_is_in_recent (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); return nemo_directory_is_in_recent (file->details->directory); } /** * nemo_file_is_in_admin * * Check if this file is using admin backend. * @file: NemoFile representing the file in question. * * Returns: TRUE if @file is using admin backend. * **/ gboolean nemo_file_is_in_admin (NemoFile *file) { g_assert (NEMO_IS_FILE (file)); return nemo_directory_is_in_admin (file->details->directory); } GError * nemo_file_get_file_info_error (NemoFile *file) { if (!file->details->get_info_failed) { return NULL; } return file->details->get_info_error; } /** * nemo_file_contains_text * * Check if this file contains text. * This is private and is used to decide whether or not to read the top left text. * @file: NemoFile representing the file in question. * * Returns: TRUE if @file has a text MIME type. * **/ gboolean nemo_file_contains_text (NemoFile *file) { if (file == NULL) { return FALSE; } /* All text files inherit from text/plain */ return nemo_file_is_mime_type (file, "text/plain"); } /** * nemo_file_is_executable * * Check if this file is executable at all. * @file: NemoFile representing the file in question. * * Returns: TRUE if any of the execute bits are set. FALSE if * not, or if the permissions are unknown. * **/ gboolean nemo_file_is_executable (NemoFile *file) { if (!file->details->has_permissions) { /* File's permissions field is not valid. * Can't access specific permissions, so return FALSE. */ return FALSE; } return file->details->can_execute; } char * nemo_file_get_filesystem_id (NemoFile *file) { return g_strdup (eel_ref_str_peek (file->details->filesystem_id)); } NemoFile * nemo_file_get_trash_original_file (NemoFile *file) { GFile *location; NemoFile *original_file; original_file = NULL; if (file->details->trash_orig_path != NULL) { location = g_file_new_for_path (file->details->trash_orig_path); original_file = nemo_file_get (location); g_object_unref (location); } return original_file; } void nemo_file_mark_gone (NemoFile *file) { NemoDirectory *directory; if (file->details->is_gone) return; file->details->is_gone = TRUE; update_links_if_target (file); /* Drop it from the symlink hash ! */ remove_from_link_hash_table (file); /* Let the directory know it's gone. */ directory = file->details->directory; if (!nemo_file_is_self_owned (file)) { nemo_directory_remove_file (directory, file); } nemo_file_clear_info (file); /* FIXME bugzilla.gnome.org 42429: * Maybe we can get rid of the name too eventually, but * for now that would probably require too many if statements * everywhere anyone deals with the name. Maybe we can give it * a hard-coded "" name or something. */ } /** * nemo_file_changed * * Notify the user that this file has changed. * @file: NemoFile representing the file in question. **/ void nemo_file_changed (NemoFile *file) { GList fake_list; g_return_if_fail (NEMO_IS_FILE (file)); if (nemo_file_is_self_owned (file)) { nemo_file_emit_changed (file); } else { fake_list.data = file; fake_list.next = NULL; fake_list.prev = NULL; nemo_directory_emit_change_signals (file->details->directory, &fake_list); } } /** * nemo_file_updated_deep_count_in_progress * * Notify clients that a newer deep count is available for * the directory in question. */ void nemo_file_updated_deep_count_in_progress (NemoFile *file) { GList *link_files, *node; g_assert (NEMO_IS_FILE (file)); g_assert (nemo_file_is_directory (file)); /* Send out a signal. */ g_signal_emit (file, signals[UPDATED_DEEP_COUNT_IN_PROGRESS], 0, file); /* Tell link files pointing to this object about the change. */ link_files = get_link_files (file); for (node = link_files; node != NULL; node = node->next) { nemo_file_updated_deep_count_in_progress (NEMO_FILE (node->data)); } nemo_file_list_free (link_files); } /** * nemo_file_emit_changed * * Emit a file changed signal. * This can only be called by the directory, since the directory * also has to emit a files_changed signal. * * @file: NemoFile representing the file in question. **/ void nemo_file_emit_changed (NemoFile *file) { GList *link_files, *p; g_assert (NEMO_IS_FILE (file)); /* Send out a signal. */ g_signal_emit (file, signals[CHANGED], 0, file); /* Tell link files pointing to this object about the change. */ link_files = get_link_files (file); for (p = link_files; p != NULL; p = p->next) { if (p->data != file) { nemo_file_changed (NEMO_FILE (p->data)); } } nemo_file_list_free (link_files); } /** * nemo_file_is_gone * * Check if a file has already been deleted. * @file: NemoFile representing the file in question. * * Returns: TRUE if the file is already gone. **/ gboolean nemo_file_is_gone (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->is_gone; } /** * nemo_file_is_not_yet_confirmed * * Check if we're in a state where we don't know if a file really * exists or not, before the initial I/O is complete. * @file: NemoFile representing the file in question. * * Returns: TRUE if the file is already gone. **/ gboolean nemo_file_is_not_yet_confirmed (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return !file->details->got_file_info; } /** * nemo_file_check_if_ready * * Check whether the values for a set of file attributes are * currently available, without doing any additional work. This * is useful for callers that want to reflect updated information * when it is ready but don't want to force the work required to * obtain the information, which might be slow network calls, e.g. * * @file: The file being queried. * @file_attributes: A bit-mask with the desired information. * * Return value: TRUE if all of the specified attributes are currently readable. */ gboolean nemo_file_check_if_ready (NemoFile *file, NemoFileAttributes file_attributes) { /* To be parallel with call_when_ready, return * TRUE for NULL file. */ if (file == NULL) { return TRUE; } g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->check_if_ready (file, file_attributes); } void nemo_file_call_when_ready (NemoFile *file, NemoFileAttributes file_attributes, NemoFileCallback callback, gpointer callback_data) { if (file == NULL) { (* callback) (file, callback_data); return; } g_return_if_fail (NEMO_IS_FILE (file)); NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->call_when_ready (file, file_attributes, callback, callback_data); } void nemo_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data) { g_return_if_fail (callback != NULL); if (file == NULL) { return; } g_return_if_fail (NEMO_IS_FILE (file)); NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready (file, callback, callback_data); } static GString * add_line (GString *string, const gchar *add, gboolean prefix_newline) { if (prefix_newline) string = g_string_append (string, "\n"); return g_string_append (string, add); } gchar * nemo_file_construct_tooltip (NemoFile *file, NemoFileTooltipFlags flags) { gchar *scheme = nemo_file_get_uri_scheme (file); gchar *nice = NULL; gchar *tmp = NULL; gchar *date; gchar *ret; if (g_strcmp0 (scheme, "x-nemo-desktop") == 0) { g_free (scheme); return NULL; } GString *string = g_string_new (""); tmp = nemo_file_get_display_name (file); nice = g_strdup_printf (_("Name: %s"), tmp); string = add_line (string, nice, FALSE); g_free (nice); g_free (tmp); if (flags & NEMO_FILE_TOOLTIP_FLAGS_FILE_TYPE) { tmp = nemo_file_get_detailed_type_as_string (file); nice = g_strdup_printf (_("Type: %s"), tmp); string = add_line (string, nice, TRUE); g_free (tmp); g_free (nice); } if (nemo_file_is_directory (file)) { guint item_count; if (nemo_file_get_directory_item_count (file, &item_count, NULL)) { gchar *launchpad_sucks = THOU_TO_STR (item_count); gchar *count = g_strdup_printf (ngettext ("%s item", "%s items", item_count), launchpad_sucks); g_free (launchpad_sucks); nice = g_strdup_printf (_("Contains: %s"), count); string = add_line (string, nice, TRUE); g_free (count); g_free (nice); } } else { gchar *size_string; gint prefix; prefix = nemo_global_preferences_get_size_prefix_preference (); size_string = g_format_size_full (nemo_file_get_size (file), prefix); nice = g_strdup_printf (_("Size: %s"), size_string); string = add_line (string, nice, TRUE); g_free (size_string); g_free (nice); } if (flags & NEMO_FILE_TOOLTIP_FLAGS_ACCESS_DATE) { date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_ACCESSED, TRUE); tmp = g_strdup_printf (_("Accessed: %s"), date); g_free (date); string = add_line (string, tmp, TRUE); g_free (tmp); } if (flags & NEMO_FILE_TOOLTIP_FLAGS_MOD_DATE) { date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_MODIFIED, TRUE); tmp = g_strdup_printf (_("Modified: %s"), date); g_free (date); string = add_line (string, tmp, TRUE); g_free (tmp); } if (flags & NEMO_FILE_TOOLTIP_FLAGS_CREATED_DATE) { date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CREATED, TRUE); tmp = g_strdup_printf (_("Created: %s"), date); g_free (date); string = add_line (string, tmp, TRUE); g_free (tmp); } if (flags & NEMO_FILE_TOOLTIP_FLAGS_PATH) { NemoFile *parent = nemo_file_get_parent (file); tmp = nemo_file_get_path (parent); nice = g_strdup_printf (_("Location: %s"), tmp); string = add_line (string, nice, TRUE); g_free (tmp); g_free (nice); if (nemo_file_is_symbolic_link (file)) { tmp = nemo_file_get_symbolic_link_target_path (file); const gchar *existing_i18n = _("Link target:"); nice = g_strdup_printf ("%s %s", existing_i18n, tmp); string = add_line (string, nice, TRUE); g_free (tmp); g_free (nice); } } ret = string->str; g_string_free (string, FALSE); g_free (scheme); return ret; } gint nemo_file_get_monitor_number (NemoFile *file) { if (file->details->desktop_monitor == -1) { file->details->desktop_monitor = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_MONITOR, -1); } return file->details->desktop_monitor; } void nemo_file_set_monitor_number (NemoFile *file, gint monitor) { nemo_file_set_integer_metadata (file, NEMO_METADATA_KEY_MONITOR, -1, monitor); file->details->desktop_monitor = monitor; } void nemo_file_get_position (NemoFile *file, GdkPoint *point) { gint x, y; if (file->details->cached_position_x == -1) { char *position_string; gboolean position_good; char c; /* Get the current position of this icon from the metadata. */ position_string = nemo_file_get_metadata (file, NEMO_METADATA_KEY_ICON_POSITION, ""); position_good = sscanf (position_string, " %d , %d %c", &x, &y, &c) == 2; g_free (position_string); if (position_good) { point->x = x; point->y = y; } else { point->x = -1; point->y = -1; } file->details->cached_position_x = x; file->details->cached_position_y = y; } else { point->x = file->details->cached_position_x; point->y = file->details->cached_position_y; } } void nemo_file_set_position (NemoFile *file, gint x, gint y) { gchar *position_string; if (x > -1 && y > -1) { position_string = g_strdup_printf ("%d,%d", x, y); } else { position_string = NULL; } nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_POSITION, NULL, position_string); file->details->cached_position_x = x; file->details->cached_position_y = y; g_free (position_string); } gboolean nemo_file_get_is_desktop_orphan (NemoFile *file) { return file->details->is_desktop_orphan; } void nemo_file_set_is_desktop_orphan (NemoFile *file, gboolean is_desktop_orphan) { file->details->is_desktop_orphan = is_desktop_orphan; } gboolean nemo_file_has_thumbnail_access_problem (NemoFile *file) { return file->details->thumbnail_access_problem; } static void invalidate_directory_count (NemoFile *file) { file->details->directory_count_is_up_to_date = FALSE; } static void invalidate_deep_counts (NemoFile *file) { file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED; } static void invalidate_mime_list (NemoFile *file) { file->details->mime_list_is_up_to_date = FALSE; } static void invalidate_file_info (NemoFile *file) { file->details->file_info_is_up_to_date = FALSE; } static void invalidate_btime (NemoFile *file) { file->details->btime_is_up_to_date = FALSE; } static void invalidate_link_info (NemoFile *file) { file->details->link_info_is_up_to_date = FALSE; } static void invalidate_thumbnail (NemoFile *file) { file->details->thumbnail_is_up_to_date = FALSE; } static void invalidate_mount (NemoFile *file) { file->details->mount_is_up_to_date = FALSE; } void nemo_file_invalidate_extension_info_internal (NemoFile *file) { if (file->details->pending_info_providers) g_list_free_full (file->details->pending_info_providers, g_object_unref); file->details->pending_info_providers = nemo_module_get_extensions_for_type (NEMO_TYPE_INFO_PROVIDER); } void nemo_file_invalidate_attributes_internal (NemoFile *file, NemoFileAttributes file_attributes) { Request request; if (file == NULL) { return; } if (NEMO_IS_DESKTOP_ICON_FILE (file)) { /* Desktop icon files are always up to date. * If we invalidate their attributes they * will lose data, so we just ignore them. */ return; } request = nemo_directory_set_up_request (file_attributes); if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) { invalidate_directory_count (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) { invalidate_deep_counts (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) { invalidate_mime_list (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) { invalidate_file_info (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) { invalidate_btime (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) { invalidate_link_info (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) { nemo_file_invalidate_extension_info_internal (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) { invalidate_thumbnail (file); } if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) { invalidate_mount (file); } /* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */ } gboolean nemo_file_has_open_window (NemoFile *file) { return file->details->has_open_window; } void nemo_file_set_has_open_window (NemoFile *file, gboolean has_open_window) { has_open_window = (has_open_window != FALSE); if (file->details->has_open_window != has_open_window) { file->details->has_open_window = has_open_window; nemo_file_changed (file); } } gboolean nemo_file_is_thumbnailing (NemoFile *file) { g_return_val_if_fail (NEMO_IS_FILE (file), FALSE); return file->details->is_thumbnailing; } void nemo_file_set_is_thumbnailing (NemoFile *file, gboolean is_thumbnailing) { g_return_if_fail (NEMO_IS_FILE (file)); file->details->is_thumbnailing = is_thumbnailing; } /** * nemo_file_invalidate_attributes * * Invalidate the specified attributes and force a reload. * @file: NemoFile representing the file in question. * @file_attributes: attributes to froget. **/ void nemo_file_invalidate_attributes (NemoFile *file, NemoFileAttributes file_attributes) { /* Cancel possible in-progress loads of any of these attributes */ nemo_directory_cancel_loading_file_attributes (file->details->directory, file, file_attributes); /* Actually invalidate the values */ nemo_file_invalidate_attributes_internal (file, file_attributes); nemo_directory_add_file_to_work_queue (file->details->directory, file); /* Kick off I/O if necessary */ nemo_directory_async_state_changed (file->details->directory); } NemoFileAttributes nemo_file_get_all_attributes (void) { return NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO | NEMO_FILE_ATTRIBUTE_DEEP_COUNTS | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES | NEMO_FILE_ATTRIBUTE_EXTENSION_INFO | NEMO_FILE_ATTRIBUTE_THUMBNAIL | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_BTIME; } void nemo_file_invalidate_all_attributes (NemoFile *file) { NemoFileAttributes all_attributes; all_attributes = nemo_file_get_all_attributes (); nemo_file_invalidate_attributes (file, all_attributes); } /** * nemo_file_dump * * Debugging call, prints out the contents of the file * fields. * * @file: file to dump. **/ void nemo_file_dump (NemoFile *file) { long size = file->details->deep_size; char *uri; const char *file_kind; uri = nemo_file_get_uri (file); g_print ("uri: %s \n", uri); if (!file->details->got_file_info) { g_print ("no file info \n"); } else if (file->details->get_info_failed) { g_print ("failed to get file info \n"); } else { g_print ("size: %ld \n", size); switch (file->details->type) { case G_FILE_TYPE_REGULAR: file_kind = "regular file"; break; case G_FILE_TYPE_DIRECTORY: file_kind = "folder"; break; case G_FILE_TYPE_SPECIAL: file_kind = "special"; break; case G_FILE_TYPE_SYMBOLIC_LINK: file_kind = "symbolic link"; break; case G_FILE_TYPE_UNKNOWN: case G_FILE_TYPE_MOUNTABLE: case G_FILE_TYPE_SHORTCUT: /* FIXME should probably show details for these file types */ default: file_kind = "unknown"; break; } g_print ("kind: %s \n", file_kind); if (file->details->type == G_FILE_TYPE_SYMBOLIC_LINK) { g_print ("link to %s \n", file->details->symlink_name); /* FIXME bugzilla.gnome.org 42430: add following of symlinks here */ } /* FIXME bugzilla.gnome.org 42431: add permissions and other useful stuff here */ } g_free (uri); } /** * nemo_file_list_ref * * Ref all the files in a list. * @list: GList of files. **/ GList * nemo_file_list_ref (GList *list) { g_list_foreach (list, (GFunc) nemo_file_ref, NULL); return list; } /** * nemo_file_list_unref * * Unref all the files in a list. * @list: GList of files. **/ void nemo_file_list_unref (GList *list) { g_list_foreach (list, (GFunc) nemo_file_unref, NULL); } /** * nemo_file_list_free * * Free a list of files after unrefing them. * @list: GList of files. **/ void nemo_file_list_free (GList *list) { nemo_file_list_unref (list); g_list_free (list); } /** * nemo_file_list_copy * * Copy the list of files, making a new ref of each, * @list: GList of files. **/ GList * nemo_file_list_copy (GList *list) { return g_list_copy (nemo_file_list_ref (list)); } GList * nemo_file_list_from_uris (GList *uri_list) { GList *l, *file_list; const char *uri; GFile *file; file_list = NULL; for (l = uri_list; l != NULL; l = l->next) { uri = l->data; file = g_file_new_for_uri (uri); file_list = g_list_prepend (file_list, file); } return g_list_reverse (file_list); } static gboolean get_attributes_for_default_sort_type (NemoFile *file, gboolean *is_recent, gboolean *is_download, gboolean *is_trash) { gboolean is_recent_dir, is_download_dir, is_desktop_dir, is_trash_dir, retval; *is_recent = FALSE; *is_download = FALSE; *is_trash = FALSE; retval = FALSE; /* special handling for certain directories */ if (file && nemo_file_is_directory (file)) { is_recent_dir = nemo_file_is_in_recent (file); is_download_dir = nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOWNLOAD); is_desktop_dir = nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP); is_trash_dir = nemo_file_is_in_trash (file); if (is_download_dir && !is_desktop_dir) { *is_download = TRUE; retval = TRUE; } else if (is_trash_dir) { *is_trash = TRUE; retval = TRUE; } else if (is_recent_dir) { *is_recent = TRUE; retval = TRUE; } } return retval; } NemoFileSortType nemo_file_get_default_sort_type (NemoFile *file, gboolean *reversed) { NemoFileSortType retval; gboolean is_recent, is_download, is_trash, res; retval = NEMO_FILE_SORT_NONE; is_recent = is_download = is_trash = FALSE; res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash); if (res) { if (is_recent) { retval = NEMO_FILE_SORT_BY_ATIME; } else if (is_download) { retval = NEMO_FILE_SORT_BY_MTIME; } else if (is_trash) { retval = NEMO_FILE_SORT_BY_TRASHED_TIME; } if (reversed != NULL) { *reversed = res; } } return retval; } const gchar * nemo_file_get_default_sort_attribute (NemoFile *file, gboolean *reversed) { const gchar *retval; gboolean is_recent, is_download, is_trash, res; retval = NULL; is_download = is_trash = FALSE; res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash); if (res) { if (is_recent || is_download) { retval = g_quark_to_string (attribute_date_modified_q); } else if (is_trash) { retval = g_quark_to_string (attribute_trashed_on_q); } if (reversed != NULL) { *reversed = res; } } return retval; } static int compare_by_display_name_cover (gconstpointer a, gconstpointer b) { return compare_by_display_name (NEMO_FILE (a), NEMO_FILE (b)); } /** * nemo_file_list_sort_by_display_name * * Sort the list of files by file name. * @list: GList of files. **/ GList * nemo_file_list_sort_by_display_name (GList *list) { return g_list_sort (list, compare_by_display_name_cover); } static GList *ready_data_list = NULL; typedef struct { GList *file_list; GList *remaining_files; NemoFileListCallback callback; gpointer callback_data; } FileListReadyData; static void file_list_ready_data_free (FileListReadyData *data) { GList *l; l = g_list_find (ready_data_list, data); if (l != NULL) { ready_data_list = g_list_delete_link (ready_data_list, l); nemo_file_list_free (data->file_list); g_list_free (data->remaining_files); g_free (data); } } static FileListReadyData * file_list_ready_data_new (GList *file_list, NemoFileListCallback callback, gpointer callback_data) { FileListReadyData *data; data = g_new0 (FileListReadyData, 1); data->file_list = nemo_file_list_copy (file_list); data->remaining_files = g_list_copy (file_list); data->callback = callback; data->callback_data = callback_data; ready_data_list = g_list_prepend (ready_data_list, data); return data; } static void file_list_file_ready_callback (NemoFile *file, gpointer user_data) { FileListReadyData *data; data = user_data; data->remaining_files = g_list_remove (data->remaining_files, file); if (data->remaining_files == NULL) { if (data->callback) { (*data->callback) (data->file_list, data->callback_data); } file_list_ready_data_free (data); } } void nemo_file_list_call_when_ready (GList *file_list, NemoFileAttributes attributes, NemoFileListHandle **handle, NemoFileListCallback callback, gpointer callback_data) { GList *l; FileListReadyData *data; NemoFile *file; g_return_if_fail (file_list != NULL); data = file_list_ready_data_new (file_list, callback, callback_data); if (handle) { *handle = (NemoFileListHandle *) data; } l = file_list; while (l != NULL) { file = NEMO_FILE (l->data); /* Need to do this here, as the list can be modified by this call */ l = l->next; nemo_file_call_when_ready (file, attributes, file_list_file_ready_callback, data); } } void nemo_file_list_cancel_call_when_ready (NemoFileListHandle *handle) { GList *l; NemoFile *file; FileListReadyData *data; g_return_if_fail (handle != NULL); data = (FileListReadyData *) handle; l = g_list_find (ready_data_list, data); if (l != NULL) { for (l = data->remaining_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready (file, file_list_file_ready_callback, data); } file_list_ready_data_free (data); } } static void thumbnail_limit_changed_callback (gpointer user_data) { g_settings_get (nemo_preferences, NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT, "t", &cached_thumbnail_limit); /* Tell the world that icons might have changed. We could invent a narrower-scope * signal to mean only "thumbnails might have changed" if this ends up being slow * for some reason. */ emit_change_signals_for_all_files_in_all_directories (); } static void thumbnail_size_changed_callback (gpointer user_data) { cached_thumbnail_size = g_settings_get_int (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE); scaled_cached_thumbnail_size = (double) cached_thumbnail_size / (double) NEMO_ICON_SIZE_STANDARD; /* Tell the world that icons might have changed. We could invent a narrower-scope * signal to mean only "thumbnails might have changed" if this ends up being slow * for some reason. */ emit_change_signals_for_all_files_in_all_directories (); } static void show_thumbnails_changed_callback (gpointer user_data) { show_image_thumbs = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS); /* Tell the world that icons might have changed. We could invent a narrower-scope * signal to mean only "thumbnails might have changed" if this ends up being slow * for some reason. */ emit_change_signals_for_all_files_in_all_directories (); } static void mime_type_data_changed_callback (GObject *signaller, gpointer user_data) { /* Tell the world that icons might have changed. We could invent a narrower-scope * signal to mean only "thumbnails might have changed" if this ends up being slow * for some reason. */ emit_change_signals_for_all_files_in_all_directories (); } static void icon_theme_changed_callback (GtkIconTheme *icon_theme, gpointer user_data) { /* Clear all pixmap caches as the icon => pixmap lookup changed */ nemo_icon_info_clear_caches (); /* Tell the world that icons might have changed. We could invent a narrower-scope * signal to mean only "thumbnails might have changed" if this ends up being slow * for some reason. */ emit_change_signals_for_all_files_in_all_directories (); } static void real_set_metadata (NemoFile *file, const char *key, const char *value) { /* Dummy default impl */ } static void real_set_metadata_as_list (NemoFile *file, const char *key, char **value) { /* Dummy default impl */ } static void nemo_file_class_init (NemoFileClass *class) { GtkIconTheme *icon_theme; nemo_file_info_getter = nemo_file_get_internal; attribute_name_q = g_quark_from_static_string ("name"); attribute_size_q = g_quark_from_static_string ("size"); attribute_type_q = g_quark_from_static_string ("type"); attribute_detailed_type_q = g_quark_from_static_string ("detailed_type"); attribute_modification_date_q = g_quark_from_static_string ("modification_date"); attribute_date_modified_q = g_quark_from_static_string ("date_modified"); attribute_date_modified_full_q = g_quark_from_static_string ("date_modified_full"); attribute_date_modified_with_time_q = g_quark_from_static_string ("date_modified_with_time"); attribute_accessed_date_q = g_quark_from_static_string ("accessed_date"); attribute_date_accessed_q = g_quark_from_static_string ("date_accessed"); attribute_date_accessed_full_q = g_quark_from_static_string ("date_accessed_full"); attribute_creation_date_q = g_quark_from_static_string ("creation_date"); attribute_date_created_q = g_quark_from_static_string ("date_created"); attribute_date_created_full_q = g_quark_from_static_string ("date_created_full"); attribute_date_created_with_time_q = g_quark_from_static_string ("date_created_with_time"); attribute_mime_type_q = g_quark_from_static_string ("mime_type"); attribute_size_detail_q = g_quark_from_static_string ("size_detail"); attribute_deep_size_q = g_quark_from_static_string ("deep_size"); attribute_deep_file_count_q = g_quark_from_static_string ("deep_file_count"); attribute_deep_directory_count_q = g_quark_from_static_string ("deep_directory_count"); attribute_deep_total_count_q = g_quark_from_static_string ("deep_total_count"); attribute_date_changed_q = g_quark_from_static_string ("date_changed"); attribute_date_changed_full_q = g_quark_from_static_string ("date_changed_full"); attribute_trashed_on_q = g_quark_from_static_string ("trashed_on"); attribute_trashed_on_full_q = g_quark_from_static_string ("trashed_on_full"); attribute_trash_orig_path_q = g_quark_from_static_string ("trash_orig_path"); attribute_date_permissions_q = g_quark_from_static_string ("date_permissions"); attribute_date_permissions_full_q = g_quark_from_static_string ("date_permissions_full"); attribute_permissions_q = g_quark_from_static_string ("permissions"); attribute_selinux_context_q = g_quark_from_static_string ("selinux_context"); attribute_octal_permissions_q = g_quark_from_static_string ("octal_permissions"); attribute_owner_q = g_quark_from_static_string ("owner"); attribute_group_q = g_quark_from_static_string ("group"); attribute_uri_q = g_quark_from_static_string ("uri"); attribute_where_q = g_quark_from_static_string ("where"); attribute_link_target_q = g_quark_from_static_string ("link_target"); attribute_volume_q = g_quark_from_static_string ("volume"); attribute_free_space_q = g_quark_from_static_string ("free_space"); G_OBJECT_CLASS (class)->finalize = finalize; G_OBJECT_CLASS (class)->constructor = nemo_file_constructor; class->set_metadata = real_set_metadata; class->set_metadata_as_list = real_set_metadata_as_list; class->get_metadata = NULL; class->get_metadata_as_list = NULL; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoFileClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[UPDATED_DEEP_COUNT_IN_PROGRESS] = g_signal_new ("updated_deep_count_in_progress", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoFileClass, updated_deep_count_in_progress), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (class, sizeof (NemoFileDetails)); thumbnail_limit_changed_callback (NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT, G_CALLBACK (thumbnail_limit_changed_callback), NULL); thumbnail_size_changed_callback (NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE, G_CALLBACK (thumbnail_size_changed_callback), NULL); show_thumbnails_changed_callback (NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, G_CALLBACK (show_thumbnails_changed_callback), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS, G_CALLBACK (show_thumbnails_changed_callback), NULL); icon_theme = gtk_icon_theme_get_default (); g_signal_connect_object (icon_theme, "changed", G_CALLBACK (icon_theme_changed_callback), NULL, 0); g_signal_connect (nemo_signaller_get_current (), "mime_data_changed", G_CALLBACK (mime_type_data_changed_callback), NULL); } static void nemo_file_add_emblem (NemoFile *file, const char *emblem_name) { if (file->details->pending_info_providers) { file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems, g_strdup (emblem_name)); } else { file->details->extension_emblems = g_list_prepend (file->details->extension_emblems, g_strdup (emblem_name)); } nemo_file_changed (file); } static void nemo_file_add_string_attribute (NemoFile *file, const char *attribute_name, const char *value) { if (file->details->pending_info_providers) { /* Lazily create hashtable */ if (!file->details->pending_extension_attributes) { file->details->pending_extension_attributes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_free); } g_hash_table_insert (file->details->pending_extension_attributes, GINT_TO_POINTER (g_quark_from_string (attribute_name)), g_strdup (value)); } else { if (!file->details->extension_attributes) { file->details->extension_attributes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_free); } g_hash_table_insert (file->details->extension_attributes, GINT_TO_POINTER (g_quark_from_string (attribute_name)), g_strdup (value)); } nemo_file_changed (file); } static void nemo_file_invalidate_extension_info (NemoFile *file) { nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_EXTENSION_INFO); } void nemo_file_info_providers_done (NemoFile *file) { g_list_free_full (file->details->extension_emblems, g_free); file->details->extension_emblems = file->details->pending_extension_emblems; file->details->pending_extension_emblems = NULL; if (file->details->extension_attributes) { g_hash_table_destroy (file->details->extension_attributes); } file->details->extension_attributes = file->details->pending_extension_attributes; file->details->pending_extension_attributes = NULL; nemo_file_changed (file); } static void nemo_file_info_iface_init (NemoFileInfoInterface *iface) { iface->is_gone = nemo_file_is_gone; iface->get_name = nemo_file_get_name; iface->get_file_type = nemo_file_get_file_type; iface->get_location = nemo_file_get_location; iface->get_uri = nemo_file_get_uri; iface->get_parent_location = nemo_file_get_parent_location; iface->get_parent_uri = nemo_file_get_parent_uri; iface->get_parent_info = nemo_file_get_parent; iface->get_mount = nemo_file_get_mount; iface->get_uri_scheme = nemo_file_get_uri_scheme; iface->get_activation_uri = nemo_file_get_activation_uri; iface->get_mime_type = nemo_file_get_mime_type; iface->is_mime_type = nemo_file_is_mime_type; iface->is_directory = nemo_file_is_directory; iface->can_write = nemo_file_can_write; iface->add_emblem = nemo_file_add_emblem; iface->get_string_attribute = nemo_file_get_string_attribute; iface->add_string_attribute = nemo_file_add_string_attribute; iface->invalidate_extension_info = nemo_file_invalidate_extension_info; } #if !defined (NEMO_OMIT_SELF_CHECK) void nemo_self_check_file (void) { NemoFile *file_1; NemoFile *file_2; GList *list; /* refcount checks */ EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0); file_1 = nemo_file_get_by_uri ("file:///home/"); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1->details->directory)->ref_count, 1); EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 1); nemo_file_unref (file_1); EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0); file_1 = nemo_file_get_by_uri ("file:///etc"); file_2 = nemo_file_get_by_uri ("file:///usr"); list = NULL; list = g_list_prepend (list, file_1); list = g_list_prepend (list, file_2); nemo_file_list_ref (list); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 2); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 2); nemo_file_list_unref (list); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1); nemo_file_list_free (list); EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0); /* name checks */ file_1 = nemo_file_get_by_uri ("file:///home/"); EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "home"); EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_by_uri ("file:///home/") == file_1, TRUE); nemo_file_unref (file_1); EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_by_uri ("file:///home") == file_1, TRUE); nemo_file_unref (file_1); nemo_file_unref (file_1); file_1 = nemo_file_get_by_uri ("file:///home"); EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "home"); nemo_file_unref (file_1); #if 0 /* ALEX: I removed this, because it was breaking distchecks. * It used to work, but when canonical uris changed from * foo: to foo:/// it broke. I don't expect it to matter * in real life */ file_1 = nemo_file_get_by_uri (":"); EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), ":"); nemo_file_unref (file_1); #endif file_1 = nemo_file_get_by_uri ("eazel:"); EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "eazel"); nemo_file_unref (file_1); /* sorting */ file_1 = nemo_file_get_by_uri ("file:///etc"); file_2 = nemo_file_get_by_uri ("file:///usr"); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1); EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) < 0, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) > 0, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) == 0, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, TRUE, FALSE) == 0, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) == 0, TRUE); EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, TRUE, TRUE) == 0, TRUE); nemo_file_unref (file_1); nemo_file_unref (file_2); } #endif /* !NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/libnemo-private/nemo-file.h000066400000000000000000001070421357442400300176060ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-file.h: Nemo file model. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_FILE_H #define NEMO_FILE_H #include #include #include #include /* NemoFile is an object used to represent a single element of a * NemoDirectory. It's lightweight and relies on NemoDirectory * to do most of the work. */ /* NemoFile is defined both here and in nemo-directory.h. */ #ifndef NEMO_FILE_DEFINED #define NEMO_FILE_DEFINED typedef struct NemoFile NemoFile; #endif #define NEMO_TYPE_FILE nemo_file_get_type() #define NEMO_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_FILE, NemoFile)) #define NEMO_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_FILE, NemoFileClass)) #define NEMO_IS_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_FILE)) #define NEMO_IS_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_FILE)) #define NEMO_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_FILE, NemoFileClass)) typedef enum { NEMO_FILE_SORT_NONE, NEMO_FILE_SORT_BY_DISPLAY_NAME, NEMO_FILE_SORT_BY_SIZE, NEMO_FILE_SORT_BY_TYPE, NEMO_FILE_SORT_BY_DETAILED_TYPE, NEMO_FILE_SORT_BY_MTIME, NEMO_FILE_SORT_BY_ATIME, NEMO_FILE_SORT_BY_TRASHED_TIME, NEMO_FILE_SORT_BY_BTIME } NemoFileSortType; typedef enum { NEMO_REQUEST_NOT_STARTED, NEMO_REQUEST_IN_PROGRESS, NEMO_REQUEST_DONE } NemoRequestStatus; typedef enum { NEMO_FILE_ICON_FLAGS_NONE = 0, NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS = (1<<0), NEMO_FILE_ICON_FLAGS_IGNORE_VISITING = (1<<1), NEMO_FILE_ICON_FLAGS_EMBEDDING_TEXT = (1<<2), NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT = (1<<3), NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER = (1<<4), /* whether the thumbnail size must match the display icon size */ NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE = (1<<5), /* uses the icon of the mount if present */ NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON = (1<<6), /* render the mount icon as an emblem over the regular one */ NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM = (1<<7), NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP = (1<<8) } NemoFileIconFlags; typedef enum { NEMO_DATE_TYPE_MODIFIED, NEMO_DATE_TYPE_CHANGED, NEMO_DATE_TYPE_ACCESSED, NEMO_DATE_TYPE_PERMISSIONS_CHANGED, NEMO_DATE_TYPE_TRASHED, NEMO_DATE_TYPE_CREATED } NemoDateType; typedef enum { NEMO_FILE_TOOLTIP_FLAGS_NONE = 0, NEMO_FILE_TOOLTIP_FLAGS_FILE_TYPE = (1<<0), NEMO_FILE_TOOLTIP_FLAGS_MOD_DATE = (1<<1), NEMO_FILE_TOOLTIP_FLAGS_ACCESS_DATE = (1<<2), NEMO_FILE_TOOLTIP_FLAGS_PATH = (1<<3), NEMO_FILE_TOOLTIP_FLAGS_CREATED_DATE = (1<<4) } NemoFileTooltipFlags; /* Emblems sometimes displayed for NemoFiles. Do not localize. */ #define NEMO_FILE_EMBLEM_NAME_SYMBOLIC_LINK "symbolic-link" #define NEMO_FILE_EMBLEM_NAME_CANT_READ "noread" #define NEMO_FILE_EMBLEM_NAME_CANT_WRITE "nowrite" #define NEMO_FILE_EMBLEM_NAME_TRASH "trash" #define NEMO_FILE_EMBLEM_NAME_NOTE "note" /* Used in list view and tree-sidebar to mark pinned files */ #define UNPINNED_TEXT_WEIGHT 400 #define PINNED_TEXT_WEIGHT 1000 typedef void (*NemoFileCallback) (NemoFile *file, gpointer callback_data); typedef void (*NemoFileListCallback) (GList *file_list, gpointer callback_data); typedef void (*NemoFileOperationCallback) (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data); typedef int (*NemoWidthMeasureCallback) (const char *string, void *context); typedef char * (*NemoTruncateCallback) (const char *string, int width, void *context); #define NEMO_FILE_ATTRIBUTES_FOR_ICON (NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO | NEMO_FILE_ATTRIBUTE_THUMBNAIL) typedef void NemoFileListHandle; /* GObject requirements. */ GType nemo_file_get_type (void); /* Getting at a single file. */ NemoFile * nemo_file_get (GFile *location); NemoFile * nemo_file_get_by_uri (const char *uri); /* Get a file only if the nemo version already exists */ NemoFile * nemo_file_get_existing (GFile *location); NemoFile * nemo_file_get_existing_by_uri (const char *uri); /* Covers for g_object_ref and g_object_unref that provide two conveniences: * 1) Using these is type safe. * 2) You are allowed to call these with NULL, */ NemoFile * nemo_file_ref (NemoFile *file); void nemo_file_unref (NemoFile *file); /* Monitor the file. */ void nemo_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes); void nemo_file_monitor_remove (NemoFile *file, gconstpointer client); /* Waiting for data that's read asynchronously. * This interface currently works only for metadata, but could be expanded * to other attributes as well. */ void nemo_file_call_when_ready (NemoFile *file, NemoFileAttributes attributes, NemoFileCallback callback, gpointer callback_data); void nemo_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data); gboolean nemo_file_check_if_ready (NemoFile *file, NemoFileAttributes attributes); void nemo_file_invalidate_attributes (NemoFile *file, NemoFileAttributes attributes); void nemo_file_invalidate_all_attributes (NemoFile *file); void nemo_file_increment_thumbnail_try_count (NemoFile *file); /* Basic attributes for file objects. */ gboolean nemo_file_contains_text (NemoFile *file); char * nemo_file_get_display_name (NemoFile *file); char * nemo_file_get_edit_name (NemoFile *file); char * nemo_file_get_name (NemoFile *file); const char * nemo_file_peek_name (NemoFile *file); GFile * nemo_file_get_location (NemoFile *file); char * nemo_file_get_description (NemoFile *file); char * nemo_file_get_uri (NemoFile *file); char * nemo_file_get_path (NemoFile *file); char * nemo_file_get_uri_scheme (NemoFile *file); NemoFile * nemo_file_get_parent (NemoFile *file); GFile * nemo_file_get_parent_location (NemoFile *file); char * nemo_file_get_parent_uri (NemoFile *file); char * nemo_file_get_parent_uri_for_display (NemoFile *file); gboolean nemo_file_can_get_size (NemoFile *file); goffset nemo_file_get_size (NemoFile *file); time_t nemo_file_get_mtime (NemoFile *file); time_t nemo_file_get_ctime (NemoFile *file); GFileType nemo_file_get_file_type (NemoFile *file); char * nemo_file_get_mime_type (NemoFile *file); gboolean nemo_file_is_mime_type (NemoFile *file, const char *mime_type); gboolean nemo_file_is_launchable (NemoFile *file); gboolean nemo_file_is_symbolic_link (NemoFile *file); gboolean nemo_file_is_mountpoint (NemoFile *file); GMount * nemo_file_get_mount (NemoFile *file); void nemo_file_set_mount (NemoFile *file, GMount *mount); char * nemo_file_get_volume_free_space (NemoFile *file); char * nemo_file_get_volume_name (NemoFile *file); char * nemo_file_get_symbolic_link_target_path (NemoFile *file); char * nemo_file_get_symbolic_link_target_uri (NemoFile *file); gboolean nemo_file_is_broken_symbolic_link (NemoFile *file); gboolean nemo_file_is_nemo_link (NemoFile *file); gboolean nemo_file_is_executable (NemoFile *file); gboolean nemo_file_is_directory (NemoFile *file); gboolean nemo_file_is_user_special_directory (NemoFile *file, GUserDirectory special_directory); gboolean nemo_file_is_archive (NemoFile *file); gboolean nemo_file_is_in_trash (NemoFile *file); gboolean nemo_file_is_in_recent (NemoFile *file); gboolean nemo_file_is_in_admin (NemoFile *file); gboolean nemo_file_is_in_desktop (NemoFile *file); gboolean nemo_file_is_home (NemoFile *file); gboolean nemo_file_is_desktop_directory (NemoFile *file); GError * nemo_file_get_file_info_error (NemoFile *file); gboolean nemo_file_get_directory_item_count (NemoFile *file, guint *count, gboolean *count_unreadable); void nemo_file_recompute_deep_counts (NemoFile *file); NemoRequestStatus nemo_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size, gboolean force); gboolean nemo_file_should_show_thumbnail (NemoFile *file); void nemo_file_delete_thumbnail (NemoFile *file); gboolean nemo_file_should_show_directory_item_count (NemoFile *file); gboolean nemo_file_should_show_type (NemoFile *file); GList * nemo_file_get_keywords (NemoFile *file); GList * nemo_file_get_emblem_icons (NemoFile *file, NemoFile *view_file); gboolean nemo_file_get_directory_item_mime_types (NemoFile *file, GList **mime_list); void nemo_file_set_attributes (NemoFile *file, GFileInfo *attributes, NemoFileOperationCallback callback, gpointer callback_data); GFilesystemPreviewType nemo_file_get_filesystem_use_preview (NemoFile *file); char * nemo_file_get_filesystem_id (NemoFile *file); NemoFile * nemo_file_get_trash_original_file (NemoFile *file); /* Permissions. */ gboolean nemo_file_can_get_permissions (NemoFile *file); gboolean nemo_file_can_set_permissions (NemoFile *file); guint nemo_file_get_permissions (NemoFile *file); gboolean nemo_file_can_get_owner (NemoFile *file); gboolean nemo_file_can_set_owner (NemoFile *file); gboolean nemo_file_can_get_group (NemoFile *file); gboolean nemo_file_can_set_group (NemoFile *file); char * nemo_file_get_owner_name (NemoFile *file); char * nemo_file_get_group_name (NemoFile *file); GList * nemo_get_user_names (void); GList * nemo_get_all_group_names (void); GList * nemo_file_get_settable_group_names (NemoFile *file); gboolean nemo_file_can_get_selinux_context (NemoFile *file); char * nemo_file_get_selinux_context (NemoFile *file); /* "Capabilities". */ gboolean nemo_file_can_read (NemoFile *file); gboolean nemo_file_can_write (NemoFile *file); gboolean nemo_file_can_execute (NemoFile *file); gboolean nemo_file_can_rename (NemoFile *file); gboolean nemo_file_can_delete (NemoFile *file); gboolean nemo_file_can_trash (NemoFile *file); gboolean nemo_file_can_mount (NemoFile *file); gboolean nemo_file_can_unmount (NemoFile *file); gboolean nemo_file_can_eject (NemoFile *file); gboolean nemo_file_can_start (NemoFile *file); gboolean nemo_file_can_start_degraded (NemoFile *file); gboolean nemo_file_can_stop (NemoFile *file); GDriveStartStopType nemo_file_get_start_stop_type (NemoFile *file); gboolean nemo_file_can_poll_for_media (NemoFile *file); gboolean nemo_file_is_media_check_automatic (NemoFile *file); void nemo_file_mount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_unmount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_eject (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_start (NemoFile *file, GMountOperation *start_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_stop (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_poll_for_media (NemoFile *file); /* Basic operations for file objects. */ void nemo_file_set_owner (NemoFile *file, const char *user_name_or_id, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_set_group (NemoFile *file, const char *group_name_or_id, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_set_permissions (NemoFile *file, guint32 permissions, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_rename (NemoFile *file, const char *new_name, NemoFileOperationCallback callback, gpointer callback_data); void nemo_file_cancel (NemoFile *file, NemoFileOperationCallback callback, gpointer callback_data); /* Return true if this file has already been deleted. * This object will be unref'd after sending the files_removed signal, * but it could hang around longer if someone ref'd it. */ gboolean nemo_file_is_gone (NemoFile *file); /* Return true if this file is not confirmed to have ever really * existed. This is true when the NemoFile object has been created, but no I/O * has yet confirmed the existence of a file by that name. */ gboolean nemo_file_is_not_yet_confirmed (NemoFile *file); /* Simple getting and setting top-level metadata. */ char * nemo_file_get_metadata (NemoFile *file, const char *key, const char *default_metadata); GList * nemo_file_get_metadata_list (NemoFile *file, const char *key); void nemo_file_set_metadata (NemoFile *file, const char *key, const char *default_metadata, const char *metadata); void nemo_file_set_metadata_list (NemoFile *file, const char *key, GList *list); void nemo_file_set_desktop_grid_adjusts (NemoFile *file, const char *key, int int_a, int int_b); void nemo_file_get_desktop_grid_adjusts (NemoFile *file, const char *key, int *int_a, int *int_b); /* Covers for common data types. */ gboolean nemo_file_get_boolean_metadata (NemoFile *file, const char *key, gboolean default_metadata); void nemo_file_set_boolean_metadata (NemoFile *file, const char *key, gboolean default_metadata, gboolean metadata); int nemo_file_get_integer_metadata (NemoFile *file, const char *key, int default_metadata); void nemo_file_set_integer_metadata (NemoFile *file, const char *key, int default_metadata, int metadata); #define UNDEFINED_TIME ((time_t) (-1)) time_t nemo_file_get_time_metadata (NemoFile *file, const char *key); void nemo_file_set_time_metadata (NemoFile *file, const char *key, time_t time); /* Attributes for file objects as user-displayable strings. */ char * nemo_file_get_string_attribute (NemoFile *file, const char *attribute_name); char * nemo_file_get_string_attribute_q (NemoFile *file, GQuark attribute_q); char * nemo_file_get_string_attribute_with_default (NemoFile *file, const char *attribute_name); char * nemo_file_get_string_attribute_with_default_q (NemoFile *file, GQuark attribute_q); /* Matching with another URI. */ gboolean nemo_file_matches_uri (NemoFile *file, const char *uri); /* Is the file local? */ gboolean nemo_file_is_local (NemoFile *file); /* Comparing two file objects for sorting */ NemoFileSortType nemo_file_get_default_sort_type (NemoFile *file, gboolean *reversed); const gchar * nemo_file_get_default_sort_attribute (NemoFile *file, gboolean *reversed); int nemo_file_compare_for_sort (NemoFile *file_1, NemoFile *file_2, NemoFileSortType sort_type, gboolean directories_first, gboolean reversed); int nemo_file_compare_for_sort_by_attribute (NemoFile *file_1, NemoFile *file_2, const char *attribute, gboolean directories_first, gboolean reversed); int nemo_file_compare_for_sort_by_attribute_q (NemoFile *file_1, NemoFile *file_2, GQuark attribute, gboolean directories_first, gboolean reversed); gboolean nemo_file_is_date_sort_attribute_q (GQuark attribute); int nemo_file_compare_display_name (NemoFile *file_1, const char *pattern); int nemo_file_compare_location (NemoFile *file_1, NemoFile *file_2); /* filtering functions for use by various directory views */ gboolean nemo_file_is_hidden_file (NemoFile *file); gboolean nemo_file_should_show (NemoFile *file, gboolean show_hidden, gboolean show_foreign); GList *nemo_file_list_filter_hidden (GList *files, gboolean show_hidden); /* Get the URI that's used when activating the file. * Getting this can require reading the contents of the file. */ gboolean nemo_file_is_launcher (NemoFile *file); gboolean nemo_file_is_foreign_link (NemoFile *file); gboolean nemo_file_is_trusted_link (NemoFile *file); gboolean nemo_file_has_activation_uri (NemoFile *file); char * nemo_file_get_activation_uri (NemoFile *file); GFile * nemo_file_get_activation_location (NemoFile *file); char * nemo_file_get_drop_target_uri (NemoFile *file); GIcon * nemo_file_get_gicon (NemoFile *file, NemoFileIconFlags flags); gchar * nemo_file_get_control_icon_name (NemoFile *file); NemoIconInfo * nemo_file_get_icon (NemoFile *file, int size, int max_width, int scale, NemoFileIconFlags flags); GdkPixbuf * nemo_file_get_icon_pixbuf (NemoFile *file, int size, gboolean force_size, int scale, NemoFileIconFlags flags); gboolean nemo_file_has_open_window (NemoFile *file); void nemo_file_set_has_open_window (NemoFile *file, gboolean has_open_window); /* Thumbnailing handling */ gboolean nemo_file_is_thumbnailing (NemoFile *file); /* Convenience functions for dealing with a list of NemoFile objects that each have a ref. * These are just convenient names for functions that work on lists of GtkObject *. */ GList * nemo_file_list_ref (GList *file_list); void nemo_file_list_unref (GList *file_list); void nemo_file_list_free (GList *file_list); GList * nemo_file_list_copy (GList *file_list); GList * nemo_file_list_from_uris (GList *uri_list); GList * nemo_file_list_sort_by_display_name (GList *file_list); void nemo_file_list_call_when_ready (GList *file_list, NemoFileAttributes attributes, NemoFileListHandle **handle, NemoFileListCallback callback, gpointer callback_data); void nemo_file_list_cancel_call_when_ready (NemoFileListHandle *handle); char * nemo_file_get_owner_as_string (NemoFile *file, gboolean include_real_name); char * nemo_file_get_type_as_string (NemoFile *file); char * nemo_file_get_detailed_type_as_string (NemoFile *file); gchar * nemo_file_construct_tooltip (NemoFile *file, NemoFileTooltipFlags flags); gboolean nemo_file_has_thumbnail_access_problem (NemoFile *file); gint nemo_file_get_monitor_number (NemoFile *file); void nemo_file_set_monitor_number (NemoFile *file, gint monitor); void nemo_file_get_position (NemoFile *file, GdkPoint *point); void nemo_file_set_position (NemoFile *file, gint x, gint y); gboolean nemo_file_get_is_desktop_orphan (NemoFile *file); void nemo_file_set_is_desktop_orphan (NemoFile *file, gboolean is_desktop_orphan); gboolean nemo_file_get_pinning (NemoFile *file); void nemo_file_set_pinning (NemoFile *file, gboolean pin); /* Debugging */ void nemo_file_dump (NemoFile *file); typedef struct NemoFileDetails NemoFileDetails; struct NemoFile { GObject parent_slot; NemoFileDetails *details; }; typedef struct { GObjectClass parent_slot; /* Subclasses can set this to something other than G_FILE_TYPE_UNKNOWN and it will be used as the default file type. This is useful when creating a "virtual" NemoFile subclass that you can't actually get real information about. For exaple NemoDesktopDirectoryFile. */ GFileType default_file_type; /* Called when the file notices any change. */ void (* changed) (NemoFile *file); /* Called periodically while directory deep count is being computed. */ void (* updated_deep_count_in_progress) (NemoFile *file); /* Virtual functions (mainly used for trash directory). */ void (* monitor_add) (NemoFile *file, gconstpointer client, NemoFileAttributes attributes); void (* monitor_remove) (NemoFile *file, gconstpointer client); void (* call_when_ready) (NemoFile *file, NemoFileAttributes attributes, NemoFileCallback callback, gpointer callback_data); void (* cancel_call_when_ready) (NemoFile *file, NemoFileCallback callback, gpointer callback_data); gboolean (* check_if_ready) (NemoFile *file, NemoFileAttributes attributes); gboolean (* get_item_count) (NemoFile *file, guint *count, gboolean *count_unreadable); NemoRequestStatus (* get_deep_counts) (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size); gboolean (* get_date) (NemoFile *file, NemoDateType type, time_t *date); char * (* get_where_string) (NemoFile *file); void (* set_metadata) (NemoFile *file, const char *key, const char *value); void (* set_metadata_as_list) (NemoFile *file, const char *key, char **value); gchar * (* get_metadata) (NemoFile *file, const char *key); gchar ** (* get_metadata_as_list) (NemoFile *file, const char *key); void (* mount) (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void (* unmount) (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void (* eject) (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void (* start) (NemoFile *file, GMountOperation *start_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void (* stop) (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data); void (* poll_for_media) (NemoFile *file); } NemoFileClass; #endif /* NEMO_FILE_H */ nemo-4.4.2/libnemo-private/nemo-global-preferences.c000066400000000000000000000250351357442400300224220ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-global-preferences.c - Nemo specific preference keys and functions. Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ramiro Estrugo */ #include #include "nemo-global-preferences.h" #include "nemo-file-utilities.h" #include "nemo-file.h" #include #include #include #include #include #include #include static gboolean ignore_view_metadata = FALSE; static gboolean inherit_folder_view_preference = FALSE; static gboolean inherit_show_thumbnails_preference = FALSE; static int size_prefixes_preference = 0; static gchar **file_roller_mimetypes = NULL; GFileMonitor *tz_mon; /* * Public functions */ char * nemo_global_preferences_get_default_folder_viewer_preference_as_iid (void) { int preference_value; const char *viewer_iid; preference_value = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_DEFAULT_FOLDER_VIEWER); if (preference_value == NEMO_DEFAULT_FOLDER_VIEWER_LIST_VIEW) { viewer_iid = NEMO_LIST_VIEW_IID; } else if (preference_value == NEMO_DEFAULT_FOLDER_VIEWER_COMPACT_VIEW) { viewer_iid = NEMO_COMPACT_VIEW_IID; } else { viewer_iid = NEMO_ICON_VIEW_IID; } return g_strdup (viewer_iid); } gboolean nemo_global_preferences_get_inherit_folder_viewer_preference (void) { return inherit_folder_view_preference; } gboolean nemo_global_preferences_get_ignore_view_metadata (void) { return ignore_view_metadata; } gboolean nemo_global_preferences_get_inherit_show_thumbnails_preference (void) { return inherit_show_thumbnails_preference; } int nemo_global_preferences_get_size_prefix_preference (void) { return size_prefixes_preference; } char * nemo_global_preferences_get_desktop_iid (void) { gboolean use_grid; const char *viewer_iid; use_grid = g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_USE_DESKTOP_GRID); if (use_grid) { viewer_iid = NEMO_DESKTOP_ICON_GRID_VIEW_IID; } else { viewer_iid = NEMO_DESKTOP_ICON_VIEW_IID; } return g_strdup (viewer_iid); } gint nemo_global_preferences_get_tooltip_flags (void) { NemoFileTooltipFlags flags = NEMO_FILE_TOOLTIP_FLAGS_NONE; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIP_FILE_TYPE)) flags |= NEMO_FILE_TOOLTIP_FLAGS_FILE_TYPE; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIP_MOD_DATE)) flags |= NEMO_FILE_TOOLTIP_FLAGS_MOD_DATE; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIP_ACCESS_DATE)) flags |= NEMO_FILE_TOOLTIP_FLAGS_ACCESS_DATE; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIP_FULL_PATH)) flags |= NEMO_FILE_TOOLTIP_FLAGS_PATH; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIP_CREATED_DATE)) flags |= NEMO_FILE_TOOLTIP_FLAGS_CREATED_DATE; return flags; } gboolean nemo_global_preferences_should_load_plugin (const gchar *name, const gchar *key) { gchar **disabled_list = g_settings_get_strv (nemo_plugin_preferences, key); gboolean ret = TRUE; guint i = 0; for (i = 0; i < g_strv_length (disabled_list); i++) { if (g_strcmp0 (disabled_list[i], name) == 0) ret = FALSE; } g_strfreev (disabled_list); return ret; } static void boolean_changed_cb (GSettings *settings, gchar *key, gboolean *user_data) { *user_data = g_settings_get_boolean (settings, key); } static void enum_changed_cb (GSettings *settings, gchar *key, int *user_data) { *user_data = g_settings_get_enum (settings, key); } static void setup_cached_pref_keys (void) { g_signal_connect (nemo_preferences, "changed::" NEMO_PREFERENCES_IGNORE_VIEW_METADATA, G_CALLBACK (boolean_changed_cb), &ignore_view_metadata); boolean_changed_cb (nemo_preferences, NEMO_PREFERENCES_IGNORE_VIEW_METADATA, &ignore_view_metadata); g_signal_connect (nemo_preferences, "changed::" NEMO_PREFERENCES_INHERIT_FOLDER_VIEWER, G_CALLBACK (boolean_changed_cb), &inherit_folder_view_preference); boolean_changed_cb (nemo_preferences, NEMO_PREFERENCES_INHERIT_FOLDER_VIEWER, &inherit_folder_view_preference); g_signal_connect (nemo_preferences, "changed::" NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS, G_CALLBACK (boolean_changed_cb), &inherit_show_thumbnails_preference); boolean_changed_cb (nemo_preferences, NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS, &inherit_show_thumbnails_preference); g_signal_connect (nemo_preferences, "changed::" NEMO_PREFERENCES_SIZE_PREFIXES, G_CALLBACK (enum_changed_cb), &size_prefixes_preference); enum_changed_cb (nemo_preferences, NEMO_PREFERENCES_SIZE_PREFIXES, &size_prefixes_preference); } gchar ** nemo_global_preferences_get_fileroller_mimetypes (void) { static gsize once_init = 0; if (g_once_init_enter (&once_init)) { if (nemo_is_file_roller_installed ()) { GAppInfo *app_info; gchar ***results; gchar **result; gint i; results = g_desktop_app_info_search ("file-roller"); if (results != NULL && results[0] != NULL) { const gchar *best; best = results[0][0]; app_info = G_APP_INFO (g_desktop_app_info_new (best)); if (app_info) { file_roller_mimetypes = g_strdupv ((gchar **) g_app_info_get_supported_types (app_info)); g_object_unref (app_info); } if (app_info == NULL) { g_warning ("Unable to retrieve list of file-roller mimetypes"); } i = 0; result = results[i]; while (result != NULL) { g_strfreev (result); result = results[++i]; } g_free (results); } } g_once_init_leave (&once_init, 1); } return file_roller_mimetypes; } static void on_time_data_changed (gpointer user_data) { prefs_current_date_format = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_DATE_FORMAT); prefs_current_24h_time_format = g_settings_get_boolean (cinnamon_interface_preferences, "clock-use-24h"); if (prefs_current_timezone != NULL) { g_time_zone_unref (prefs_current_timezone); } prefs_current_timezone = g_time_zone_new_local (); } static void setup_cached_time_data (void) { GFile *tz; prefs_current_timezone = NULL; g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DATE_FORMAT, G_CALLBACK (on_time_data_changed), NULL); g_signal_connect_swapped (cinnamon_interface_preferences, "changed::clock-use-24h", G_CALLBACK (on_time_data_changed), NULL); tz = g_file_new_for_path ("/etc/localtime"); tz_mon = g_file_monitor_file (tz, 0, NULL, NULL); g_object_unref (tz); g_signal_connect_swapped (tz_mon, "changed", G_CALLBACK (on_time_data_changed), NULL); on_time_data_changed (NULL); } void nemo_global_preferences_init (void) { static gboolean initialized = FALSE; if (initialized) { return; } initialized = TRUE; nemo_preferences = g_settings_new("org.nemo.preferences"); nemo_window_state = g_settings_new("org.nemo.window-state"); nemo_icon_view_preferences = g_settings_new("org.nemo.icon-view"); nemo_list_view_preferences = g_settings_new("org.nemo.list-view"); nemo_compact_view_preferences = g_settings_new("org.nemo.compact-view"); nemo_desktop_preferences = g_settings_new("org.nemo.desktop"); nemo_tree_sidebar_preferences = g_settings_new("org.nemo.sidebar-panels.tree"); nemo_plugin_preferences = g_settings_new("org.nemo.plugins"); nemo_menu_config_preferences = g_settings_new("org.nemo.preferences.menu-config"); gnome_lockdown_preferences = g_settings_new("org.cinnamon.desktop.lockdown"); gnome_background_preferences = g_settings_new("org.cinnamon.desktop.background"); gnome_media_handling_preferences = g_settings_new("org.cinnamon.desktop.media-handling"); gnome_terminal_preferences = g_settings_new("org.cinnamon.desktop.default-applications.terminal"); cinnamon_privacy_preferences = g_settings_new("org.cinnamon.desktop.privacy"); cinnamon_interface_preferences = g_settings_new ("org.cinnamon.desktop.interface"); setup_cached_pref_keys (); setup_cached_time_data (); eel_debug_call_at_shutdown (nemo_global_preferences_finalize); } void nemo_global_preferences_finalize (void) { g_strfreev (file_roller_mimetypes); g_object_unref (tz_mon); g_object_unref (nemo_preferences); g_object_unref (nemo_window_state); g_object_unref (nemo_icon_view_preferences); g_object_unref (nemo_list_view_preferences); g_object_unref (nemo_compact_view_preferences); g_object_unref (nemo_desktop_preferences); g_object_unref (nemo_tree_sidebar_preferences); g_object_unref (nemo_plugin_preferences); g_object_unref (nemo_menu_config_preferences); g_object_unref (gnome_lockdown_preferences); g_object_unref (gnome_background_preferences); g_object_unref (gnome_media_handling_preferences); g_object_unref (gnome_terminal_preferences); g_object_unref (cinnamon_privacy_preferences); g_object_unref (cinnamon_interface_preferences); } nemo-4.4.2/libnemo-private/nemo-global-preferences.h000066400000000000000000000315721357442400300224320ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-global-preferences.h - Nemo specific preference keys and functions. Copyright (C) 1999, 2000, 2001 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ramiro Estrugo */ #ifndef NEMO_GLOBAL_PREFERENCES_H #define NEMO_GLOBAL_PREFERENCES_H #include G_BEGIN_DECLS /* Trash options */ #define NEMO_PREFERENCES_CONFIRM_MOVE_TO_TRASH "confirm-move-to-trash" #define NEMO_PREFERENCES_CONFIRM_TRASH "confirm-trash" #define NEMO_PREFERENCES_ENABLE_DELETE "enable-delete" #define NEMO_PREFERENCES_SWAP_TRASH_DELETE "swap-trash-delete" /* Desktop options */ #define NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR "desktop-is-home-dir" /* Display */ #define NEMO_PREFERENCES_SHOW_HIDDEN_FILES "show-hidden-files" #define NEMO_PREFERENCES_SHOW_ADVANCED_PERMISSIONS "show-advanced-permissions" #define NEMO_PREFERENCES_DATE_FORMAT "date-format" /* Mouse */ #define NEMO_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS "mouse-use-extra-buttons" #define NEMO_PREFERENCES_MOUSE_FORWARD_BUTTON "mouse-forward-button" #define NEMO_PREFERENCES_MOUSE_BACK_BUTTON "mouse-back-button" typedef enum { NEMO_DATE_FORMAT_LOCALE, NEMO_DATE_FORMAT_ISO, NEMO_DATE_FORMAT_INFORMAL } NemoDateFormat; typedef enum { NEMO_NEW_TAB_POSITION_AFTER_CURRENT_TAB, NEMO_NEW_TAB_POSITION_END, } NemoNewTabPosition; /* Sidebar panels */ #define NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES "show-only-directories" /* Single/Double click preference */ #define NEMO_PREFERENCES_CLICK_POLICY "click-policy" /* Quick renames with two single clicks and pause in-between*/ #define NEMO_PREFERENCES_CLICK_TO_RENAME "quick-renames-with-pause-in-between" /* Activating executable text files */ #define NEMO_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION "executable-text-activation" /* Spatial or browser mode */ #define NEMO_PREFERENCES_ALWAYS_USE_BROWSER "always-use-browser" #define NEMO_PREFERENCES_NEW_TAB_POSITION "tabs-open-position" #define NEMO_PREFERENCES_SHOW_LOCATION_ENTRY "show-location-entry" #define NEMO_PREFERENCES_SHOW_PREVIOUS_ICON_TOOLBAR "show-previous-icon-toolbar" #define NEMO_PREFERENCES_SHOW_NEXT_ICON_TOOLBAR "show-next-icon-toolbar" #define NEMO_PREFERENCES_SHOW_UP_ICON_TOOLBAR "show-up-icon-toolbar" #define NEMO_PREFERENCES_SHOW_EDIT_ICON_TOOLBAR "show-edit-icon-toolbar" #define NEMO_PREFERENCES_SHOW_RELOAD_ICON_TOOLBAR "show-reload-icon-toolbar" #define NEMO_PREFERENCES_SHOW_HOME_ICON_TOOLBAR "show-home-icon-toolbar" #define NEMO_PREFERENCES_SHOW_COMPUTER_ICON_TOOLBAR "show-computer-icon-toolbar" #define NEMO_PREFERENCES_SHOW_SEARCH_ICON_TOOLBAR "show-search-icon-toolbar" #define NEMO_PREFERENCES_SHOW_NEW_FOLDER_ICON_TOOLBAR "show-new-folder-icon-toolbar" #define NEMO_PREFERENCES_SHOW_OPEN_IN_TERMINAL_TOOLBAR "show-open-in-terminal-toolbar" #define NEMO_PREFERENCES_SHOW_ICON_VIEW_ICON_TOOLBAR "show-icon-view-icon-toolbar" #define NEMO_PREFERENCES_SHOW_LIST_VIEW_ICON_TOOLBAR "show-list-view-icon-toolbar" #define NEMO_PREFERENCES_SHOW_COMPACT_VIEW_ICON_TOOLBAR "show-compact-view-icon-toolbar" #define NEMO_PREFERENCES_SHOW_ROOT_WARNING "show-root-warning" #define NEMO_PREFERENCES_SHOW_SHOW_THUMBNAILS_TOOLBAR "show-show-thumbnails-toolbar" /* Which views should be displayed for new windows */ #define NEMO_WINDOW_STATE_START_WITH_STATUS_BAR "start-with-status-bar" #define NEMO_WINDOW_STATE_START_WITH_SIDEBAR "start-with-sidebar" #define NEMO_WINDOW_STATE_START_WITH_TOOLBAR "start-with-toolbar" #define NEMO_WINDOW_STATE_START_WITH_MENU_BAR "start-with-menu-bar" #define NEMO_WINDOW_STATE_SIDE_PANE_VIEW "side-pane-view" #define NEMO_WINDOW_STATE_GEOMETRY "geometry" #define NEMO_WINDOW_STATE_MAXIMIZED "maximized" #define NEMO_WINDOW_STATE_SIDEBAR_WIDTH "sidebar-width" #define NEMO_WINDOW_STATE_MY_COMPUTER_EXPANDED "my-computer-expanded" #define NEMO_WINDOW_STATE_BOOKMARKS_EXPANDED "bookmarks-expanded" #define NEMO_WINDOW_STATE_DEVICES_EXPANDED "devices-expanded" #define NEMO_WINDOW_STATE_NETWORK_EXPANDED "network-expanded" /* Sorting order */ #define NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST "sort-directories-first" #define NEMO_PREFERENCES_DEFAULT_SORT_ORDER "default-sort-order" #define NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER "default-sort-in-reverse-order" /* The default folder viewer - one of the two enums below */ #define NEMO_PREFERENCES_DEFAULT_FOLDER_VIEWER "default-folder-viewer" #define NEMO_PREFERENCES_INHERIT_FOLDER_VIEWER "inherit-folder-viewer" #define NEMO_PREFERENCES_SHOW_FULL_PATH_TITLES "show-full-path-titles" #define NEMO_PREFERENCES_CLOSE_DEVICE_VIEW_ON_EJECT "close-device-view-on-device-eject" #define NEMO_PREFERENCES_START_WITH_DUAL_PANE "start-with-dual-pane" #define NEMO_PREFERENCES_IGNORE_VIEW_METADATA "ignore-view-metadata" #define NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS "show-bookmarks-in-to-menus" #define NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS "show-places-in-to-menus" #define NEMO_PREFERENCES_RECENT_ENABLED "remember-recent-files" #define NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT "sidebar-bookmark-breakpoint" enum { NEMO_DEFAULT_FOLDER_VIEWER_ICON_VIEW, NEMO_DEFAULT_FOLDER_VIEWER_COMPACT_VIEW, NEMO_DEFAULT_FOLDER_VIEWER_LIST_VIEW, NEMO_DEFAULT_FOLDER_VIEWER_OTHER }; /* These IIDs are used by the preferences code and in nemo-application.c */ #define NEMO_ICON_VIEW_IID "OAFIID:Nemo_File_Manager_Icon_View" #define NEMO_COMPACT_VIEW_IID "OAFIID:Nemo_File_Manager_Compact_View" #define NEMO_LIST_VIEW_IID "OAFIID:Nemo_File_Manager_List_View" #define NEMO_DESKTOP_ICON_VIEW_IID "OAFIID:Nemo_File_Manager_Desktop_Icon_View" #define NEMO_DESKTOP_ICON_GRID_VIEW_IID "OAFIID:Nemo_File_Manager_Desktop_Icon_Grid_View" /* Icon View */ #define NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL "default-zoom-level" #define NEMO_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS "labels-beside-icons" /* Which text attributes appear beneath icon names */ #define NEMO_PREFERENCES_ICON_VIEW_CAPTIONS "captions" /* The default size for thumbnail icons */ #define NEMO_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE "thumbnail-size" /* ellipsization preferences */ #define NEMO_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT "text-ellipsis-limit" #define NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT "text-ellipsis-limit" /* Compact View */ #define NEMO_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL "default-zoom-level" #define NEMO_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH "all-columns-have-same-width" /* List View */ #define NEMO_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL "default-zoom-level" #define NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS "default-visible-columns" #define NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER "default-column-order" #define NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS "search-visible-columns" enum { NEMO_CLICK_POLICY_SINGLE, NEMO_CLICK_POLICY_DOUBLE }; enum { NEMO_EXECUTABLE_TEXT_LAUNCH, NEMO_EXECUTABLE_TEXT_DISPLAY, NEMO_EXECUTABLE_TEXT_ASK }; typedef enum { NEMO_SPEED_TRADEOFF_ALWAYS, NEMO_SPEED_TRADEOFF_LOCAL_ONLY, NEMO_SPEED_TRADEOFF_NEVER } NemoSpeedTradeoffValue; #define NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS "show-directory-item-counts" #define NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS "show-image-thumbnails" #define NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT "thumbnail-limit" #define NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS "inherit-show-thumbnails" typedef enum { NEMO_COMPLEX_SEARCH_BAR, NEMO_SIMPLE_SEARCH_BAR } NemoSearchBarMode; #define NEMO_PREFERENCES_DESKTOP_FONT "font" #define NEMO_PREFERENCES_DESKTOP_HOME_VISIBLE "home-icon-visible" #define NEMO_PREFERENCES_DESKTOP_COMPUTER_VISIBLE "computer-icon-visible" #define NEMO_PREFERENCES_DESKTOP_TRASH_VISIBLE "trash-icon-visible" #define NEMO_PREFERENCES_DESKTOP_VOLUMES_VISIBLE "volumes-visible" #define NEMO_PREFERENCES_DESKTOP_NETWORK_VISIBLE "network-icon-visible" #define NEMO_PREFERENCES_DESKTOP_BACKGROUND_FADE "background-fade" #define NEMO_PREFERENCES_DESKTOP_IGNORED_DESKTOP_HANDLERS "ignored-desktop-handlers" /* bulk rename utility */ #define NEMO_PREFERENCES_BULK_RENAME_TOOL "bulk-rename-tool" /* Lockdown */ #define NEMO_PREFERENCES_LOCKDOWN_COMMAND_LINE "disable-command-line" /* Desktop background */ #define NEMO_PREFERENCES_DESKTOP_LAYOUT "desktop-layout" #define NEMO_PREFERENCES_SHOW_ORPHANED_DESKTOP_ICONS "show-orphaned-desktop-icons" #define NEMO_PREFERENCES_SHOW_DESKTOP "show-desktop-icons" /* DEPRECATED */ #define NEMO_PREFERENCES_USE_DESKTOP_GRID "use-desktop-grid" #define NEMO_PREFERENCES_DESKTOP_HORIZONTAL_GRID_ADJUST "horizontal-grid-adjust" #define NEMO_PREFERENCES_DESKTOP_VERTICAL_GRID_ADJUST "vertical-grid-adjust" /* File size unit prefix */ #define NEMO_PREFERENCES_SIZE_PREFIXES "size-prefixes" /* media handling */ #define GNOME_DESKTOP_MEDIA_HANDLING_AUTOMOUNT "automount" #define GNOME_DESKTOP_MEDIA_HANDLING_AUTOMOUNT_OPEN "automount-open" #define GNOME_DESKTOP_MEDIA_HANDLING_AUTORUN "autorun-never" /* Terminal */ #define GNOME_DESKTOP_TERMINAL_EXEC "exec" /* Tooltips */ #define NEMO_PREFERENCES_TOOLTIPS_DESKTOP "tooltips-on-desktop" #define NEMO_PREFERENCES_TOOLTIPS_ICON_VIEW "tooltips-in-icon-view" #define NEMO_PREFERENCES_TOOLTIPS_LIST_VIEW "tooltips-in-list-view" #define NEMO_PREFERENCES_TOOLTIP_FILE_TYPE "tooltips-show-file-type" #define NEMO_PREFERENCES_TOOLTIP_MOD_DATE "tooltips-show-mod-date" #define NEMO_PREFERENCES_TOOLTIP_ACCESS_DATE "tooltips-show-access-date" #define NEMO_PREFERENCES_TOOLTIP_CREATED_DATE "tooltips-show-birth-date" #define NEMO_PREFERENCES_TOOLTIP_FULL_PATH "tooltips-show-path" #define NEMO_PREFERENCES_DISABLE_MENU_WARNING "disable-menu-warning" /* Plugins */ #define NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS "disabled-extensions" #define NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS "disabled-actions" #define NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS "disabled-scripts" /* Connect-to server dialog last-used method */ #define NEMO_PREFERENCES_LAST_SERVER_CONNECT_METHOD "last-server-connect-method" /* File operations queue */ #define NEMO_PREFERENCES_NEVER_QUEUE_FILE_OPS "never-queue-file-ops" #define NEMO_PREFERENCES_CLICK_DOUBLE_PARENT_FOLDER "click-double-parent-folder" #define NEMO_PREFERENCES_SAVED_SEARCHES "saved-searches" #define NEMO_PREFERENCES_SHOW_MIME_MAKE_EXECUTABLE "enable-mime-actions-make-executable" void nemo_global_preferences_init (void); void nemo_global_preferences_finalize (void); char *nemo_global_preferences_get_default_folder_viewer_preference_as_iid (void); gboolean nemo_global_preferences_get_inherit_folder_viewer_preference (void); gboolean nemo_global_preferences_get_inherit_show_thumbnails_preference (void); gboolean nemo_global_preferences_get_ignore_view_metadata (void); int nemo_global_preferences_get_size_prefix_preference (void); char *nemo_global_preferences_get_desktop_iid (void); gint nemo_global_preferences_get_tooltip_flags (void); gboolean nemo_global_preferences_should_load_plugin (const gchar *name, const gchar *key); gchar **nemo_global_preferences_get_fileroller_mimetypes (void); GSettings *nemo_preferences; GSettings *nemo_icon_view_preferences; GSettings *nemo_list_view_preferences; GSettings *nemo_compact_view_preferences; GSettings *nemo_desktop_preferences; GSettings *nemo_tree_sidebar_preferences; GSettings *nemo_window_state; GSettings *nemo_plugin_preferences; GSettings *nemo_menu_config_preferences; GSettings *gnome_lockdown_preferences; GSettings *gnome_background_preferences; GSettings *gnome_media_handling_preferences; GSettings *gnome_terminal_preferences; GSettings *cinnamon_privacy_preferences; GSettings *cinnamon_interface_preferences; /* Cached for fast access and used in nemo-file.c for constructing date/time strings */ GTimeZone *prefs_current_timezone; gboolean prefs_current_24h_time_format; NemoDateFormat prefs_current_date_format; GTimer *nemo_startup_timer; G_END_DECLS #endif /* NEMO_GLOBAL_PREFERENCES_H */ nemo-4.4.2/libnemo-private/nemo-icon-canvas-item.c000066400000000000000000002473331357442400300220270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* Nemo - Icon canvas item class for icon container. * * Copyright (C) 2000 Eazel, Inc * * Author: Andy Hertzfeld * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include "nemo-icon-canvas-item.h" #include #include "nemo-file-utilities.h" #include "nemo-global-preferences.h" #include "nemo-icon-private.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* gap between bottom of icon and start of text box */ #define LABEL_OFFSET 3 #define LABEL_OFFSET_BESIDES 3 #define LABEL_LINE_SPACING 0 /* special text height handling * each item has three text height variables: * + text_height: actual height of the displayed (i.e. on-screen) PangoLayout. * + text_height_for_layout: height used in icon grid layout algorithms. * “sane amount†of text. * “sane amount“ as of * + hard-coded to three lines in text-below-icon mode. * + unlimited in text-besides-icon mode (see VOODOO-TODO) * * This layout height is used by grid layout algorithms, even * though the actually displayed and/or requested text size may be larger * and overlap adjacent icons, if an icon is selected. * * + text_height_for_entire_text: height needed to display the entire PangoLayout, * if it wasn't ellipsized. */ /* Private part of the NemoIconCanvasItem structure. */ struct NemoIconCanvasItemDetails { /* The image, text, font. */ double x, y; GdkPixbuf *pixbuf; cairo_surface_t *rendered_surface; char *editable_text; /* Text that can be modified by a renaming function */ char *additional_text; /* Text that cannot be modifed, such as file size, etc. */ /* Size of the text at current font. */ int text_dx; int text_width; /* actual size required for rendering the text to display */ int text_height; /* actual size that would be required for rendering the entire text if it wasn't ellipsized */ int text_height_for_entire_text; /* actual size needed for rendering a “sane amount†of text */ int text_height_for_layout; int editable_text_height; /* whether the entire text must always be visible. In that case, * text_height_for_layout will always be equal to text_height. * Used for the last line of a line-wise icon layout. */ guint entire_text : 1; /* Highlight state. */ guint is_highlighted_for_selection : 1; guint is_highlighted_as_keyboard_focus: 1; guint is_highlighted_for_drop : 1; guint is_highlighted_for_clipboard : 1; guint show_stretch_handles : 1; guint is_prelit : 1; guint rendered_is_highlighted_for_selection : 1; guint rendered_is_highlighted_for_drop : 1; guint rendered_is_highlighted_for_clipboard : 1; guint rendered_is_prelit : 1; guint rendered_is_focused : 1; guint is_renaming : 1; guint bounds_cached : 1; guint is_visible : 1; guint is_pinned : 1; /* Cached PangoLayouts. Only used if the icon is visible */ PangoLayout *editable_text_layout; PangoLayout *additional_text_layout; /* Cached rectangle in canvas coordinates */ EelIRect canvas_rect; EelIRect text_rect; EelIRect bounds_cache; EelIRect bounds_cache_for_layout; EelIRect bounds_cache_for_entire_item; GdkWindow *cursor_window; /* Accessibility bits */ GailTextUtil *text_util; }; /* Object argument IDs. */ enum { PROP_0, PROP_EDITABLE_TEXT, PROP_ADDITIONAL_TEXT, PROP_HIGHLIGHTED_FOR_SELECTION, PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS, PROP_HIGHLIGHTED_FOR_DROP, PROP_HIGHLIGHTED_FOR_CLIPBOARD, PROP_PINNED }; typedef enum { RIGHT_SIDE, BOTTOM_SIDE, LEFT_SIDE, TOP_SIDE } RectangleSide; static void nemo_icon_canvas_item_text_interface_init (EelAccessibleTextIface *iface); static GType nemo_icon_canvas_item_accessible_factory_get_type (void); G_DEFINE_TYPE_WITH_CODE (NemoIconCanvasItem, nemo_icon_canvas_item, EEL_TYPE_CANVAS_ITEM, G_IMPLEMENT_INTERFACE (EEL_TYPE_ACCESSIBLE_TEXT, nemo_icon_canvas_item_text_interface_init)); /* private */ static void draw_label_text (NemoIconCanvasItem *item, cairo_t *cr, EelIRect icon_rect); static void measure_label_text (NemoIconCanvasItem *item); static void draw_pixbuf (GdkPixbuf *pixbuf, cairo_t *cr, int x, int y); static PangoLayout *get_label_layout (PangoLayout **layout, NemoIconCanvasItem *item, const char *text); static gboolean hit_test_stretch_handle (NemoIconCanvasItem *item, EelIRect canvas_rect, GtkCornerType *corner); static void nemo_icon_canvas_item_ensure_bounds_up_to_date (NemoIconCanvasItem *icon_item); /* Object initialization function for the icon item. */ static void nemo_icon_canvas_item_init (NemoIconCanvasItem *icon_item) { icon_item->details = G_TYPE_INSTANCE_GET_PRIVATE ((icon_item), NEMO_TYPE_ICON_CANVAS_ITEM, NemoIconCanvasItemDetails); nemo_icon_canvas_item_invalidate_label_size (icon_item); } static void nemo_icon_canvas_item_finalize (GObject *object) { NemoIconCanvasItemDetails *details; g_assert (NEMO_IS_ICON_CANVAS_ITEM (object)); details = NEMO_ICON_CANVAS_ITEM (object)->details; if (details->cursor_window != NULL) { gdk_window_set_cursor (details->cursor_window, NULL); g_object_unref (details->cursor_window); } if (details->pixbuf != NULL) { g_object_unref (details->pixbuf); } if (details->text_util != NULL) { g_object_unref (details->text_util); } g_free (details->editable_text); g_free (details->additional_text); if (details->rendered_surface != NULL) { cairo_surface_destroy (details->rendered_surface); } if (details->editable_text_layout != NULL) { g_object_unref (details->editable_text_layout); } if (details->additional_text_layout != NULL) { g_object_unref (details->additional_text_layout); } G_OBJECT_CLASS (nemo_icon_canvas_item_parent_class)->finalize (object); } /* Currently we require pixbufs in this format (for hit testing). * Perhaps gdk-pixbuf will be changed so it can do the hit testing * and we won't have this requirement any more. */ static gboolean pixbuf_is_acceptable (GdkPixbuf *pixbuf) { return gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB && ((!gdk_pixbuf_get_has_alpha (pixbuf) && gdk_pixbuf_get_n_channels (pixbuf) == 3) || (gdk_pixbuf_get_has_alpha (pixbuf) && gdk_pixbuf_get_n_channels (pixbuf) == 4)) && gdk_pixbuf_get_bits_per_sample (pixbuf) == 8; } static void nemo_icon_canvas_item_invalidate_bounds_cache (NemoIconCanvasItem *item) { item->details->bounds_cached = FALSE; } /* invalidate the text width and height cached in the item details. */ void nemo_icon_canvas_item_invalidate_label_size (NemoIconCanvasItem *item) { if (item->details->editable_text_layout != NULL) { pango_layout_context_changed (item->details->editable_text_layout); } if (item->details->additional_text_layout != NULL) { pango_layout_context_changed (item->details->additional_text_layout); } nemo_icon_canvas_item_invalidate_bounds_cache (item); item->details->text_width = -1; item->details->text_height = -1; item->details->text_height_for_layout = -1; item->details->text_height_for_entire_text = -1; item->details->editable_text_height = -1; } /* Set property handler for the icon item. */ static void nemo_icon_canvas_item_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoIconCanvasItem *item; NemoIconCanvasItemDetails *details; AtkObject *accessible; item = NEMO_ICON_CANVAS_ITEM (object); accessible = atk_gobject_accessible_for_object (G_OBJECT (item)); details = item->details; switch (property_id) { case PROP_EDITABLE_TEXT: if (g_strcmp0 (details->editable_text, g_value_get_string (value)) == 0) { return; } g_free (details->editable_text); details->editable_text = g_strdup (g_value_get_string (value)); if (details->text_util) { gail_text_util_text_setup (details->text_util, details->editable_text); g_object_notify (G_OBJECT(accessible), "accessible-name"); } nemo_icon_canvas_item_invalidate_label_size (item); if (details->editable_text_layout) { g_object_unref (details->editable_text_layout); details->editable_text_layout = NULL; } break; case PROP_ADDITIONAL_TEXT: if (g_strcmp0 (details->additional_text, g_value_get_string (value)) == 0) { return; } g_free (details->additional_text); details->additional_text = g_strdup (g_value_get_string (value)); nemo_icon_canvas_item_invalidate_label_size (item); if (details->additional_text_layout) { g_object_unref (details->additional_text_layout); details->additional_text_layout = NULL; } break; case PROP_HIGHLIGHTED_FOR_SELECTION: if (!details->is_highlighted_for_selection == !g_value_get_boolean (value)) { return; } details->is_highlighted_for_selection = g_value_get_boolean (value); nemo_icon_canvas_item_invalidate_label_size (item); atk_object_notify_state_change (accessible, ATK_STATE_SELECTED, details->is_highlighted_for_selection); break; case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS: if (!details->is_highlighted_as_keyboard_focus == !g_value_get_boolean (value)) { return; } details->is_highlighted_as_keyboard_focus = g_value_get_boolean (value); if (details->is_highlighted_as_keyboard_focus) { atk_focus_tracker_notify (accessible); } break; case PROP_HIGHLIGHTED_FOR_DROP: if (!details->is_highlighted_for_drop == !g_value_get_boolean (value)) { return; } details->is_highlighted_for_drop = g_value_get_boolean (value); nemo_icon_canvas_item_invalidate_label_size (item); break; case PROP_HIGHLIGHTED_FOR_CLIPBOARD: if (!details->is_highlighted_for_clipboard == !g_value_get_boolean (value)) { return; } details->is_highlighted_for_clipboard = g_value_get_boolean (value); break; case PROP_PINNED: if (!details->is_pinned == !g_value_get_boolean (value)) { return; } details->is_pinned = g_value_get_boolean (value); nemo_icon_canvas_item_invalidate_label (item); break; default: g_warning ("nemo_icons_view_item_item_set_arg on unknown argument"); return; } eel_canvas_item_request_update (EEL_CANVAS_ITEM (object)); } /* Get property handler for the icon item */ static void nemo_icon_canvas_item_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoIconCanvasItemDetails *details; details = NEMO_ICON_CANVAS_ITEM (object)->details; switch (property_id) { case PROP_EDITABLE_TEXT: g_value_set_string (value, details->editable_text); break; case PROP_ADDITIONAL_TEXT: g_value_set_string (value, details->additional_text); break; case PROP_HIGHLIGHTED_FOR_SELECTION: g_value_set_boolean (value, details->is_highlighted_for_selection); break; case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS: g_value_set_boolean (value, details->is_highlighted_as_keyboard_focus); break; case PROP_HIGHLIGHTED_FOR_DROP: g_value_set_boolean (value, details->is_highlighted_for_drop); break; case PROP_HIGHLIGHTED_FOR_CLIPBOARD: g_value_set_boolean (value, details->is_highlighted_for_clipboard); break; default: g_warning ("invalid property %d", property_id); break; } } static void get_scaled_icon_size (NemoIconCanvasItem *item, gint *width, gint *height) { EelCanvas *canvas; GdkPixbuf *pixbuf = NULL; gint scale; scale = 1.0; if (item != NULL) { canvas = EEL_CANVAS_ITEM (item)->canvas; scale = gtk_widget_get_scale_factor (GTK_WIDGET (canvas)); pixbuf = item->details->pixbuf; } if (width) *width = (pixbuf == NULL) ? 0 : (gdk_pixbuf_get_width (pixbuf) / scale); if (height) *height = (pixbuf == NULL) ? 0 : (gdk_pixbuf_get_height (pixbuf) / scale); } cairo_surface_t * nemo_icon_canvas_item_get_drag_surface (NemoIconCanvasItem *item) { cairo_surface_t *surface; EelCanvas *canvas; int width, height; int pix_width, pix_height; int item_offset_x, item_offset_y; EelIRect icon_rect; double item_x, item_y; cairo_t *cr; GtkStyleContext *context; cairo_surface_t *drag_surface; g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), NULL); canvas = EEL_CANVAS_ITEM (item)->canvas; context = gtk_widget_get_style_context (GTK_WIDGET (canvas)); gtk_style_context_save (context); gtk_style_context_add_class (context, "nemo-canvas-item"); /* Assume we're updated so canvas item data is right */ /* Calculate the offset from the top-left corner of the new image to the item position (where the pixmap is placed) */ eel_canvas_world_to_window (canvas, item->details->x, item->details->y, &item_x, &item_y); item_offset_x = item_x - EEL_CANVAS_ITEM (item)->x1; item_offset_y = item_y - EEL_CANVAS_ITEM (item)->y1; /* Calculate the width of the item */ width = EEL_CANVAS_ITEM (item)->x2 - EEL_CANVAS_ITEM (item)->x1; height = EEL_CANVAS_ITEM (item)->y2 - EEL_CANVAS_ITEM (item)->y1; surface = gdk_window_create_similar_surface (gtk_widget_get_window (GTK_WIDGET (canvas)), CAIRO_CONTENT_COLOR_ALPHA, width, height); cr = cairo_create (surface); drag_surface = gdk_cairo_surface_create_from_pixbuf (item->details->pixbuf, gtk_widget_get_scale_factor (GTK_WIDGET (canvas)), gtk_widget_get_window (GTK_WIDGET (canvas))); gtk_render_icon_surface (context, cr, drag_surface, item_offset_x, item_offset_y); cairo_surface_destroy (drag_surface); get_scaled_icon_size (item, &pix_width, &pix_height); icon_rect.x0 = item_offset_x; icon_rect.y0 = item_offset_y; icon_rect.x1 = item_offset_x + pix_width; icon_rect.y1 = item_offset_y + pix_height; draw_label_text (item, cr, icon_rect); cairo_destroy (cr); gtk_style_context_restore (context); return surface; } void nemo_icon_canvas_item_set_image (NemoIconCanvasItem *item, GdkPixbuf *image) { NemoIconCanvasItemDetails *details; g_return_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item)); g_return_if_fail (image == NULL || pixbuf_is_acceptable (image)); details = item->details; if (details->pixbuf == image) { return; } if (image != NULL) { g_object_ref (image); } if (details->pixbuf != NULL) { g_object_unref (details->pixbuf); } if (details->rendered_surface != NULL) { cairo_surface_destroy (details->rendered_surface); details->rendered_surface = NULL; } details->pixbuf = image; nemo_icon_canvas_item_invalidate_bounds_cache (item); eel_canvas_item_request_update (EEL_CANVAS_ITEM (item)); } /* Recomputes the bounding box of a icon canvas item. * This is a generic implementation that could be used for any canvas item * class, it has no assumptions about how the item is used. */ static void recompute_bounding_box (NemoIconCanvasItem *icon_item, double i2w_dx, double i2w_dy) { /* The bounds stored in the item is the same as what get_bounds * returns, except it's in canvas coordinates instead of the item's * parent's coordinates. */ EelCanvasItem *item; EelDRect bounds_rect; item = EEL_CANVAS_ITEM (icon_item); eel_canvas_item_get_bounds (item, &bounds_rect.x0, &bounds_rect.y0, &bounds_rect.x1, &bounds_rect.y1); bounds_rect.x0 += i2w_dx; bounds_rect.y0 += i2w_dy; bounds_rect.x1 += i2w_dx; bounds_rect.y1 += i2w_dy; eel_canvas_w2c_d (item->canvas, bounds_rect.x0, bounds_rect.y0, &item->x1, &item->y1); eel_canvas_w2c_d (item->canvas, bounds_rect.x1, bounds_rect.y1, &item->x2, &item->y2); } static EelIRect compute_text_rectangle (const NemoIconCanvasItem *item, EelIRect icon_rectangle, gboolean canvas_coords, NemoIconCanvasItemBoundsUsage usage) { EelIRect text_rectangle; double pixels_per_unit; double label_offset; double text_width, text_height, text_height_for_layout, text_height_for_entire_text, real_text_height, text_dx; pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; if (canvas_coords) { text_width = item->details->text_width; text_height = item->details->text_height; text_height_for_layout = item->details->text_height_for_layout; text_height_for_entire_text = item->details->text_height_for_entire_text; text_dx = item->details->text_dx; label_offset = LABEL_OFFSET; } else { text_width = item->details->text_width / pixels_per_unit; text_height = item->details->text_height / pixels_per_unit; text_height_for_layout = item->details->text_height_for_layout / pixels_per_unit; text_height_for_entire_text = item->details->text_height_for_entire_text / pixels_per_unit; text_dx = item->details->text_dx / pixels_per_unit; label_offset = LABEL_OFFSET / pixels_per_unit; } if (NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas)->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { if (!nemo_icon_container_is_layout_rtl (NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas))) { text_rectangle.x0 = icon_rectangle.x1 + LABEL_OFFSET_BESIDES; text_rectangle.x1 = text_rectangle.x0 + text_dx + text_width; } else { text_rectangle.x1 = icon_rectangle.x0; text_rectangle.x0 = text_rectangle.x1 - text_dx - text_width; } /* VOODOO-TODO */ #if 0 if (for_layout) { /* in this case, we should be more smart and calculate the size according to the maximum * number of lines fitting next to the icon. However, this requires a more complex layout logic. * It would mean that when measuring the label, the icon dimensions must be known already, * and we * 1. start with an unlimited layout * 2. measure how many lines of this layout fit next to the icon * 3. limit the number of lines to the given number of fitting lines */ real_text_height = VOODOO(); } else { #endif if (usage == BOUNDS_USAGE_FOR_LAYOUT) { real_text_height = text_height_for_layout; } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { real_text_height = text_height_for_entire_text; } else if (usage == BOUNDS_USAGE_FOR_DISPLAY) { real_text_height = text_height; } else { g_assert_not_reached (); } #if 0 } #endif text_rectangle.y0 = (icon_rectangle.y0 + icon_rectangle.y1) / 2- (int) real_text_height / 2; text_rectangle.y1 = text_rectangle.y0 + real_text_height; } else { text_rectangle.x0 = (icon_rectangle.x0 + icon_rectangle.x1) / 2 - (int) text_width / 2; text_rectangle.y0 = icon_rectangle.y1 + label_offset; text_rectangle.x1 = text_rectangle.x0 + text_width; if (usage == BOUNDS_USAGE_FOR_LAYOUT) { real_text_height = text_height_for_layout; } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { real_text_height = text_height_for_entire_text; } else if (usage == BOUNDS_USAGE_FOR_DISPLAY) { real_text_height = text_height; } else { g_assert_not_reached (); } text_rectangle.y1 = text_rectangle.y0 + real_text_height + label_offset; } return text_rectangle; } static EelIRect get_current_canvas_bounds (EelCanvasItem *item) { EelIRect bounds; g_assert (EEL_IS_CANVAS_ITEM (item)); bounds.x0 = item->x1; bounds.y0 = item->y1; bounds.x1 = item->x2; bounds.y1 = item->y2; return bounds; } void nemo_icon_canvas_item_update_bounds (NemoIconCanvasItem *item, double i2w_dx, double i2w_dy) { EelIRect before, after; EelCanvasItem *canvas_item; canvas_item = EEL_CANVAS_ITEM (item); /* Compute new bounds. */ before = get_current_canvas_bounds (canvas_item); recompute_bounding_box (item, i2w_dx, i2w_dy); after = get_current_canvas_bounds (canvas_item); /* If the bounds didn't change, we are done. */ if (eel_irect_equal (before, after)) { return; } /* Update canvas and text rect cache */ nemo_icon_canvas_item_get_icon_canvas_rectangle (item, &item->details->canvas_rect); item->details->text_rect = compute_text_rectangle (item, item->details->canvas_rect, TRUE, BOUNDS_USAGE_FOR_DISPLAY); /* queue a redraw. */ eel_canvas_request_redraw (canvas_item->canvas, before.x0, before.y0, before.x1 + 5, before.y1 + 5); } /* Update handler for the icon canvas item. */ static void nemo_icon_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags) { nemo_icon_canvas_item_update_bounds (NEMO_ICON_CANVAS_ITEM (item), i2w_dx, i2w_dy); eel_canvas_item_request_redraw (EEL_CANVAS_ITEM (item)); EEL_CANVAS_ITEM_CLASS (nemo_icon_canvas_item_parent_class)->update (item, i2w_dx, i2w_dy, flags); } /* Rendering */ static gboolean in_single_click_mode (void) { int click_policy; click_policy = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_CLICK_POLICY); return click_policy == NEMO_CLICK_POLICY_SINGLE; } /* Keep these for a bit while we work on performance of draw_or_measure_label_text. */ /* #define PERFORMANCE_TEST_DRAW_DISABLE #define PERFORMANCE_TEST_MEASURE_DISABLE */ /* This gets the size of the layout from the position of the layout. * This means that if the layout is right aligned we get the full width * of the layout, not just the width of the text snippet on the right side */ static void layout_get_full_size (PangoLayout *layout, int *width, int *height, int *dx) { PangoRectangle logical_rect; int the_width, total_width; pango_layout_get_extents (layout, NULL, &logical_rect); the_width = (logical_rect.width + PANGO_SCALE / 2) / PANGO_SCALE; total_width = (logical_rect.x + logical_rect.width + PANGO_SCALE / 2) / PANGO_SCALE; if (width != NULL) { *width = the_width; } if (height != NULL) { *height = (logical_rect.height + PANGO_SCALE / 2) / PANGO_SCALE; } if (dx != NULL) { *dx = total_width - the_width; } } static void layout_get_size_for_layout (PangoLayout *layout, int max_layout_line_count, int height_for_entire_text, int *height_for_layout) { PangoLayoutIter *iter; PangoRectangle logical_rect; int i; /* only use the first max_layout_line_count lines for the gridded auto layout */ if (pango_layout_get_line_count (layout) <= max_layout_line_count) { *height_for_layout = height_for_entire_text; } else { *height_for_layout = 0; iter = pango_layout_get_iter (layout); /* VOODOO-TODO, determine number of lines based on the icon size for text besides icon. * cf. compute_text_rectangle() */ for (i = 0; i < max_layout_line_count; i++) { pango_layout_iter_get_line_extents (iter, NULL, &logical_rect); *height_for_layout += (logical_rect.height + PANGO_SCALE / 2) / PANGO_SCALE; if (!pango_layout_iter_next_line (iter)) { break; } *height_for_layout += pango_layout_get_spacing (layout); } pango_layout_iter_free (iter); } } #define IS_COMPACT_VIEW(container) \ ((container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_L_R || \ container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_R_L) && \ container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) #define TEXT_BACK_PADDING_X 4 #define TEXT_BACK_PADDING_Y 1 static void prepare_pango_layout_width (NemoIconCanvasItem *item, PangoLayout *layout) { if (nemo_icon_canvas_item_get_max_text_width (item) < 0) { pango_layout_set_width (layout, -1); } else { pango_layout_set_width (layout, floor (nemo_icon_canvas_item_get_max_text_width (item)) * PANGO_SCALE); pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); } } static void prepare_pango_layout_for_measure_entire_text (NemoIconCanvasItem *item, PangoLayout *layout) { NemoIconContainer *container; prepare_pango_layout_width (item, layout); container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); if (IS_COMPACT_VIEW (container)) { pango_layout_set_height (layout, -1); } else { pango_layout_set_height (layout, G_MININT); } } static void prepare_pango_layout_for_draw (NemoIconCanvasItem *item, PangoLayout *layout) { NemoIconCanvasItemDetails *details; NemoIconContainer *container; gboolean needs_highlight; prepare_pango_layout_width (item, layout); container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); details = item->details; needs_highlight = details->is_highlighted_for_selection || details->is_highlighted_for_drop; if (IS_COMPACT_VIEW (container)) { pango_layout_set_height (layout, -1); } else if (needs_highlight || details->is_prelit || details->is_highlighted_as_keyboard_focus || details->entire_text) { /* VOODOO-TODO, cf. compute_text_rectangle() */ pango_layout_set_height (layout, G_MININT); } else { /* TODO? we might save some resources, when the re-layout is not neccessary in case * the layout height already fits into max. layout lines. But pango should figure this * out itself (which it doesn't ATM). */ pango_layout_set_height (layout, nemo_icon_container_get_max_layout_lines_for_pango (container)); } } static void measure_label_text (NemoIconCanvasItem *item) { NemoIconCanvasItemDetails *details; NemoIconContainer *container; gint editable_height, editable_height_for_layout, editable_height_for_entire_text, editable_width, editable_dx; gint additional_height, additional_width, additional_dx; PangoLayout *editable_layout; PangoLayout *additional_layout; gboolean have_editable, have_additional; /* check to see if the cached values are still valid; if so, there's * no work necessary */ if (item->details->text_width >= 0 && item->details->text_height >= 0) { return; } details = item->details; have_editable = details->editable_text != NULL && details->editable_text[0] != '\0'; have_additional = details->additional_text != NULL && details->additional_text[0] != '\0'; /* No font or no text, then do no work. */ if (!have_editable && !have_additional) { details->text_height = 0; details->text_height_for_layout = 0; details->text_height_for_entire_text = 0; details->text_width = 0; return; } #ifdef PERFORMANCE_TEST_MEASURE_DISABLE /* fake out the width */ details->text_width = 80; details->text_height = 20; details->text_height_for_layout = 20; details->text_height_for_entire_text = 20; return; #endif editable_width = 0; editable_height = 0; editable_height_for_layout = 0; editable_height_for_entire_text = 0; editable_dx = 0; additional_width = 0; additional_height = 0; additional_dx = 0; container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); editable_layout = NULL; additional_layout = NULL; if (have_editable) { /* first, measure required text height: editable_height_for_entire_text * then, measure text height applicable for layout: editable_height_for_layout * next, measure actually displayed height: editable_height */ editable_layout = get_label_layout (&details->editable_text_layout, item, details->editable_text); prepare_pango_layout_for_measure_entire_text (item, editable_layout); layout_get_full_size (editable_layout, NULL, &editable_height_for_entire_text, NULL); layout_get_size_for_layout (editable_layout, nemo_icon_container_get_max_layout_lines (container), editable_height_for_entire_text, &editable_height_for_layout); prepare_pango_layout_for_draw (item, editable_layout); layout_get_full_size (editable_layout, &editable_width, &editable_height, &editable_dx); } if (have_additional) { additional_layout = get_label_layout (&details->additional_text_layout, item, details->additional_text); prepare_pango_layout_for_draw (item, additional_layout); layout_get_full_size (additional_layout, &additional_width, &additional_height, &additional_dx); } details->editable_text_height = editable_height; if (editable_width > additional_width) { details->text_width = editable_width; details->text_dx = editable_dx; } else { details->text_width = additional_width; details->text_dx = additional_dx; } if (have_additional) { details->text_height = editable_height + LABEL_LINE_SPACING + additional_height; details->text_height_for_layout = editable_height_for_layout + LABEL_LINE_SPACING + additional_height; details->text_height_for_entire_text = editable_height_for_entire_text + LABEL_LINE_SPACING + additional_height; } else { details->text_height = editable_height; details->text_height_for_layout = editable_height_for_layout; details->text_height_for_entire_text = editable_height_for_entire_text; } /* add some extra space for highlighting even when we don't highlight so things won't move */ /* extra slop for nicer highlighting */ details->text_height += TEXT_BACK_PADDING_Y*2; details->text_height_for_layout += TEXT_BACK_PADDING_Y*2; details->text_height_for_entire_text += TEXT_BACK_PADDING_Y*2; details->editable_text_height += TEXT_BACK_PADDING_Y*2; /* extra to make it look nicer */ details->text_width += TEXT_BACK_PADDING_X*2; if (editable_layout) { g_object_unref (editable_layout); } if (additional_layout) { g_object_unref (additional_layout); } } static void draw_label_text (NemoIconCanvasItem *item, cairo_t *cr, EelIRect icon_rect) { NemoIconCanvasItemDetails *details; NemoIconContainer *container; PangoLayout *editable_layout; PangoLayout *additional_layout; GtkStyleContext *context; GtkStateFlags state, base_state; gboolean have_editable, have_additional; gboolean needs_highlight, prelight_label, is_rtl_label_beside; EelIRect text_rect; int x; int max_text_width; gdouble frame_w, frame_h, frame_x, frame_y; gboolean draw_frame = TRUE; #ifdef PERFORMANCE_TEST_DRAW_DISABLE return; #endif details = item->details; measure_label_text (item); if (details->text_height == 0 || details->text_width == 0) { return; } container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); context = gtk_widget_get_style_context (GTK_WIDGET (container)); text_rect = compute_text_rectangle (item, icon_rect, TRUE, BOUNDS_USAGE_FOR_DISPLAY); needs_highlight = details->is_highlighted_for_selection || details->is_highlighted_for_drop; is_rtl_label_beside = nemo_icon_container_is_layout_rtl (container) && container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE; editable_layout = NULL; additional_layout = NULL; have_editable = details->editable_text != NULL && details->editable_text[0] != '\0'; have_additional = details->additional_text != NULL && details->additional_text[0] != '\0'; g_assert (have_editable || have_additional); max_text_width = floor (nemo_icon_canvas_item_get_max_text_width (item)); base_state = gtk_widget_get_state_flags (GTK_WIDGET (container)); base_state &= ~(GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_PRELIGHT); state = base_state; gtk_widget_style_get (GTK_WIDGET (container), "activate_prelight_icon_label", &prelight_label, NULL); /* if the icon is highlighted, do some set-up */ if (needs_highlight && !details->is_renaming) { state |= GTK_STATE_FLAG_SELECTED; frame_x = is_rtl_label_beside ? text_rect.x0 + item->details->text_dx : text_rect.x0; frame_y = text_rect.y0; frame_w = is_rtl_label_beside ? text_rect.x1 - text_rect.x0 - item->details->text_dx : text_rect.x1 - text_rect.x0; frame_h = text_rect.y1 - text_rect.y0; } else if (!needs_highlight && have_editable && details->text_width > 0 && details->text_height > 0 && prelight_label && item->details->is_prelit) { state |= GTK_STATE_FLAG_PRELIGHT; frame_x = text_rect.x0; frame_y = text_rect.y0; frame_w = text_rect.x1 - text_rect.x0; frame_h = text_rect.y1 - text_rect.y0; } else { draw_frame = FALSE; } if (draw_frame) { gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_render_frame (context, cr, frame_x, frame_y, frame_w, frame_h); gtk_render_background (context, cr, frame_x, frame_y, frame_w, frame_h); gtk_style_context_restore (context); } if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { x = text_rect.x0 + 2; } else { x = text_rect.x0 + ((text_rect.x1 - text_rect.x0) - max_text_width) / 2; } if (have_editable && !details->is_renaming) { state = base_state; if (prelight_label && item->details->is_prelit) { state |= GTK_STATE_FLAG_PRELIGHT; } if (needs_highlight) { state |= GTK_STATE_FLAG_SELECTED; } editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text); prepare_pango_layout_for_draw (item, editable_layout); gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_render_layout (context, cr, x, text_rect.y0 + TEXT_BACK_PADDING_Y, editable_layout); gtk_style_context_restore (context); } if (have_additional && !details->is_renaming) { state = base_state; if (needs_highlight) { state |= GTK_STATE_FLAG_SELECTED; } additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text); prepare_pango_layout_for_draw (item, additional_layout); gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_style_context_add_class (context, "dim-label"); gtk_render_layout (context, cr, x, text_rect.y0 + details->editable_text_height + LABEL_LINE_SPACING + TEXT_BACK_PADDING_Y, additional_layout); } if (item->details->is_highlighted_as_keyboard_focus) { if (needs_highlight) { state = GTK_STATE_FLAG_SELECTED; } gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_render_focus (context, cr, text_rect.x0, text_rect.y0, text_rect.x1 - text_rect.x0, text_rect.y1 - text_rect.y0); gtk_style_context_restore (context); } if (editable_layout != NULL) { g_object_unref (editable_layout); } if (additional_layout != NULL) { g_object_unref (additional_layout); } } void nemo_icon_canvas_item_set_is_visible (NemoIconCanvasItem *item, gboolean visible) { if (item->details->is_visible == visible) return; item->details->is_visible = visible; if (!visible) { nemo_icon_canvas_item_invalidate_label (item); } } void nemo_icon_canvas_item_invalidate_label (NemoIconCanvasItem *item) { nemo_icon_canvas_item_invalidate_label_size (item); if (item->details->editable_text_layout) { g_object_unref (item->details->editable_text_layout); item->details->editable_text_layout = NULL; } if (item->details->additional_text_layout) { g_object_unref (item->details->additional_text_layout); item->details->additional_text_layout = NULL; } } static GdkPixbuf * get_knob_pixbuf (void) { GdkPixbuf *knob_pixbuf; knob_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "stock-nemo-knob", 8, 0, NULL); if (!knob_pixbuf) { GInputStream *stream = g_resources_open_stream ("/org/nemo/icons/knob.png", 0, NULL); if (stream != NULL) { knob_pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL); g_object_unref (stream); } } return knob_pixbuf; } static void draw_stretch_handles (NemoIconCanvasItem *item, cairo_t *cr, const EelIRect *rect) { GtkWidget *widget; GdkPixbuf *knob_pixbuf; int knob_width, knob_height; double dash = { 2.0 }; GtkStyleContext *style; GdkRGBA color; if (!item->details->show_stretch_handles) { return; } widget = GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas); style = gtk_widget_get_style_context (widget); cairo_save (cr); knob_pixbuf = get_knob_pixbuf (); knob_width = gdk_pixbuf_get_width (knob_pixbuf); knob_height = gdk_pixbuf_get_height (knob_pixbuf); /* first draw the box */ gtk_style_context_get_color (style, GTK_STATE_FLAG_SELECTED, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_set_dash (cr, &dash, 1, 0); cairo_set_line_width (cr, 1.0); cairo_rectangle (cr, rect->x0 + 0.5, rect->y0 + 0.5, rect->x1 - rect->x0 - 1, rect->y1 - rect->y0 - 1); cairo_stroke (cr); cairo_restore (cr); /* draw the stretch handles themselves */ draw_pixbuf (knob_pixbuf, cr, rect->x0, rect->y0); draw_pixbuf (knob_pixbuf, cr, rect->x0, rect->y1 - knob_height); draw_pixbuf (knob_pixbuf, cr, rect->x1 - knob_width, rect->y0); draw_pixbuf (knob_pixbuf, cr, rect->x1 - knob_width, rect->y1 - knob_height); g_object_unref (knob_pixbuf); } static void draw_pixbuf (GdkPixbuf *pixbuf, cairo_t *cr, int x, int y) { cairo_save (cr); gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); cairo_paint (cr); cairo_restore (cr); } /* shared code to highlight or dim the passed-in pixbuf */ static cairo_surface_t * real_map_surface (NemoIconCanvasItem *icon_item) { EelCanvas *canvas; GdkPixbuf *temp_pixbuf, *old_pixbuf; GtkStyleContext *style; GdkRGBA color; cairo_surface_t *surface; temp_pixbuf = icon_item->details->pixbuf; canvas = EEL_CANVAS_ITEM(icon_item)->canvas; g_object_ref (temp_pixbuf); if (icon_item->details->is_prelit || icon_item->details->is_highlighted_for_clipboard) { old_pixbuf = temp_pixbuf; temp_pixbuf = eel_create_spotlight_pixbuf (temp_pixbuf); g_object_unref (old_pixbuf); } if (icon_item->details->is_highlighted_for_selection || icon_item->details->is_highlighted_for_drop) { style = gtk_widget_get_style_context (GTK_WIDGET (canvas)); if (gtk_widget_has_focus (GTK_WIDGET (canvas))) { gtk_style_context_get_background_color (style, GTK_STATE_FLAG_SELECTED, &color); } else { gtk_style_context_get_background_color (style, GTK_STATE_FLAG_ACTIVE, &color); } old_pixbuf = temp_pixbuf; temp_pixbuf = eel_create_colorized_pixbuf (temp_pixbuf, &color); g_object_unref (old_pixbuf); } surface = gdk_cairo_surface_create_from_pixbuf (temp_pixbuf, gtk_widget_get_scale_factor (GTK_WIDGET (canvas)), gtk_widget_get_window (GTK_WIDGET (canvas))); g_object_unref (temp_pixbuf); return surface; } static cairo_surface_t * map_surface (NemoIconCanvasItem *icon_item) { if (!(icon_item->details->rendered_surface != NULL && icon_item->details->rendered_is_prelit == icon_item->details->is_prelit && icon_item->details->rendered_is_highlighted_for_selection == icon_item->details->is_highlighted_for_selection && icon_item->details->rendered_is_highlighted_for_drop == icon_item->details->is_highlighted_for_drop && icon_item->details->rendered_is_highlighted_for_clipboard == icon_item->details->is_highlighted_for_clipboard && (icon_item->details->is_highlighted_for_selection && icon_item->details->rendered_is_focused == gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas))))) { if (icon_item->details->rendered_surface != NULL) { cairo_surface_destroy (icon_item->details->rendered_surface); } icon_item->details->rendered_surface = real_map_surface (icon_item); icon_item->details->rendered_is_prelit = icon_item->details->is_prelit; icon_item->details->rendered_is_highlighted_for_selection = icon_item->details->is_highlighted_for_selection; icon_item->details->rendered_is_highlighted_for_drop = icon_item->details->is_highlighted_for_drop; icon_item->details->rendered_is_highlighted_for_clipboard = icon_item->details->is_highlighted_for_clipboard; icon_item->details->rendered_is_focused = gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas)); } cairo_surface_reference (icon_item->details->rendered_surface); return icon_item->details->rendered_surface; } /* Draw the icon item for non-anti-aliased mode. */ static void nemo_icon_canvas_item_draw (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region) { NemoIconContainer *container; NemoIconCanvasItem *icon_item; NemoIconCanvasItemDetails *details; EelIRect icon_rect; cairo_surface_t *temp_surface; GtkStyleContext *context; container = NEMO_ICON_CONTAINER (item->canvas); icon_item = NEMO_ICON_CANVAS_ITEM (item); details = icon_item->details; /* Draw the pixbuf. */ if (details->pixbuf == NULL) { return; } context = gtk_widget_get_style_context (GTK_WIDGET (container)); gtk_style_context_save (context); gtk_style_context_add_class (context, "nemo-canvas-item"); icon_rect = icon_item->details->canvas_rect; temp_surface = map_surface (icon_item); gtk_render_icon_surface (context, cr, temp_surface, icon_rect.x0, icon_rect.y0); cairo_surface_destroy (temp_surface); /* Draw stretching handles (if necessary). */ draw_stretch_handles (icon_item, cr, &icon_rect); /* Draw the label text. */ draw_label_text (icon_item, cr, icon_rect); gtk_style_context_restore (context); } #define ZERO_WIDTH_SPACE "\xE2\x80\x8B" static PangoLayout * create_label_layout (NemoIconCanvasItem *item, const char *text) { PangoLayout *layout; PangoContext *context; PangoFontDescription *desc; NemoIconContainer *container; EelCanvasItem *canvas_item; GString *str; char *zeroified_text; const char *p; #ifdef HAVE_PANGO_144 PangoAttrList *attr_list; #endif canvas_item = EEL_CANVAS_ITEM (item); container = NEMO_ICON_CONTAINER (canvas_item->canvas); context = gtk_widget_get_pango_context (GTK_WIDGET (canvas_item->canvas)); layout = pango_layout_new (context); #ifdef HAVE_PANGO_144 attr_list = pango_attr_list_new (); #endif zeroified_text = NULL; if (text != NULL) { str = g_string_new (NULL); for (p = text; *p != '\0'; p++) { str = g_string_append_c (str, *p); if (*p == '_' || *p == '-' || (*p == '.' && !g_ascii_isdigit(*(p+1)))) { /* Ensure that we allow to break after '_' or '.' characters, * if they are not followed by a number */ str = g_string_append (str, ZERO_WIDTH_SPACE); } } zeroified_text = g_string_free (str, FALSE); } pango_layout_set_text (layout, zeroified_text, -1); pango_layout_set_auto_dir (layout, FALSE); if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { if (!nemo_icon_container_is_layout_rtl (container)) { pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); } else { pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); } } else { pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); } pango_layout_set_spacing (layout, LABEL_LINE_SPACING); pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); #ifdef HAVE_PANGO_144 pango_attr_list_insert (attr_list, pango_attr_insert_hyphens_new (FALSE)); pango_layout_set_attributes (layout, attr_list); #endif /* Create a font description */ if (container->details->font && g_strcmp0 (container->details->font, "") != 0) { desc = pango_font_description_from_string (container->details->font); } else { desc = pango_font_description_copy (pango_context_get_font_description (context)); } if (pango_font_description_get_size (desc) > 0) { pango_font_description_set_size (desc, pango_font_description_get_size (desc) + container->details->font_size_table [container->details->zoom_level]); } if (item->details->is_pinned) { pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD); } pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); g_free (zeroified_text); #ifdef HAVE_PANGO_144 pango_attr_list_unref (attr_list); #endif return layout; } static PangoLayout * get_label_layout (PangoLayout **layout_cache, NemoIconCanvasItem *item, const char *text) { PangoLayout *layout; if (*layout_cache != NULL) { return g_object_ref (*layout_cache); } layout = create_label_layout (item, text); if (item->details->is_visible) { *layout_cache = g_object_ref (layout); } return layout; } /* handle events */ static int nemo_icon_canvas_item_event (EelCanvasItem *item, GdkEvent *event) { NemoIconCanvasItem *icon_item; GdkCursor *cursor; GdkWindow *cursor_window; icon_item = NEMO_ICON_CANVAS_ITEM (item); cursor_window = ((GdkEventAny *)event)->window; if (event->type == GDK_ENTER_NOTIFY) { nemo_icon_container_update_tooltip_text (NEMO_ICON_CONTAINER (item->canvas), icon_item); if (!icon_item->details->is_prelit) { icon_item->details->is_prelit = TRUE; nemo_icon_canvas_item_invalidate_label_size (icon_item); eel_canvas_item_request_update (item); eel_canvas_item_send_behind (item, NEMO_ICON_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle); /* show a hand cursor */ if (in_single_click_mode ()) { cursor = gdk_cursor_new_for_display (gdk_display_get_default(), GDK_HAND2); gdk_window_set_cursor (cursor_window, cursor); g_object_unref (cursor); icon_item->details->cursor_window = g_object_ref (cursor_window); } } return TRUE; } else if (event->type == GDK_LEAVE_NOTIFY) { nemo_icon_container_update_tooltip_text (NEMO_ICON_CONTAINER (item->canvas), NULL); if (icon_item->details->is_prelit || icon_item->details->is_highlighted_for_drop) { /* When leaving, turn of the prelight state and the * higlighted for drop. The latter gets turned on * by the drag&drop motion callback. */ icon_item->details->is_prelit = FALSE; icon_item->details->is_highlighted_for_drop = FALSE; nemo_icon_canvas_item_invalidate_label_size (icon_item); eel_canvas_item_request_update (item); /* show default cursor */ gdk_window_set_cursor (cursor_window, NULL); g_clear_object (&icon_item->details->cursor_window); } return TRUE; } return FALSE; } static gboolean hit_test (NemoIconCanvasItem *icon_item, EelIRect canvas_rect) { NemoIconCanvasItemDetails *details; details = icon_item->details; /* Quick check to see if the rect hits the icon or text at all. */ if (!eel_irect_hits_irect (icon_item->details->canvas_rect, canvas_rect) && (!eel_irect_hits_irect (details->text_rect, canvas_rect))) { return FALSE; } /* Check for hits in the stretch handles. */ if (hit_test_stretch_handle (icon_item, canvas_rect, NULL)) { return TRUE; } /* Check for hit in the icon. */ if (eel_irect_hits_irect (icon_item->details->canvas_rect, canvas_rect)) { return TRUE; } /* Check for hit in the text. */ if (eel_irect_hits_irect (details->text_rect, canvas_rect) && !icon_item->details->is_renaming) { return TRUE; } return FALSE; } /* Point handler for the icon canvas item. */ static double nemo_icon_canvas_item_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) { EelIRect canvas_rect; *actual_item = item; canvas_rect.x0 = cx; canvas_rect.y0 = cy; canvas_rect.x1 = cx + 1; canvas_rect.y1 = cy + 1; if (hit_test (NEMO_ICON_CANVAS_ITEM (item), canvas_rect)) { return 0.0; } else { /* This value means not hit. * It's kind of arbitrary. Can we do better? */ return item->canvas->pixels_per_unit * 2 + 10; } } static void nemo_icon_canvas_item_translate (EelCanvasItem *item, double dx, double dy) { NemoIconCanvasItem *icon_item; NemoIconCanvasItemDetails *details; icon_item = NEMO_ICON_CANVAS_ITEM (item); details = icon_item->details; details->x += dx; details->y += dy; } void nemo_icon_canvas_item_get_bounds_for_layout (NemoIconCanvasItem *icon_item, double *x1, double *y1, double *x2, double *y2) { NemoIconCanvasItemDetails *details; EelIRect *total_rect; details = icon_item->details; nemo_icon_canvas_item_ensure_bounds_up_to_date (icon_item); g_assert (details->bounds_cached); total_rect = &details->bounds_cache_for_layout; /* Return the result. */ if (x1 != NULL) { *x1 = (int)details->x + total_rect->x0; } if (y1 != NULL) { *y1 = (int)details->y + total_rect->y0; } if (x2 != NULL) { *x2 = (int)details->x + total_rect->x1 + 1; } if (y2 != NULL) { *y2 = (int)details->y + total_rect->y1 + 1; } } void nemo_icon_canvas_item_get_bounds_for_entire_item (NemoIconCanvasItem *icon_item, double *x1, double *y1, double *x2, double *y2) { NemoIconCanvasItemDetails *details; EelIRect *total_rect; details = icon_item->details; nemo_icon_canvas_item_ensure_bounds_up_to_date (icon_item); g_assert (details->bounds_cached); total_rect = &details->bounds_cache_for_entire_item; /* Return the result. */ if (x1 != NULL) { *x1 = (int)details->x + total_rect->x0; } if (y1 != NULL) { *y1 = (int)details->y + total_rect->y0; } if (x2 != NULL) { *x2 = (int)details->x + total_rect->x1 + 1; } if (y2 != NULL) { *y2 = (int)details->y + total_rect->y1 + 1; } } /* Bounds handler for the icon canvas item. */ static void nemo_icon_canvas_item_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { NemoIconCanvasItem *icon_item; NemoIconCanvasItemDetails *details; EelIRect *total_rect; icon_item = NEMO_ICON_CANVAS_ITEM (item); details = icon_item->details; g_assert (x1 != NULL); g_assert (y1 != NULL); g_assert (x2 != NULL); g_assert (y2 != NULL); nemo_icon_canvas_item_ensure_bounds_up_to_date (icon_item); g_assert (details->bounds_cached); total_rect = &details->bounds_cache; /* Return the result. */ *x1 = (int)details->x + total_rect->x0; *y1 = (int)details->y + total_rect->y0; *x2 = (int)details->x + total_rect->x1 + 1; *y2 = (int)details->y + total_rect->y1 + 1; } static void nemo_icon_canvas_item_ensure_bounds_up_to_date (NemoIconCanvasItem *icon_item) { NemoIconCanvasItemDetails *details; EelIRect icon_rect, icon_rect_raw; EelIRect text_rect, text_rect_for_layout, text_rect_for_entire_text; EelIRect total_rect, total_rect_for_layout, total_rect_for_entire_text; EelCanvasItem *item; double pixels_per_unit; gint width, height; details = icon_item->details; item = EEL_CANVAS_ITEM (icon_item); if (!details->bounds_cached) { measure_label_text (icon_item); pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; /* Compute raw and scaled icon rectangle. */ icon_rect.x0 = 0; icon_rect.y0 = 0; icon_rect_raw.x0 = 0; icon_rect_raw.y0 = 0; get_scaled_icon_size (icon_item, &width, &height); icon_rect_raw.x1 = icon_rect_raw.x0 + width; icon_rect_raw.y1 = icon_rect_raw.y0 + height; icon_rect.x1 = icon_rect_raw.x1 / pixels_per_unit; icon_rect.y1 = icon_rect_raw.y1 / pixels_per_unit; /* Compute text rectangle. */ text_rect = compute_text_rectangle (icon_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_DISPLAY); text_rect_for_layout = compute_text_rectangle (icon_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_LAYOUT); text_rect_for_entire_text = compute_text_rectangle (icon_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_ENTIRE_ITEM); /* Compute total rectangle */ eel_irect_union (&total_rect, &icon_rect, &text_rect); eel_irect_union (&total_rect_for_layout, &icon_rect, &text_rect_for_layout); eel_irect_union (&total_rect_for_entire_text, &icon_rect, &text_rect_for_entire_text); details->bounds_cache = total_rect; details->bounds_cache_for_layout = total_rect_for_layout; details->bounds_cache_for_entire_item = total_rect_for_entire_text; details->bounds_cached = TRUE; } } /* Get the rectangle of the icon only, in world coordinates. */ EelDRect nemo_icon_canvas_item_get_icon_rectangle (const NemoIconCanvasItem *item) { EelDRect rectangle; double pixels_per_unit; gint width, height; g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), eel_drect_empty); rectangle.x0 = item->details->x; rectangle.y0 = item->details->y; pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; get_scaled_icon_size (NEMO_ICON_CANVAS_ITEM (item), &width, &height); rectangle.x1 = rectangle.x0 + width / pixels_per_unit; rectangle.y1 = rectangle.y0 + height / pixels_per_unit; eel_canvas_item_i2w (EEL_CANVAS_ITEM (item), &rectangle.x0, &rectangle.y0); eel_canvas_item_i2w (EEL_CANVAS_ITEM (item), &rectangle.x1, &rectangle.y1); return rectangle; } EelDRect nemo_icon_canvas_item_get_text_rectangle (NemoIconCanvasItem *item, gboolean for_layout) { /* FIXME */ EelIRect icon_rectangle; EelIRect text_rectangle; EelDRect ret; double pixels_per_unit; gint width, height; g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), eel_drect_empty); icon_rectangle.x0 = item->details->x; icon_rectangle.y0 = item->details->y; pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; get_scaled_icon_size (item, &width, &height); icon_rectangle.x1 = icon_rectangle.x0 + width / pixels_per_unit; icon_rectangle.y1 = icon_rectangle.y0 + height / pixels_per_unit; measure_label_text (item); text_rectangle = compute_text_rectangle (item, icon_rectangle, FALSE, for_layout ? BOUNDS_USAGE_FOR_LAYOUT : BOUNDS_USAGE_FOR_DISPLAY); ret.x0 = text_rectangle.x0; ret.y0 = text_rectangle.y0; ret.x1 = text_rectangle.x1; ret.y1 = text_rectangle.y1; eel_canvas_item_i2w (EEL_CANVAS_ITEM (item), &ret.x0, &ret.y0); eel_canvas_item_i2w (EEL_CANVAS_ITEM (item), &ret.x1, &ret.y1); return ret; } /* Get the rectangle of the icon only, in canvas coordinates. */ void nemo_icon_canvas_item_get_icon_canvas_rectangle (NemoIconCanvasItem *item, EelIRect *rect) { gint width, height; g_assert (NEMO_IS_ICON_CANVAS_ITEM (item)); g_assert (rect != NULL); eel_canvas_w2c (EEL_CANVAS_ITEM (item)->canvas, item->details->x, item->details->y, &rect->x0, &rect->y0); get_scaled_icon_size (item, &width, &height); rect->x1 = rect->x0 + width; rect->y1 = rect->y0 + height; } void nemo_icon_canvas_item_set_show_stretch_handles (NemoIconCanvasItem *item, gboolean show_stretch_handles) { g_return_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item)); g_return_if_fail (show_stretch_handles == FALSE || show_stretch_handles == TRUE); if (!item->details->show_stretch_handles == !show_stretch_handles) { return; } item->details->show_stretch_handles = show_stretch_handles; eel_canvas_item_request_update (EEL_CANVAS_ITEM (item)); } /* Check if one of the stretch handles was hit. */ static gboolean hit_test_stretch_handle (NemoIconCanvasItem *item, EelIRect probe_canvas_rect, GtkCornerType *corner) { EelIRect icon_rect; GdkPixbuf *knob_pixbuf; int knob_width, knob_height; int hit_corner; g_assert (NEMO_IS_ICON_CANVAS_ITEM (item)); /* Make sure there are handles to hit. */ if (!item->details->show_stretch_handles) { return FALSE; } /* Quick check to see if the rect hits the icon at all. */ icon_rect = item->details->canvas_rect; if (!eel_irect_hits_irect (probe_canvas_rect, icon_rect)) { return FALSE; } knob_pixbuf = get_knob_pixbuf (); knob_width = gdk_pixbuf_get_width (knob_pixbuf); knob_height = gdk_pixbuf_get_height (knob_pixbuf); g_object_unref (knob_pixbuf); /* Check for hits in the stretch handles. */ hit_corner = -1; if (probe_canvas_rect.x0 < icon_rect.x0 + knob_width) { if (probe_canvas_rect.y0 < icon_rect.y0 + knob_height) hit_corner = GTK_CORNER_TOP_LEFT; else if (probe_canvas_rect.y1 >= icon_rect.y1 - knob_height) hit_corner = GTK_CORNER_BOTTOM_LEFT; } else if (probe_canvas_rect.x1 >= icon_rect.x1 - knob_width) { if (probe_canvas_rect.y0 < icon_rect.y0 + knob_height) hit_corner = GTK_CORNER_TOP_RIGHT; else if (probe_canvas_rect.y1 >= icon_rect.y1 - knob_height) hit_corner = GTK_CORNER_BOTTOM_RIGHT; } if (corner) *corner = hit_corner; return hit_corner != -1; } gboolean nemo_icon_canvas_item_hit_test_stretch_handles (NemoIconCanvasItem *item, gdouble world_x, gdouble world_y, GtkCornerType *corner) { EelIRect canvas_rect; g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), FALSE); eel_canvas_w2c (EEL_CANVAS_ITEM (item)->canvas, world_x, world_y, &canvas_rect.x0, &canvas_rect.y0); canvas_rect.x1 = canvas_rect.x0 + 1; canvas_rect.y1 = canvas_rect.y0 + 1; return hit_test_stretch_handle (item, canvas_rect, corner); } /* nemo_icon_canvas_item_hit_test_rectangle * * Check and see if there is an intersection between the item and the * canvas rect. */ gboolean nemo_icon_canvas_item_hit_test_rectangle (NemoIconCanvasItem *item, EelIRect canvas_rect) { g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), FALSE); return hit_test (item, canvas_rect); } const char * nemo_icon_canvas_item_get_editable_text (NemoIconCanvasItem *icon_item) { g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (icon_item), NULL); return icon_item->details->editable_text; } void nemo_icon_canvas_item_set_renaming (NemoIconCanvasItem *item, gboolean state) { g_return_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item)); g_return_if_fail (state == FALSE || state == TRUE); if (!item->details->is_renaming == !state) { return; } item->details->is_renaming = state; eel_canvas_item_request_update (EEL_CANVAS_ITEM (item)); } double nemo_icon_canvas_item_get_max_text_width (NemoIconCanvasItem *item) { EelCanvasItem *canvas_item; NemoIconContainer *container; canvas_item = EEL_CANVAS_ITEM (item); container = NEMO_ICON_CONTAINER (canvas_item->canvas); if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { if (container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_L_R || container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_R_L) { /* compact view */ if (container->details->all_columns_same_width) { return GET_VIEW_CONSTANT (container, max_text_width_beside_top_to_bottom) * canvas_item->canvas->pixels_per_unit; } else { return -1; } } else { /* normal icon view with labels-beside-icons */ return GET_VIEW_CONSTANT (container, max_text_width_beside) * canvas_item->canvas->pixels_per_unit; } } else { /* normal icon view */ if (container->details->is_desktop) { return nemo_get_desktop_text_width_for_zoom_level (nemo_icon_container_get_zoom_level (container)); } else { return nemo_get_icon_text_width_for_zoom_level (nemo_icon_container_get_zoom_level (container)); } } } void nemo_icon_canvas_item_set_entire_text (NemoIconCanvasItem *item, gboolean entire_text) { if (item->details->entire_text != entire_text) { item->details->entire_text = entire_text; nemo_icon_canvas_item_invalidate_label_size (item); eel_canvas_item_request_update (EEL_CANVAS_ITEM (item)); } } /* Class initialization function for the icon canvas item. */ static void nemo_icon_canvas_item_class_init (NemoIconCanvasItemClass *class) { GObjectClass *object_class; EelCanvasItemClass *item_class; object_class = G_OBJECT_CLASS (class); item_class = EEL_CANVAS_ITEM_CLASS (class); object_class->finalize = nemo_icon_canvas_item_finalize; object_class->set_property = nemo_icon_canvas_item_set_property; object_class->get_property = nemo_icon_canvas_item_get_property; g_object_class_install_property ( object_class, PROP_EDITABLE_TEXT, g_param_spec_string ("editable_text", "editable text", "the editable label", "", G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_ADDITIONAL_TEXT, g_param_spec_string ("additional_text", "additional text", "some more text", "", G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_HIGHLIGHTED_FOR_SELECTION, g_param_spec_boolean ("highlighted_for_selection", "highlighted for selection", "whether we are highlighted for a selection", FALSE, G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS, g_param_spec_boolean ("highlighted_as_keyboard_focus", "highlighted as keyboard focus", "whether we are highlighted to render keyboard focus", FALSE, G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_HIGHLIGHTED_FOR_DROP, g_param_spec_boolean ("highlighted_for_drop", "highlighted for drop", "whether we are highlighted for a D&D drop", FALSE, G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_HIGHLIGHTED_FOR_CLIPBOARD, g_param_spec_boolean ("highlighted_for_clipboard", "highlighted for clipboard", "whether we are highlighted for a clipboard paste (after we have been cut)", FALSE, G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_PINNED, g_param_spec_boolean ("pinned", "pinned", "backing file is pinned", FALSE, G_PARAM_READWRITE)); item_class->update = nemo_icon_canvas_item_update; item_class->draw = nemo_icon_canvas_item_draw; item_class->point = nemo_icon_canvas_item_point; item_class->translate = nemo_icon_canvas_item_translate; item_class->bounds = nemo_icon_canvas_item_bounds; item_class->event = nemo_icon_canvas_item_event; atk_registry_set_factory_type (atk_get_default_registry (), NEMO_TYPE_ICON_CANVAS_ITEM, nemo_icon_canvas_item_accessible_factory_get_type ()); g_type_class_add_private (class, sizeof (NemoIconCanvasItemDetails)); } static GailTextUtil * nemo_icon_canvas_item_get_text (GObject *text) { return NEMO_ICON_CANVAS_ITEM (text)->details->text_util; } static void nemo_icon_canvas_item_text_interface_init (EelAccessibleTextIface *iface) { iface->get_text = nemo_icon_canvas_item_get_text; } /* ============================= a11y interfaces =========================== */ static const char *nemo_icon_canvas_item_accessible_action_names[] = { "open", "menu", NULL }; static const char *nemo_icon_canvas_item_accessible_action_descriptions[] = { "Open item", "Popup context menu", NULL }; enum { ACTION_OPEN, ACTION_MENU, LAST_ACTION }; typedef struct { char *action_descriptions[LAST_ACTION]; char *image_description; char *description; } NemoIconCanvasItemAccessiblePrivate; typedef struct { NemoIconCanvasItem *item; gint action_number; } NemoIconCanvasItemAccessibleActionContext; static GType nemo_icon_canvas_item_accessible_get_type (void); #define GET_PRIV(o) \ G_TYPE_INSTANCE_GET_PRIVATE(o,\ nemo_icon_canvas_item_accessible_get_type (),\ NemoIconCanvasItemAccessiblePrivate); /* accessible AtkAction interface */ static gboolean nemo_icon_canvas_item_accessible_idle_do_action (gpointer data) { NemoIconCanvasItem *item; NemoIconCanvasItemAccessibleActionContext *ctx; NemoIcon *icon; NemoIconContainer *container; GList* selection; GList file_list; GdkEventButton button_event = { 0 }; gint action_number; container = NEMO_ICON_CONTAINER (data); container->details->a11y_item_action_idle_handler = 0; while (!g_queue_is_empty (container->details->a11y_item_action_queue)) { ctx = g_queue_pop_head (container->details->a11y_item_action_queue); action_number = ctx->action_number; item = ctx->item; g_free (ctx); icon = item->user_data; switch (action_number) { case ACTION_OPEN: file_list.data = icon->data; file_list.next = NULL; file_list.prev = NULL; g_signal_emit_by_name (container, "activate", &file_list); break; case ACTION_MENU: selection = nemo_icon_container_get_selection (container); if (selection == NULL || g_list_length (selection) != 1 || selection->data != icon->data) { g_list_free (selection); return FALSE; } g_list_free (selection); g_signal_emit_by_name (container, "context_click_selection", &button_event); break; default : g_assert_not_reached (); break; } } return FALSE; } static gboolean nemo_icon_canvas_item_accessible_do_action (AtkAction *accessible, int i) { NemoIconCanvasItem *item; NemoIconCanvasItemAccessibleActionContext *ctx; NemoIconContainer *container; g_assert (i < LAST_ACTION); item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { return FALSE; } container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); switch (i) { case ACTION_OPEN: case ACTION_MENU: if (container->details->a11y_item_action_queue == NULL) { container->details->a11y_item_action_queue = g_queue_new (); } ctx = g_new (NemoIconCanvasItemAccessibleActionContext, 1); ctx->action_number = i; ctx->item = item; g_queue_push_head (container->details->a11y_item_action_queue, ctx); if (container->details->a11y_item_action_idle_handler == 0) { container->details->a11y_item_action_idle_handler = g_idle_add (nemo_icon_canvas_item_accessible_idle_do_action, container); } break; default : g_warning ("Invalid action passed to NemoIconCanvasItemAccessible::do_action"); return FALSE; } return TRUE; } static int nemo_icon_canvas_item_accessible_get_n_actions (AtkAction *accessible) { return LAST_ACTION; } static const char * nemo_icon_canvas_item_accessible_action_get_description (AtkAction *accessible, int i) { NemoIconCanvasItemAccessiblePrivate *priv; g_assert (i < LAST_ACTION); priv = GET_PRIV (accessible); if (priv->action_descriptions[i]) { return priv->action_descriptions[i]; } else { return nemo_icon_canvas_item_accessible_action_descriptions[i]; } } static const char * nemo_icon_canvas_item_accessible_action_get_name (AtkAction *accessible, int i) { g_assert (i < LAST_ACTION); return nemo_icon_canvas_item_accessible_action_names[i]; } static const char * nemo_icon_canvas_item_accessible_action_get_keybinding (AtkAction *accessible, int i) { g_assert (i < LAST_ACTION); return NULL; } static gboolean nemo_icon_canvas_item_accessible_action_set_description (AtkAction *accessible, int i, const char *description) { NemoIconCanvasItemAccessiblePrivate *priv; g_assert (i < LAST_ACTION); priv = GET_PRIV (accessible); if (priv->action_descriptions[i]) { g_free (priv->action_descriptions[i]); } priv->action_descriptions[i] = g_strdup (description); return TRUE; } static void nemo_icon_canvas_item_accessible_action_interface_init (AtkActionIface *iface) { iface->do_action = nemo_icon_canvas_item_accessible_do_action; iface->get_n_actions = nemo_icon_canvas_item_accessible_get_n_actions; iface->get_description = nemo_icon_canvas_item_accessible_action_get_description; iface->get_keybinding = nemo_icon_canvas_item_accessible_action_get_keybinding; iface->get_name = nemo_icon_canvas_item_accessible_action_get_name; iface->set_description = nemo_icon_canvas_item_accessible_action_set_description; } static const gchar * nemo_icon_canvas_item_accessible_get_name (AtkObject *accessible) { NemoIconCanvasItem *item; if (accessible->name) { return accessible->name; } item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { return NULL; } return item->details->editable_text; } static const gchar* nemo_icon_canvas_item_accessible_get_description (AtkObject *accessible) { NemoIconCanvasItem *item; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { return NULL; } return item->details->additional_text; } static AtkObject * nemo_icon_canvas_item_accessible_get_parent (AtkObject *accessible) { NemoIconCanvasItem *item; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { return NULL; } return gtk_widget_get_accessible (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas)); } static int nemo_icon_canvas_item_accessible_get_index_in_parent (AtkObject *accessible) { NemoIconCanvasItem *item; NemoIconContainer *container; GList *l; NemoIcon *icon; int i; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { return -1; } container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); l = container->details->icons; i = 0; while (l) { icon = l->data; if (icon->item == item) { return i; } i++; l = l->next; } return -1; } static const gchar * nemo_icon_canvas_item_accessible_get_image_description (AtkImage *image) { NemoIconCanvasItemAccessiblePrivate *priv; NemoIconCanvasItem *item; NemoIcon *icon; NemoIconContainer *container; char *description; priv = GET_PRIV (image); if (priv->image_description) { return priv->image_description; } else { item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image))); if (item == NULL) { return NULL; } icon = item->user_data; container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); description = nemo_icon_container_get_icon_description (container, icon->data); g_free (priv->description); priv->description = description; return priv->description; } } static void nemo_icon_canvas_item_accessible_get_image_size (AtkImage *image, gint *width, gint *height) { NemoIconCanvasItem *item; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image))); get_scaled_icon_size (item, width, height); } static void nemo_icon_canvas_item_accessible_get_image_position (AtkImage *image, gint *x, gint *y, AtkCoordType coord_type) { NemoIconCanvasItem *item; gint x_offset, y_offset, itmp; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image))); if (!item) { return; } if (!item->details->canvas_rect.x0 && !item->details->canvas_rect.x1) { return; } else { x_offset = 0; y_offset = 0; if (item->details->text_width) { itmp = item->details->canvas_rect.x0 - item->details->text_rect.x0; if (itmp > x_offset) { x_offset = itmp; } itmp = item->details->canvas_rect.y0 - item->details->text_rect.y0; if (itmp > y_offset) { y_offset = itmp; } } } atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type); *x += x_offset; *y += y_offset; } static gboolean nemo_icon_canvas_item_accessible_set_image_description (AtkImage *image, const gchar *description) { NemoIconCanvasItemAccessiblePrivate *priv; priv = GET_PRIV (image); g_free (priv->image_description); priv->image_description = g_strdup (description); return TRUE; } static void nemo_icon_canvas_item_accessible_image_interface_init (AtkImageIface *iface) { iface->get_image_description = nemo_icon_canvas_item_accessible_get_image_description; iface->set_image_description = nemo_icon_canvas_item_accessible_set_image_description; iface->get_image_size = nemo_icon_canvas_item_accessible_get_image_size; iface->get_image_position = nemo_icon_canvas_item_accessible_get_image_position; } /* accessible text interface */ static gint nemo_icon_canvas_item_accessible_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { gint real_x, real_y, real_width, real_height; NemoIconCanvasItem *item; gint editable_height; gint offset = 0; gint index; PangoLayout *layout, *editable_layout, *additional_layout; PangoRectangle rect0; char *icon_text; gboolean have_editable; gboolean have_additional; gint text_offset, height; atk_component_get_extents (ATK_COMPONENT (text), &real_x, &real_y, &real_width, &real_height, coords); x -= real_x; y -= real_y; item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); if (item->details->pixbuf) { get_scaled_icon_size (item, NULL, &height); y -= height; } have_editable = item->details->editable_text != NULL && item->details->editable_text[0] != '\0'; have_additional = item->details->additional_text != NULL &&item->details->additional_text[0] != '\0'; editable_layout = NULL; additional_layout = NULL; if (have_editable) { editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text); prepare_pango_layout_for_draw (item, editable_layout); pango_layout_get_pixel_size (editable_layout, NULL, &editable_height); if (y >= editable_height && have_additional) { prepare_pango_layout_for_draw (item, editable_layout); additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text); layout = additional_layout; icon_text = item->details->additional_text; y -= editable_height + LABEL_LINE_SPACING; } else { layout = editable_layout; icon_text = item->details->editable_text; } } else if (have_additional) { additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text); prepare_pango_layout_for_draw (item, additional_layout); layout = additional_layout; icon_text = item->details->additional_text; } else { return 0; } text_offset = 0; if (have_editable) { pango_layout_index_to_pos (editable_layout, 0, &rect0); text_offset = PANGO_PIXELS (rect0.x); } if (have_additional) { gint itmp; pango_layout_index_to_pos (additional_layout, 0, &rect0); itmp = PANGO_PIXELS (rect0.x); if (itmp < text_offset) { text_offset = itmp; } } pango_layout_index_to_pos (layout, 0, &rect0); x += text_offset; if (!pango_layout_xy_to_index (layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, NULL)) { if (x < 0 || y < 0) { index = 0; } else { index = -1; } } if (index == -1) { offset = g_utf8_strlen (icon_text, -1); } else { offset = g_utf8_pointer_to_offset (icon_text, icon_text + index); } if (layout == additional_layout) { offset += g_utf8_strlen (item->details->editable_text, -1); } if (editable_layout != NULL) { g_object_unref (editable_layout); } if (additional_layout != NULL) { g_object_unref (additional_layout); } return offset; } static void nemo_icon_canvas_item_accessible_get_character_extents (AtkText *text, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords) { gint pos_x, pos_y; gint len, byte_offset; gint editable_height; gchar *icon_text; NemoIconCanvasItem *item; PangoLayout *layout, *editable_layout, *additional_layout; PangoRectangle rect; PangoRectangle rect0; gboolean have_editable; gint text_offset, pix_height; atk_component_get_position (ATK_COMPONENT (text), &pos_x, &pos_y, coords); item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); if (item->details->pixbuf) { get_scaled_icon_size (item, NULL, &pix_height); pos_y += pix_height; } have_editable = item->details->editable_text != NULL && item->details->editable_text[0] != '\0'; if (have_editable) { len = g_utf8_strlen (item->details->editable_text, -1); } else { len = 0; } editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text); additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text); if (offset < len) { icon_text = item->details->editable_text; layout = editable_layout; } else { offset -= len; icon_text = item->details->additional_text; layout = additional_layout; pos_y += LABEL_LINE_SPACING; if (have_editable) { pango_layout_get_pixel_size (editable_layout, NULL, &editable_height); pos_y += editable_height; } } byte_offset = g_utf8_offset_to_pointer (icon_text, offset) - icon_text; pango_layout_index_to_pos (layout, byte_offset, &rect); text_offset = 0; if (have_editable) { pango_layout_index_to_pos (editable_layout, 0, &rect0); text_offset = PANGO_PIXELS (rect0.x); } if (item->details->additional_text != NULL && item->details->additional_text[0] != '\0') { gint itmp; pango_layout_index_to_pos (additional_layout, 0, &rect0); itmp = PANGO_PIXELS (rect0.x); if (itmp < text_offset) { text_offset = itmp; } } g_object_unref (editable_layout); g_object_unref (additional_layout); *x = pos_x + PANGO_PIXELS (rect.x) - text_offset; *y = pos_y + PANGO_PIXELS (rect.y); *width = PANGO_PIXELS (rect.width); *height = PANGO_PIXELS (rect.height); } static void nemo_icon_canvas_item_accessible_text_interface_init (AtkTextIface *iface) { iface->get_text = eel_accessibility_text_get_text; iface->get_character_at_offset = eel_accessibility_text_get_character_at_offset; iface->get_text_before_offset = eel_accessibility_text_get_text_before_offset; iface->get_text_at_offset = eel_accessibility_text_get_text_at_offset; iface->get_text_after_offset = eel_accessibility_text_get_text_after_offset; iface->get_character_count = eel_accessibility_text_get_character_count; iface->get_character_extents = nemo_icon_canvas_item_accessible_get_character_extents; iface->get_offset_at_point = nemo_icon_canvas_item_accessible_get_offset_at_point; } typedef struct { AtkGObjectAccessible parent; } NemoIconCanvasItemAccessible; typedef struct { AtkGObjectAccessibleClass parent_class; } NemoIconCanvasItemAccessibleClass; G_DEFINE_TYPE_WITH_CODE (NemoIconCanvasItemAccessible, nemo_icon_canvas_item_accessible, ATK_TYPE_GOBJECT_ACCESSIBLE, G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, nemo_icon_canvas_item_accessible_image_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, nemo_icon_canvas_item_accessible_text_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, nemo_icon_canvas_item_accessible_action_interface_init)); static AtkStateSet* nemo_icon_canvas_item_accessible_ref_state_set (AtkObject *accessible) { AtkStateSet *state_set; NemoIconCanvasItem *item; NemoIconContainer *container; NemoIcon *icon; GList *l; gboolean one_item_selected; state_set = ATK_OBJECT_CLASS (nemo_icon_canvas_item_accessible_parent_class)->ref_state_set (accessible); item = NEMO_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); if (!item) { atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); return state_set; } container = NEMO_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); if (item->details->is_highlighted_as_keyboard_focus) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } else if (!container->details->keyboard_focus) { one_item_selected = FALSE; l = container->details->icons; while (l) { icon = l->data; if (icon->item == item) { if (icon->is_selected) { one_item_selected = TRUE; } else { break; } } else if (icon->is_selected) { one_item_selected = FALSE; break; } l = l->next; } if (one_item_selected) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } } return state_set; } static void nemo_icon_canvas_item_accessible_finalize (GObject *object) { NemoIconCanvasItemAccessiblePrivate *priv; int i; priv = GET_PRIV (object); for (i = 0; i < LAST_ACTION; i++) { g_free (priv->action_descriptions[i]); } g_free (priv->image_description); g_free (priv->description); G_OBJECT_CLASS (nemo_icon_canvas_item_accessible_parent_class)->finalize (object); } static void nemo_icon_canvas_item_accessible_initialize (AtkObject *accessible, gpointer widget) { ATK_OBJECT_CLASS (nemo_icon_canvas_item_accessible_parent_class)->initialize (accessible, widget); atk_object_set_role (accessible, ATK_ROLE_ICON); } static void nemo_icon_canvas_item_accessible_class_init (NemoIconCanvasItemAccessibleClass *klass) { AtkObjectClass *aclass = ATK_OBJECT_CLASS (klass); GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_icon_canvas_item_accessible_finalize; aclass->initialize = nemo_icon_canvas_item_accessible_initialize; aclass->get_name = nemo_icon_canvas_item_accessible_get_name; aclass->get_description = nemo_icon_canvas_item_accessible_get_description; aclass->get_parent = nemo_icon_canvas_item_accessible_get_parent; aclass->get_index_in_parent = nemo_icon_canvas_item_accessible_get_index_in_parent; aclass->ref_state_set = nemo_icon_canvas_item_accessible_ref_state_set; g_type_class_add_private (klass, sizeof (NemoIconCanvasItemAccessiblePrivate)); } static void nemo_icon_canvas_item_accessible_init (NemoIconCanvasItemAccessible *self) { } /* dummy typedef */ typedef AtkObjectFactory NemoIconCanvasItemAccessibleFactory; typedef AtkObjectFactoryClass NemoIconCanvasItemAccessibleFactoryClass; G_DEFINE_TYPE (NemoIconCanvasItemAccessibleFactory, nemo_icon_canvas_item_accessible_factory, ATK_TYPE_OBJECT_FACTORY); static AtkObject * nemo_icon_canvas_item_accessible_factory_create_accessible (GObject *for_object) { AtkObject *accessible; NemoIconCanvasItem *item; GString *item_text; item = NEMO_ICON_CANVAS_ITEM (for_object); g_assert (item != NULL); item_text = g_string_new (NULL); if (item->details->editable_text) { g_string_append (item_text, item->details->editable_text); } if (item->details->additional_text) { g_string_append (item_text, item->details->additional_text); } item->details->text_util = gail_text_util_new (); gail_text_util_text_setup (item->details->text_util, item_text->str); g_string_free (item_text, TRUE); accessible = g_object_new (nemo_icon_canvas_item_accessible_get_type (), NULL); atk_object_initialize (accessible, for_object); return accessible; } static GType nemo_icon_canvas_item_accessible_factory_get_accessible_type (void) { return nemo_icon_canvas_item_accessible_get_type (); } static void nemo_icon_canvas_item_accessible_factory_init (NemoIconCanvasItemAccessibleFactory *self) { } static void nemo_icon_canvas_item_accessible_factory_class_init (NemoIconCanvasItemAccessibleFactoryClass *klass) { klass->create_accessible = nemo_icon_canvas_item_accessible_factory_create_accessible; klass->get_accessible_type = nemo_icon_canvas_item_accessible_factory_get_accessible_type; } nemo-4.4.2/libnemo-private/nemo-icon-canvas-item.h000066400000000000000000000120221357442400300220150ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Icon canvas item class for icon container. * * Copyright (C) 2000 Eazel, Inc. * * Author: Andy Hertzfeld * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_ICON_CANVAS_ITEM_H #define NEMO_ICON_CANVAS_ITEM_H #include #include G_BEGIN_DECLS #define NEMO_TYPE_ICON_CANVAS_ITEM nemo_icon_canvas_item_get_type() #define NEMO_ICON_CANVAS_ITEM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ICON_CANVAS_ITEM, NemoIconCanvasItem)) #define NEMO_ICON_CANVAS_ITEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ICON_CANVAS_ITEM, NemoIconCanvasItemClass)) #define NEMO_IS_ICON_CANVAS_ITEM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ICON_CANVAS_ITEM)) #define NEMO_IS_ICON_CANVAS_ITEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ICON_CANVAS_ITEM)) #define NEMO_ICON_CANVAS_ITEM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ICON_CANVAS_ITEM, NemoIconCanvasItemClass)) typedef struct NemoIconCanvasItem NemoIconCanvasItem; typedef struct NemoIconCanvasItemClass NemoIconCanvasItemClass; typedef struct NemoIconCanvasItemDetails NemoIconCanvasItemDetails; struct NemoIconCanvasItem { EelCanvasItem item; NemoIconCanvasItemDetails *details; gpointer user_data; }; struct NemoIconCanvasItemClass { EelCanvasItemClass parent_class; }; /* not namespaced due to their length */ typedef enum { BOUNDS_USAGE_FOR_LAYOUT, BOUNDS_USAGE_FOR_ENTIRE_ITEM, BOUNDS_USAGE_FOR_DISPLAY } NemoIconCanvasItemBoundsUsage; /* GObject */ GType nemo_icon_canvas_item_get_type (void); /* attributes */ void nemo_icon_canvas_item_set_image (NemoIconCanvasItem *item, GdkPixbuf *image); cairo_surface_t* nemo_icon_canvas_item_get_drag_surface (NemoIconCanvasItem *item); void nemo_icon_canvas_item_set_emblems (NemoIconCanvasItem *item, GList *emblem_pixbufs); void nemo_icon_canvas_item_set_show_stretch_handles (NemoIconCanvasItem *item, gboolean show_stretch_handles); double nemo_icon_canvas_item_get_max_text_width (NemoIconCanvasItem *item); const char *nemo_icon_canvas_item_get_editable_text (NemoIconCanvasItem *icon_item); void nemo_icon_canvas_item_set_renaming (NemoIconCanvasItem *icon_item, gboolean state); /* geometry and hit testing */ gboolean nemo_icon_canvas_item_hit_test_rectangle (NemoIconCanvasItem *item, EelIRect canvas_rect); gboolean nemo_icon_canvas_item_hit_test_stretch_handles (NemoIconCanvasItem *item, gdouble world_x, gdouble world_y, GtkCornerType *corner); void nemo_icon_canvas_item_invalidate_label (NemoIconCanvasItem *item); void nemo_icon_canvas_item_invalidate_label_size (NemoIconCanvasItem *item); EelDRect nemo_icon_canvas_item_get_icon_rectangle (const NemoIconCanvasItem *item); EelDRect nemo_icon_canvas_item_get_text_rectangle (NemoIconCanvasItem *item, gboolean for_layout); void nemo_icon_canvas_item_get_icon_canvas_rectangle (NemoIconCanvasItem *item, EelIRect *rect); void nemo_icon_canvas_item_get_bounds_for_layout (NemoIconCanvasItem *item, double *x1, double *y1, double *x2, double *y2); void nemo_icon_canvas_item_get_bounds_for_entire_item (NemoIconCanvasItem *item, double *x1, double *y1, double *x2, double *y2); void nemo_icon_canvas_item_update_bounds (NemoIconCanvasItem *item, double i2w_dx, double i2w_dy); void nemo_icon_canvas_item_set_is_visible (NemoIconCanvasItem *item, gboolean visible); /* whether the entire label text must be visible at all times */ void nemo_icon_canvas_item_set_entire_text (NemoIconCanvasItem *icon_item, gboolean entire_text); G_END_DECLS #endif /* NEMO_ICON_CANVAS_ITEM_H */ nemo-4.4.2/libnemo-private/nemo-icon-container.c000066400000000000000000006626721357442400300216110ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-icon-container.c - Icon container widget. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000, 2001 Eazel, Inc. Copyright (C) 2002, 2003 Red Hat, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ettore Perazzoli , Darin Adler */ #include #include #include "nemo-icon-container.h" #include "nemo-file.h" #include "nemo-desktop-icon-file.h" #include "nemo-global-preferences.h" #include "nemo-icon-private.h" #include "nemo-lib-self-check-functions.h" #include "nemo-selection-canvas-item.h" #include "nemo-desktop-utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_ICON_CONTAINER #include "nemo-debug.h" #define TAB_NAVIGATION_DISABLED /* Interval for updating the rubberband selection, in milliseconds. */ #define RUBBERBAND_TIMEOUT_INTERVAL 10 #define RUBBERBAND_SCROLL_THRESHOLD 5 /* Timeout for making the icon currently selected for keyboard operation visible. * If this is 0, you can get into trouble with extra scrolling after holding * down the arrow key for awhile when there are many items. */ #define KEYBOARD_ICON_REVEAL_TIMEOUT 10 /* Maximum amount of milliseconds the mouse button is allowed to stay down * and still be considered a click. */ #define MAX_CLICK_TIME 1500 /* Button assignments. */ #define DRAG_BUTTON 1 #define RUBBERBAND_BUTTON 1 #define MIDDLE_BUTTON 2 #define CONTEXTUAL_MENU_BUTTON 3 #define DRAG_MENU_BUTTON 2 /* Copied from NemoIconContainer */ #define NEMO_ICON_CONTAINER_SEARCH_DIALOG_TIMEOUT 5 /* Copied from NemoFile */ #define UNDEFINED_TIME ((time_t) (-1)) enum { ACTION_ACTIVATE, ACTION_MENU, LAST_ACTION }; typedef struct { GList *selection; char *action_descriptions[LAST_ACTION]; } NemoIconContainerAccessiblePrivate; static GType nemo_icon_container_accessible_get_type (void); static void preview_selected_items (NemoIconContainer *container); static void activate_selected_items (NemoIconContainer *container); static void activate_selected_items_alternate (NemoIconContainer *container, NemoIcon *icon); static void compute_stretch (StretchState *start, StretchState *current); static NemoIcon *get_first_selected_icon (NemoIconContainer *container); static NemoIcon *get_nth_selected_icon (NemoIconContainer *container, int index); static gboolean has_multiple_selection (NemoIconContainer *container); static gboolean all_selected (NemoIconContainer *container); static gboolean has_selection (NemoIconContainer *container); static void icon_destroy (NemoIconContainer *container, NemoIcon *icon); static gboolean is_renaming (NemoIconContainer *container); static gboolean is_renaming_pending (NemoIconContainer *container); static void process_pending_icon_to_rename (NemoIconContainer *container); static void handle_hadjustment_changed (GtkAdjustment *adjustment, NemoIconContainer *container); static void handle_vadjustment_changed (GtkAdjustment *adjustment, NemoIconContainer *container); static GList * nemo_icon_container_get_selected_icons (NemoIconContainer *container); static void nemo_icon_container_update_visible_icons (NemoIconContainer *container); static void reveal_icon (NemoIconContainer *container, NemoIcon *icon); static void text_ellipsis_limit_changed_container_callback (gpointer callback_data); static int compare_icons_horizontal (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b); static int compare_icons_vertical (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b); static void remove_search_entry_timeout (NemoIconContainer *container); static gboolean handle_icon_slow_two_click (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event); static void schedule_align_icons (NemoIconContainer *container); static gpointer accessible_parent_class; static GQuark accessible_private_data_quark = 0; static const char *nemo_icon_container_accessible_action_names[] = { "activate", "menu", NULL }; static const char *nemo_icon_container_accessible_action_descriptions[] = { "Activate selected items", "Popup context menu", NULL }; G_DEFINE_TYPE (NemoIconContainer, nemo_icon_container, EEL_TYPE_CANVAS); /* The NemoIconContainer signals. */ enum { ACTIVATE, ACTIVATE_ALTERNATE, ACTIVATE_PREVIEWER, BAND_SELECT_STARTED, BAND_SELECT_ENDED, BUTTON_PRESS, CAN_ACCEPT_ITEM, CONTEXT_CLICK_BACKGROUND, CONTEXT_CLICK_SELECTION, MIDDLE_CLICK, GET_CONTAINER_URI, GET_ICON_URI, GET_ICON_DROP_TARGET_URI, ICON_POSITION_CHANGED, GET_STORED_LAYOUT_TIMESTAMP, STORE_LAYOUT_TIMESTAMP, ICON_RENAME_STARTED, ICON_RENAME_ENDED, ICON_STRETCH_STARTED, ICON_STRETCH_ENDED, LAYOUT_CHANGED, MOVE_COPY_ITEMS, HANDLE_NETSCAPE_URL, HANDLE_URI_LIST, HANDLE_TEXT, HANDLE_RAW, SELECTION_CHANGED, ICON_ADDED, ICON_REMOVED, CLEARED, GET_TOOLTIP_TEXT, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void tooltip_prefs_changed_callback (NemoIconContainer *container) { container->details->show_desktop_tooltips = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIPS_DESKTOP); container->details->show_icon_view_tooltips = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIPS_ICON_VIEW); container->details->tooltip_flags = nemo_global_preferences_get_tooltip_flags (); nemo_icon_container_request_update_all (container); } /* Functions dealing with NemoIcons. */ static gboolean clicked_on_text (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { if (icon == NULL) return FALSE; double eventX, eventY; EelDRect icon_rect; icon_rect = nemo_icon_canvas_item_get_text_rectangle (icon->item, TRUE); eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &eventX, &eventY); gboolean ret = (eventX > icon_rect.x0) && (eventX < icon_rect.x1) && (eventY > icon_rect.y0) && (eventY < icon_rect.y1); return ret; } static gboolean clicked_on_icon (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { if (icon == NULL) return FALSE; double eventX, eventY; EelDRect icon_rect; icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &eventX, &eventY); gboolean ret = (eventX > icon_rect.x0) && (eventX < icon_rect.x1) && (eventY > icon_rect.y0) && (eventY < icon_rect.y1); return ret; } static void icon_free (NemoIcon *icon) { /* Destroy this canvas item; the parent will unref it. */ eel_canvas_item_destroy (EEL_CANVAS_ITEM (icon->item)); g_free (icon); } gboolean nemo_icon_container_icon_is_positioned (const NemoIcon *icon) { return icon->x != ICON_UNPOSITIONED_VALUE && icon->y != ICON_UNPOSITIONED_VALUE; } static void icon_get_size (NemoIconContainer *container, NemoIcon *icon, guint *size) { if (size != NULL) { *size = MAX (nemo_get_icon_size_for_zoom_level (container->details->zoom_level) * icon->scale, NEMO_ICON_SIZE_SMALLEST); } } /* The icon_set_size function is used by the stretching user * interface, which currently stretches in a way that keeps the aspect * ratio. Later we might have a stretching interface that stretches Y * separate from X and we will change this around. */ static void icon_set_size (NemoIconContainer *container, NemoIcon *icon, guint icon_size, gboolean snap, gboolean update_position) { guint old_size; double scale; icon_get_size (container, icon, &old_size); if (icon_size == old_size) { return; } scale = (double) icon_size / nemo_get_icon_size_for_zoom_level (container->details->zoom_level); nemo_icon_container_move_icon (container, icon, icon->x, icon->y, scale, FALSE, snap, update_position); } static void emit_stretch_started (NemoIconContainer *container, NemoIcon *icon) { g_signal_emit (container, signals[ICON_STRETCH_STARTED], 0, icon->data); } static void emit_stretch_ended (NemoIconContainer *container, NemoIcon *icon) { g_signal_emit (container, signals[ICON_STRETCH_ENDED], 0, icon->data); } static void icon_toggle_selected (NemoIconContainer *container, NemoIcon *icon) { nemo_icon_container_end_renaming_mode (container, TRUE); icon->is_selected = !icon->is_selected; eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item), "highlighted_for_selection", (gboolean) icon->is_selected, NULL); /* If the icon is deselected, then get rid of the stretch handles. * No harm in doing the same if the item is newly selected. */ if (icon == container->details->stretch_icon) { container->details->stretch_icon = NULL; nemo_icon_canvas_item_set_show_stretch_handles (icon->item, FALSE); /* snap the icon if necessary */ if (container->details->keep_aligned) { nemo_icon_container_move_icon (container, icon, icon->x, icon->y, icon->scale, FALSE, TRUE, TRUE); } emit_stretch_ended (container, icon); } /* Raise each newly-selected icon to the front as it is selected. */ if (icon->is_selected) { nemo_icon_container_icon_raise (container, icon); } } /* Select an icon. Return TRUE if selection has changed. */ static gboolean icon_set_selected (NemoIconContainer *container, NemoIcon *icon, gboolean select) { g_assert (select == FALSE || select == TRUE); g_assert (icon->is_selected == FALSE || icon->is_selected == TRUE); if (select == icon->is_selected) { return FALSE; } icon_toggle_selected (container, icon); g_assert (select == icon->is_selected); return TRUE; } /* Utility functions for NemoIconContainer. */ gboolean nemo_icon_container_scroll (NemoIconContainer *container, int delta_x, int delta_y) { GtkAdjustment *hadj, *vadj; int old_h_value, old_v_value; hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)); /* Store the old ajustment values so we can tell if we * ended up actually scrolling. We may not have in a case * where the resulting value got pinned to the adjustment * min or max. */ old_h_value = gtk_adjustment_get_value (hadj); old_v_value = gtk_adjustment_get_value (vadj); gtk_adjustment_set_value (hadj, gtk_adjustment_get_value (hadj) + delta_x); gtk_adjustment_set_value (vadj, gtk_adjustment_get_value (vadj) + delta_y); /* return TRUE if we did scroll */ return gtk_adjustment_get_value (hadj) != old_h_value || gtk_adjustment_get_value (vadj) != old_v_value; } static void pending_icon_to_reveal_destroy_callback (NemoIconCanvasItem *item, NemoIconContainer *container) { g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (container->details->pending_icon_to_reveal != NULL); g_assert (container->details->pending_icon_to_reveal->item == item); container->details->pending_icon_to_reveal = NULL; } static NemoIcon* get_pending_icon_to_reveal (NemoIconContainer *container) { return container->details->pending_icon_to_reveal; } static void set_pending_icon_to_reveal (NemoIconContainer *container, NemoIcon *icon) { NemoIcon *old_icon; old_icon = container->details->pending_icon_to_reveal; if (icon == old_icon) { return; } if (old_icon != NULL) { g_signal_handlers_disconnect_by_func (old_icon->item, G_CALLBACK (pending_icon_to_reveal_destroy_callback), container); } if (icon != NULL) { g_signal_connect (icon->item, "destroy", G_CALLBACK (pending_icon_to_reveal_destroy_callback), container); } container->details->pending_icon_to_reveal = icon; } static void item_get_canvas_bounds (NemoIconContainer *container, EelCanvasItem *item, EelIRect *bounds, gboolean safety_pad) { EelDRect world_rect; eel_canvas_item_get_bounds (item, &world_rect.x0, &world_rect.y0, &world_rect.x1, &world_rect.y1); eel_canvas_item_i2w (item->parent, &world_rect.x0, &world_rect.y0); eel_canvas_item_i2w (item->parent, &world_rect.x1, &world_rect.y1); if (safety_pad) { world_rect.x0 -= GET_VIEW_CONSTANT (container, icon_pad_left) + GET_VIEW_CONSTANT (container, icon_pad_right); world_rect.x1 += GET_VIEW_CONSTANT (container, icon_pad_left) + GET_VIEW_CONSTANT (container, icon_pad_right); world_rect.y0 -= GET_VIEW_CONSTANT (container, icon_pad_top) + GET_VIEW_CONSTANT (container, icon_pad_bottom); world_rect.y1 += GET_VIEW_CONSTANT (container, icon_pad_top) + GET_VIEW_CONSTANT (container, icon_pad_bottom); } eel_canvas_w2c (item->canvas, world_rect.x0, world_rect.y0, &bounds->x0, &bounds->y0); eel_canvas_w2c (item->canvas, world_rect.x1, world_rect.y1, &bounds->x1, &bounds->y1); } static void icon_get_row_and_column_bounds (NemoIconContainer *container, NemoIcon *icon, EelIRect *bounds, gboolean safety_pad) { GList *p; NemoIcon *one_icon; EelIRect one_bounds; item_get_canvas_bounds (container, EEL_CANVAS_ITEM (icon->item), bounds, safety_pad); for (p = container->details->icons; p != NULL; p = p->next) { one_icon = p->data; if (icon == one_icon) { continue; } if (compare_icons_horizontal (container, icon, one_icon) == 0) { item_get_canvas_bounds (container, EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad); bounds->x0 = MIN (bounds->x0, one_bounds.x0); bounds->x1 = MAX (bounds->x1, one_bounds.x1); } if (compare_icons_vertical (container, icon, one_icon) == 0) { item_get_canvas_bounds (container, EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad); bounds->y0 = MIN (bounds->y0, one_bounds.y0); bounds->y1 = MAX (bounds->y1, one_bounds.y1); } } } static void reveal_icon (NemoIconContainer *container, NemoIcon *icon) { GtkAllocation allocation; GtkAdjustment *hadj, *vadj; EelIRect bounds; if (!nemo_icon_container_icon_is_positioned (icon)) { set_pending_icon_to_reveal (container, icon); return; } set_pending_icon_to_reveal (container, NULL); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)); if (nemo_icon_container_is_auto_layout (container)) { /* ensure that we reveal the entire row/column */ icon_get_row_and_column_bounds (container, icon, &bounds, TRUE); } else { item_get_canvas_bounds (container, EEL_CANVAS_ITEM (icon->item), &bounds, TRUE); } if (bounds.y0 < gtk_adjustment_get_value (vadj)) { gtk_adjustment_set_value (vadj, bounds.y0); } else if (bounds.y1 > gtk_adjustment_get_value (vadj) + allocation.height) { gtk_adjustment_set_value (vadj, bounds.y1 - allocation.height); } if (bounds.x0 < gtk_adjustment_get_value (hadj)) { gtk_adjustment_set_value (hadj, bounds.x0); } else if (bounds.x1 > gtk_adjustment_get_value (hadj) + allocation.width) { if (bounds.x1 - allocation.width > bounds.x0) { gtk_adjustment_set_value (hadj, bounds.x0); } else { gtk_adjustment_set_value (hadj, bounds.x1 - allocation.width); } } } static void process_pending_icon_to_reveal (NemoIconContainer *container) { NemoIcon *pending_icon_to_reveal; pending_icon_to_reveal = get_pending_icon_to_reveal (container); if (pending_icon_to_reveal != NULL) { reveal_icon (container, pending_icon_to_reveal); } } static gboolean keyboard_icon_reveal_timeout_callback (gpointer data) { NemoIconContainer *container; NemoIcon *icon; container = NEMO_ICON_CONTAINER (data); icon = container->details->keyboard_icon_to_reveal; g_assert (icon != NULL); /* Only reveal the icon if it's still the keyboard focus or if * it's still selected. Someone originally thought we should * cancel this reveal if the user manages to sneak a direct * scroll in before the timeout fires, but we later realized * this wouldn't actually be an improvement * (see bugzilla.gnome.org 40612). */ if (icon == container->details->keyboard_focus || icon->is_selected) { reveal_icon (container, icon); } container->details->keyboard_icon_reveal_timer_id = 0; return FALSE; } static void unschedule_keyboard_icon_reveal (NemoIconContainer *container) { NemoIconContainerDetails *details; details = container->details; if (details->keyboard_icon_reveal_timer_id != 0) { g_source_remove (details->keyboard_icon_reveal_timer_id); } } static void schedule_keyboard_icon_reveal (NemoIconContainer *container, NemoIcon *icon) { NemoIconContainerDetails *details; details = container->details; unschedule_keyboard_icon_reveal (container); details->keyboard_icon_to_reveal = icon; details->keyboard_icon_reveal_timer_id = g_timeout_add (KEYBOARD_ICON_REVEAL_TIMEOUT, keyboard_icon_reveal_timeout_callback, container); } static void clear_keyboard_focus (NemoIconContainer *container) { if (container->details->keyboard_focus != NULL) { eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item), "highlighted_as_keyboard_focus", 0, NULL); } container->details->keyboard_focus = NULL; } inline static void emit_atk_focus_tracker_notify (NemoIcon *icon) { AtkObject *atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item)); atk_focus_tracker_notify (atk_object); } /* Set @icon as the icon currently selected for keyboard operations. */ static void set_keyboard_focus (NemoIconContainer *container, NemoIcon *icon) { g_assert (icon != NULL); if (icon == container->details->keyboard_focus) { return; } clear_keyboard_focus (container); container->details->keyboard_focus = icon; eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item), "highlighted_as_keyboard_focus", 1, NULL); emit_atk_focus_tracker_notify (icon); } static void set_keyboard_rubberband_start (NemoIconContainer *container, NemoIcon *icon) { container->details->keyboard_rubberband_start = icon; } static void clear_keyboard_rubberband_start (NemoIconContainer *container) { container->details->keyboard_rubberband_start = NULL; } /* carbon-copy of eel_canvas_group_bounds(), but * for NemoIconContainerItems it returns the * bounds for the “entire itemâ€. */ static void get_icon_bounds_for_canvas_bounds (EelCanvasGroup *group, double *x1, double *y1, double *x2, double *y2, NemoIconCanvasItemBoundsUsage usage) { EelCanvasItem *child; GList *list; double tx1, ty1, tx2, ty2; double minx, miny, maxx, maxy; int set; /* Get the bounds of the first visible item */ child = NULL; /* Unnecessary but eliminates a warning. */ set = FALSE; for (list = group->item_list; list; list = list->next) { child = list->data; if (!NEMO_IS_ICON_CANVAS_ITEM (child)) { continue; } if (child->flags & EEL_CANVAS_ITEM_VISIBLE) { set = TRUE; if (!NEMO_IS_ICON_CANVAS_ITEM (child) || usage == BOUNDS_USAGE_FOR_DISPLAY) { eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy); } else if (usage == BOUNDS_USAGE_FOR_LAYOUT) { nemo_icon_canvas_item_get_bounds_for_layout (NEMO_ICON_CANVAS_ITEM (child), &minx, &miny, &maxx, &maxy); } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { nemo_icon_canvas_item_get_bounds_for_entire_item (NEMO_ICON_CANVAS_ITEM (child), &minx, &miny, &maxx, &maxy); } else { g_assert_not_reached (); } break; } } /* If there were no visible items, return an empty bounding box */ if (!set) { *x1 = *y1 = *x2 = *y2 = 0.0; return; } /* Now we can grow the bounds using the rest of the items */ list = list->next; for (; list; list = list->next) { child = list->data; if (!NEMO_IS_ICON_CANVAS_ITEM (child)) { continue; } if (!(child->flags & EEL_CANVAS_ITEM_VISIBLE)) continue; if (!NEMO_IS_ICON_CANVAS_ITEM (child) || usage == BOUNDS_USAGE_FOR_DISPLAY) { eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2); } else if (usage == BOUNDS_USAGE_FOR_LAYOUT) { nemo_icon_canvas_item_get_bounds_for_layout (NEMO_ICON_CANVAS_ITEM (child), &tx1, &ty1, &tx2, &ty2); } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { nemo_icon_canvas_item_get_bounds_for_entire_item (NEMO_ICON_CANVAS_ITEM (child), &tx1, &ty1, &tx2, &ty2); } else { g_assert_not_reached (); } if (tx1 < minx) minx = tx1; if (ty1 < miny) miny = ty1; if (tx2 > maxx) maxx = tx2; if (ty2 > maxy) maxy = ty2; } /* Make the bounds be relative to our parent's coordinate system */ if (EEL_CANVAS_ITEM (group)->parent) { minx += group->xpos; miny += group->ypos; maxx += group->xpos; maxy += group->ypos; } if (x1 != NULL) { *x1 = minx; } if (y1 != NULL) { *y1 = miny; } if (x2 != NULL) { *x2 = maxx; } if (y2 != NULL) { *y2 = maxy; } } void nemo_icon_container_get_all_icon_bounds (NemoIconContainer *container, double *x1, double *y1, double *x2, double *y2, NemoIconCanvasItemBoundsUsage usage) { /* FIXME bugzilla.gnome.org 42477: Do we have to do something about the rubberband * here? Any other non-icon items? */ get_icon_bounds_for_canvas_bounds (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root), x1, y1, x2, y2, usage); } /* Don't preserve visible white space the next time the scroll region * is recomputed when the container is not empty. */ void nemo_icon_container_reset_scroll_region (NemoIconContainer *container) { container->details->reset_scroll_region_trigger = TRUE; } /* Set a new scroll region without eliminating any of the currently-visible area. */ static void canvas_set_scroll_region_include_visible_area (EelCanvas *canvas, double x1, double y1, double x2, double y2) { double old_x1, old_y1, old_x2, old_y2; double old_scroll_x, old_scroll_y; double height, width; GtkAllocation allocation; eel_canvas_get_scroll_region (canvas, &old_x1, &old_y1, &old_x2, &old_y2); gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation); width = (allocation.width) / canvas->pixels_per_unit; height = (allocation.height) / canvas->pixels_per_unit; old_scroll_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas))); old_scroll_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas))); x1 = MIN (x1, old_x1 + old_scroll_x); y1 = MIN (y1, old_y1 + old_scroll_y); x2 = MAX (x2, old_x1 + old_scroll_x + width); y2 = MAX (y2, old_y1 + old_scroll_y + height); eel_canvas_set_scroll_region (canvas, x1, y1, x2, y2); } void nemo_icon_container_update_scroll_region (NemoIconContainer *container) { double x1, y1, x2, y2; double pixels_per_unit; GtkAdjustment *hadj, *vadj; float step_increment; gboolean reset_scroll_region; GtkAllocation allocation; pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit; if (nemo_icon_container_get_is_fixed_size (container)) { /* Set the scroll region to the size of the container allocation */ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); eel_canvas_set_scroll_region (EEL_CANVAS (container), (double) - container->details->left_margin / pixels_per_unit, (double) - container->details->top_margin / pixels_per_unit, ((double) (allocation.width - 1) - container->details->left_margin - container->details->right_margin) / pixels_per_unit, ((double) (allocation.height - 1) - container->details->top_margin - container->details->bottom_margin) / pixels_per_unit); return; } reset_scroll_region = container->details->reset_scroll_region_trigger || nemo_icon_container_is_empty (container) || nemo_icon_container_is_auto_layout (container); /* The trigger is only cleared when container is non-empty, so * callers can reliably reset the scroll region when an item * is added even if extraneous relayouts are called when the * window is still empty. */ if (!nemo_icon_container_is_empty (container)) { container->details->reset_scroll_region_trigger = FALSE; } nemo_icon_container_get_all_icon_bounds (container, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM); /* Add border at the "end"of the layout (i.e. after the icons), to * ensure we get some space when scrolled to the end. * For horizontal layouts, we add a bottom border. * Vertical layout is used by the compact view so the end * depends on the RTL setting. */ if (nemo_icon_container_is_layout_vertical (container)) { if (nemo_icon_container_is_layout_rtl (container)) { x1 -= GET_VIEW_CONSTANT (container, icon_pad_left) + GET_VIEW_CONSTANT (container, container_pad_left); } else { x2 += GET_VIEW_CONSTANT (container, icon_pad_right) + GET_VIEW_CONSTANT (container, container_pad_right); } } else { y2 += GET_VIEW_CONSTANT (container, icon_pad_bottom) + GET_VIEW_CONSTANT (container, container_pad_bottom); } /* Auto-layout assumes a 0, 0 scroll origin and at least allocation->width. * Then we lay out to the right or to the left, so * x can be < 0 and > allocation */ if (nemo_icon_container_is_auto_layout (container)) { gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); x1 = MIN (x1, 0); x2 = MAX (x2, allocation.width / pixels_per_unit); y1 = 0; } else { /* Otherwise we add the padding that is at the start of the layout */ if (nemo_icon_container_is_layout_rtl (container)) { x2 += GET_VIEW_CONSTANT (container, icon_pad_right) + GET_VIEW_CONSTANT (container, container_pad_right); } else { x1 -= GET_VIEW_CONSTANT (container, icon_pad_left) + GET_VIEW_CONSTANT (container, container_pad_left); } y1 -= GET_VIEW_CONSTANT (container, icon_pad_top) + GET_VIEW_CONSTANT (container, container_pad_top); } x2 -= 1; x2 = MAX(x1, x2); y2 -= 1; y2 = MAX(y1, y2); if (reset_scroll_region) { eel_canvas_set_scroll_region (EEL_CANVAS (container), x1, y1, x2, y2); } else { canvas_set_scroll_region_include_visible_area (EEL_CANVAS (container), x1, y1, x2, y2); } hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)); /* Scroll by 1/4 icon each time you click. */ step_increment = nemo_get_icon_size_for_zoom_level (container->details->zoom_level) / 4; if (gtk_adjustment_get_step_increment (hadj) != step_increment) { gtk_adjustment_set_step_increment (hadj, step_increment); } if (gtk_adjustment_get_step_increment (vadj) != step_increment) { gtk_adjustment_set_step_increment (vadj, step_increment); } } static int compare_icons (gconstpointer a, gconstpointer b, gpointer icon_container) { NemoIconContainerClass *klass; const NemoIcon *icon_a, *icon_b; icon_a = a; icon_b = b; klass = NEMO_ICON_CONTAINER_GET_CLASS (icon_container); return klass->compare_icons (icon_container, icon_a->data, icon_b->data); } static void align_icons (NemoIconContainer *container) { NEMO_ICON_CONTAINER_GET_CLASS (container)->align_icons (container); } static void redo_layout_internal (NemoIconContainer *container) { if (NEMO_ICON_CONTAINER_GET_CLASS (container)->finish_adding_new_icons != NULL) { NEMO_ICON_CONTAINER_GET_CLASS (container)->finish_adding_new_icons (container); } /* Don't do any re-laying-out during stretching. Later we * might add smart logic that does this and leaves room for * the stretched icon, but if we do it we want it to be fast * and only re-lay-out when it's really needed. */ if (container->details->auto_layout && container->details->drag_state != DRAG_STATE_STRETCH) { if (container->details->needs_resort) { nemo_icon_container_resort (container); container->details->needs_resort = FALSE; } NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, container->details->icons, 0); } if (nemo_icon_container_is_layout_rtl (container)) { nemo_icon_container_set_rtl_positions (container); } nemo_icon_container_update_scroll_region (container); process_pending_icon_to_reveal (container); process_pending_icon_to_rename (container); nemo_icon_container_update_visible_icons (container); } static gboolean redo_layout_callback (gpointer callback_data) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (callback_data); redo_layout_internal (container); container->details->idle_id = 0; return FALSE; } static void unschedule_redo_layout (NemoIconContainer *container) { if (container->details->idle_id != 0) { g_source_remove (container->details->idle_id); container->details->idle_id = 0; } } static void schedule_redo_layout (NemoIconContainer *container) { if (container->details->idle_id == 0 && container->details->has_been_allocated) { container->details->idle_id = g_idle_add (redo_layout_callback, container); } } void nemo_icon_container_redo_layout (NemoIconContainer *container) { unschedule_redo_layout (container); redo_layout_internal (container); } static void reload_icon_positions (NemoIconContainer *container) { NEMO_ICON_CONTAINER_GET_CLASS (container)->reload_icon_positions (container); } /* Container-level icon handling functions. */ static gboolean button_event_modifies_selection (GdkEventButton *event) { return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0; } /* invalidate the cached label sizes for all the icons */ static void invalidate_label_sizes (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_canvas_item_invalidate_label_size (icon->item); } } static void update_icons (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_container_update_icon (container, icon); } } static gboolean select_range (NemoIconContainer *container, NemoIcon *icon1, NemoIcon *icon2, gboolean unselect_outside_range) { gboolean selection_changed; GList *p; NemoIcon *icon; NemoIcon *unmatched_icon; gboolean select; selection_changed = FALSE; unmatched_icon = NULL; select = FALSE; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (unmatched_icon == NULL) { if (icon == icon1) { unmatched_icon = icon2; select = TRUE; } else if (icon == icon2) { unmatched_icon = icon1; select = TRUE; } } if (select || unselect_outside_range) { selection_changed |= icon_set_selected (container, icon, select); } if (unmatched_icon != NULL && icon == unmatched_icon) { select = FALSE; } } if (selection_changed && icon2 != NULL) { emit_atk_focus_tracker_notify (icon2); } return selection_changed; } static gboolean select_one_unselect_others (NemoIconContainer *container, NemoIcon *icon_to_select) { gboolean selection_changed; GList *p; NemoIcon *icon; selection_changed = FALSE; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; selection_changed |= icon_set_selected (container, icon, icon == icon_to_select); } if (selection_changed && icon_to_select != NULL) { emit_atk_focus_tracker_notify (icon_to_select); reveal_icon (container, icon_to_select); } return selection_changed; } static gboolean unselect_all (NemoIconContainer *container) { return select_one_unselect_others (container, NULL); } /* Implementation of rubberband selection. */ static void rubberband_select (NemoIconContainer *container, const EelDRect *previous_rect, const EelDRect *current_rect) { GList *p; gboolean selection_changed, is_in, canvas_rect_calculated; NemoIcon *icon; EelIRect canvas_rect; EelCanvas *canvas; selection_changed = FALSE; canvas_rect_calculated = FALSE; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (!canvas_rect_calculated) { /* Only do this calculation once, since all the canvas items * we are interating are in the same coordinate space */ canvas = EEL_CANVAS_ITEM (icon->item)->canvas; eel_canvas_w2c (canvas, current_rect->x0, current_rect->y0, &canvas_rect.x0, &canvas_rect.y0); eel_canvas_w2c (canvas, current_rect->x1, current_rect->y1, &canvas_rect.x1, &canvas_rect.y1); canvas_rect_calculated = TRUE; } is_in = nemo_icon_canvas_item_hit_test_rectangle (icon->item, canvas_rect); selection_changed |= icon_set_selected (container, icon, is_in ^ icon->was_selected_before_rubberband); } if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } static int rubberband_timeout_callback (gpointer data) { NemoIconContainer *container; GtkWidget *widget; NemoIconRubberbandInfo *band_info; int x, y; double x1, y1, x2, y2; double world_x, world_y; int x_scroll, y_scroll; int adj_x, adj_y; gboolean adj_changed; GtkAllocation allocation; EelDRect selection_rect; widget = GTK_WIDGET (data); container = NEMO_ICON_CONTAINER (data); band_info = &container->details->rubberband_info; g_assert (band_info->timer_id != 0); adj_changed = FALSE; gtk_widget_get_allocation (widget, &allocation); adj_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); if (adj_x != band_info->last_adj_x) { band_info->last_adj_x = adj_x; adj_changed = TRUE; } adj_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))); if (adj_y != band_info->last_adj_y) { band_info->last_adj_y = adj_y; adj_changed = TRUE; } gdk_window_get_device_position (gtk_widget_get_window (widget), gdk_device_manager_get_client_pointer ( gdk_display_get_device_manager ( gtk_widget_get_display (widget))), &x, &y, NULL); if (x < RUBBERBAND_SCROLL_THRESHOLD) { x_scroll = x - RUBBERBAND_SCROLL_THRESHOLD; x = 0; } else if (x >= allocation.width - RUBBERBAND_SCROLL_THRESHOLD) { x_scroll = x - allocation.width + RUBBERBAND_SCROLL_THRESHOLD + 1; x = allocation.width - 1; } else { x_scroll = 0; } if (y < RUBBERBAND_SCROLL_THRESHOLD) { y_scroll = y - RUBBERBAND_SCROLL_THRESHOLD; y = 0; } else if (y >= allocation.height - RUBBERBAND_SCROLL_THRESHOLD) { y_scroll = y - allocation.height + RUBBERBAND_SCROLL_THRESHOLD + 1; y = allocation.height - 1; } else { y_scroll = 0; } if (y_scroll == 0 && x_scroll == 0 && (int) band_info->prev_x == x && (int) band_info->prev_y == y && !adj_changed) { return TRUE; } nemo_icon_container_scroll (container, x_scroll, y_scroll); /* Remember to convert from widget to scrolled window coords */ eel_canvas_window_to_world (EEL_CANVAS (container), x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))), y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))), &world_x, &world_y); if (world_x < band_info->start_x) { x1 = world_x; x2 = band_info->start_x; } else { x1 = band_info->start_x; x2 = world_x; } if (world_y < band_info->start_y) { y1 = world_y; y2 = band_info->start_y; } else { y1 = band_info->start_y; y2 = world_y; } /* Don't let the area of the selection rectangle be empty. * Aside from the fact that it would be funny when the rectangle disappears, * this also works around a crash in libart that happens sometimes when a * zero height rectangle is passed. */ x2 = MAX (x1 + 1, x2); y2 = MAX (y1 + 1, y2); eel_canvas_item_set (band_info->selection_rectangle, "x1", x1, "y1", y1, "x2", x2, "y2", y2, NULL); selection_rect.x0 = x1; selection_rect.y0 = y1; selection_rect.x1 = x2; selection_rect.y1 = y2; rubberband_select (container, &band_info->prev_rect, &selection_rect); band_info->prev_x = x; band_info->prev_y = y; band_info->prev_rect = selection_rect; return TRUE; } static void start_rubberbanding (NemoIconContainer *container, GdkEventButton *event) { AtkObject *accessible; NemoIconContainerDetails *details; NemoIconRubberbandInfo *band_info; GdkRGBA bg_color, border_color; GList *p; NemoIcon *icon; GtkStyleContext *context; details = container->details; band_info = &details->rubberband_info; g_signal_emit (container, signals[BAND_SELECT_STARTED], 0); for (p = details->icons; p != NULL; p = p->next) { icon = p->data; icon->was_selected_before_rubberband = icon->is_selected; } eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &band_info->start_x, &band_info->start_y); context = gtk_widget_get_style_context (GTK_WIDGET (container)); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND); gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg_color); gtk_style_context_get_border_color (context, GTK_STATE_FLAG_NORMAL, &border_color); gtk_style_context_restore (context); band_info->selection_rectangle = eel_canvas_item_new (eel_canvas_root (EEL_CANVAS (container)), NEMO_TYPE_SELECTION_CANVAS_ITEM, "x1", band_info->start_x, "y1", band_info->start_y, "x2", band_info->start_x, "y2", band_info->start_y, "fill_color_rgba", &bg_color, "outline_color_rgba", &border_color, "width_pixels", 1, NULL); accessible = atk_gobject_accessible_for_object (G_OBJECT (band_info->selection_rectangle)); atk_object_set_name (accessible, "selection"); atk_object_set_description (accessible, _("The selection rectangle")); band_info->prev_x = event->x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); band_info->prev_y = event->y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))); band_info->active = TRUE; if (band_info->timer_id == 0) { band_info->timer_id = g_timeout_add (RUBBERBAND_TIMEOUT_INTERVAL, rubberband_timeout_callback, container); } eel_canvas_item_grab (band_info->selection_rectangle, (GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK), NULL, event->time); } static void stop_rubberbanding (NemoIconContainer *container, guint32 time) { NemoIconRubberbandInfo *band_info; GList *icons; gboolean enable_animation; band_info = &container->details->rubberband_info; g_assert (band_info->timer_id != 0); g_source_remove (band_info->timer_id); band_info->timer_id = 0; band_info->active = FALSE; g_object_get (gtk_settings_get_default (), "gtk-enable-animations", &enable_animation, NULL); /* Destroy this canvas item; the parent will unref it. */ eel_canvas_item_ungrab (band_info->selection_rectangle, time); eel_canvas_item_lower_to_bottom (band_info->selection_rectangle); if (enable_animation) { nemo_selection_canvas_item_fade_out (NEMO_SELECTION_CANVAS_ITEM (band_info->selection_rectangle), 150); } else { eel_canvas_item_destroy (band_info->selection_rectangle); } band_info->selection_rectangle = NULL; /* if only one item has been selected, use it as range * selection base (cf. handle_icon_button_press) */ icons = nemo_icon_container_get_selected_icons (container); if (g_list_length (icons) == 1) { container->details->range_selection_base_icon = icons->data; } g_list_free (icons); g_signal_emit (container, signals[BAND_SELECT_ENDED], 0); } /* Keyboard navigation. */ typedef gboolean (* IsBetterIconFunction) (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data); static NemoIcon * find_best_icon (NemoIconContainer *container, NemoIcon *start_icon, IsBetterIconFunction function, void *data) { GList *p; NemoIcon *best, *candidate; best = NULL; for (p = container->details->icons; p != NULL; p = p->next) { candidate = p->data; if (candidate != start_icon) { if ((* function) (container, start_icon, best, candidate, data)) { best = candidate; } } } return best; } static NemoIcon * find_best_selected_icon (NemoIconContainer *container, NemoIcon *start_icon, IsBetterIconFunction function, void *data) { GList *p; NemoIcon *best, *candidate; best = NULL; for (p = container->details->icons; p != NULL; p = p->next) { candidate = p->data; if (candidate != start_icon && candidate->is_selected) { if ((* function) (container, start_icon, best, candidate, data)) { best = candidate; } } } return best; } static int compare_icons_by_uri (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b) { char *uri_a, *uri_b; int result; g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (icon_a != NULL); g_assert (icon_b != NULL); g_assert (icon_a != icon_b); uri_a = nemo_icon_container_get_icon_uri (container, icon_a); uri_b = nemo_icon_container_get_icon_uri (container, icon_b); result = strcmp (uri_a, uri_b); g_assert (result != 0); g_free (uri_a); g_free (uri_b); return result; } static int get_cmp_point_x (NemoIconContainer *container, EelDRect icon_rect) { if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) { return icon_rect.x0; } else { return icon_rect.x1; } } else { return (icon_rect.x0 + icon_rect.x1) / 2; } } static int get_cmp_point_y (NemoIconContainer *container, EelDRect icon_rect) { if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { return (icon_rect.y0 + icon_rect.y1)/2; } else { return icon_rect.y1; } } static int compare_icons_horizontal (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b) { EelDRect world_rect; int ax, bx; world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_a->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &ax, NULL); world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_b->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &bx, NULL); if (ax < bx) { return -1; } if (ax > bx) { return +1; } return 0; } static int compare_icons_vertical (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b) { EelDRect world_rect; int ay, by; world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_a->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), NULL, &ay); world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_b->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), NULL, &by); if (ay < by) { return -1; } if (ay > by) { return +1; } return 0; } static int compare_icons_horizontal_first (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b) { EelDRect world_rect; int ax, ay, bx, by; world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_a->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &ax, &ay); world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_b->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &bx, &by); if (ax < bx) { return -1; } if (ax > bx) { return +1; } if (ay < by) { return -1; } if (ay > by) { return +1; } return compare_icons_by_uri (container, icon_a, icon_b); } static int compare_icons_vertical_first (NemoIconContainer *container, NemoIcon *icon_a, NemoIcon *icon_b) { EelDRect world_rect; int ax, ay, bx, by; world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_a->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &ax, &ay); world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon_b->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &bx, &by); if (ay < by) { return -1; } if (ay > by) { return +1; } if (ax < bx) { return -1; } if (ax > bx) { return +1; } return compare_icons_by_uri (container, icon_a, icon_b); } static gboolean leftmost_in_top_row (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { if (best_so_far == NULL) { return TRUE; } return compare_icons_vertical_first (container, best_so_far, candidate) > 0; } static gboolean rightmost_in_top_row (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { if (best_so_far == NULL) { return TRUE; } return compare_icons_vertical (container, best_so_far, candidate) > 0; return compare_icons_horizontal (container, best_so_far, candidate) < 0; } static gboolean rightmost_in_bottom_row (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { if (best_so_far == NULL) { return TRUE; } return compare_icons_vertical_first (container, best_so_far, candidate) < 0; } static int compare_with_start_row (NemoIconContainer *container, NemoIcon *icon) { EelCanvasItem *item; item = EEL_CANVAS_ITEM (icon->item); if (container->details->arrow_key_start_y < item->y1) { return -1; } if (container->details->arrow_key_start_y > item->y2) { return +1; } return 0; } static int compare_with_start_column (NemoIconContainer *container, NemoIcon *icon) { EelCanvasItem *item; item = EEL_CANVAS_ITEM (icon->item); if (container->details->arrow_key_start_x < item->x1) { return -1; } if (container->details->arrow_key_start_x > item->x2) { return +1; } return 0; } static gboolean same_row_right_side_leftmost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* Candidates not on the start row do not qualify. */ if (compare_with_start_row (container, candidate) != 0) { return FALSE; } /* Candidates that are farther right lose out. */ if (best_so_far != NULL) { if (compare_icons_horizontal_first (container, best_so_far, candidate) < 0) { return FALSE; } } /* Candidate to the left of the start do not qualify. */ if (compare_icons_horizontal_first (container, candidate, start_icon) <= 0) { return FALSE; } return TRUE; } static gboolean same_row_left_side_rightmost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* Candidates not on the start row do not qualify. */ if (compare_with_start_row (container, candidate) != 0) { return FALSE; } /* Candidates that are farther left lose out. */ if (best_so_far != NULL) { if (compare_icons_horizontal_first (container, best_so_far, candidate) > 0) { return FALSE; } } /* Candidate to the right of the start do not qualify. */ if (compare_icons_horizontal_first (container, candidate, start_icon) >= 0) { return FALSE; } return TRUE; } static gboolean next_row_leftmost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not below the current row */ if (compare_with_start_row (container, candidate) >= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_vertical_first (container, best_so_far, candidate) > 0) { /* candidate is above best choice, but below the current row */ return TRUE; } if (compare_icons_horizontal_first (container, best_so_far, candidate) > 0) { return TRUE; } } return best_so_far == NULL; } static gboolean next_row_rightmost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not below the current row */ if (compare_with_start_row (container, candidate) >= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_vertical_first (container, best_so_far, candidate) > 0) { /* candidate is above best choice, but below the current row */ return TRUE; } if (compare_icons_horizontal_first (container, best_so_far, candidate) < 0) { return TRUE; } } return best_so_far == NULL; } static gboolean next_column_bottommost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not on the right of the current column */ if (compare_with_start_column (container, candidate) >= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_horizontal_first (container, best_so_far, candidate) > 0) { /* candidate is above best choice, but below the current row */ return TRUE; } if (compare_icons_vertical_first (container, best_so_far, candidate) < 0) { return TRUE; } } return best_so_far == NULL; } static gboolean previous_row_rightmost (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not above the current row */ if (compare_with_start_row (container, candidate) <= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_vertical_first (container, best_so_far, candidate) < 0) { /* candidate is below the best choice, but above the current row */ return TRUE; } if (compare_icons_horizontal_first (container, best_so_far, candidate) < 0) { return TRUE; } } return best_so_far == NULL; } static gboolean same_column_above_lowest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* Candidates not on the start column do not qualify. */ if (compare_with_start_column (container, candidate) != 0) { return FALSE; } /* Candidates that are higher lose out. */ if (best_so_far != NULL) { if (compare_icons_vertical_first (container, best_so_far, candidate) > 0) { return FALSE; } } /* Candidates below the start do not qualify. */ if (compare_icons_vertical_first (container, candidate, start_icon) >= 0) { return FALSE; } return TRUE; } static gboolean same_column_below_highest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* Candidates not on the start column do not qualify. */ if (compare_with_start_column (container, candidate) != 0) { return FALSE; } /* Candidates that are lower lose out. */ if (best_so_far != NULL) { if (compare_icons_vertical_first (container, best_so_far, candidate) < 0) { return FALSE; } } /* Candidates above the start do not qualify. */ if (compare_icons_vertical_first (container, candidate, start_icon) <= 0) { return FALSE; } return TRUE; } static gboolean previous_column_highest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not before the current column */ if (compare_with_start_column (container, candidate) <= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_horizontal (container, best_so_far, candidate) < 0) { /* candidate is right of the best choice, but left of the current column */ return TRUE; } if (compare_icons_vertical (container, best_so_far, candidate) > 0) { return TRUE; } } return best_so_far == NULL; } static gboolean next_column_highest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not after the current column */ if (compare_with_start_column (container, candidate) >= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_horizontal_first (container, best_so_far, candidate) > 0) { /* candidate is left of the best choice, but right of the current column */ return TRUE; } if (compare_icons_vertical_first (container, best_so_far, candidate) > 0) { return TRUE; } } return best_so_far == NULL; } static gboolean previous_column_lowest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { /* sort out icons that are not before the current column */ if (compare_with_start_column (container, candidate) <= 0) { return FALSE; } if (best_so_far != NULL) { if (compare_icons_horizontal_first (container, best_so_far, candidate) < 0) { /* candidate is right of the best choice, but left of the current column */ return TRUE; } if (compare_icons_vertical_first (container, best_so_far, candidate) < 0) { return TRUE; } } return best_so_far == NULL; } static gboolean last_column_lowest (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { if (best_so_far == NULL) { return TRUE; } return compare_icons_horizontal_first (container, best_so_far, candidate) < 0; } static gboolean closest_in_90_degrees (NemoIconContainer *container, NemoIcon *start_icon, NemoIcon *best_so_far, NemoIcon *candidate, void *data) { EelDRect world_rect; int x, y; int dx, dy; int dist; int *best_dist; world_rect = nemo_icon_canvas_item_get_icon_rectangle (candidate->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &x, &y); dx = x - container->details->arrow_key_start_x; dy = y - container->details->arrow_key_start_y; switch (container->details->arrow_key_direction) { case GTK_DIR_UP: if (dy > 0 || ABS(dx) > ABS(dy)) { return FALSE; } break; case GTK_DIR_DOWN: if (dy < 0 || ABS(dx) > ABS(dy)) { return FALSE; } break; case GTK_DIR_LEFT: if (dx > 0 || ABS(dy) > ABS(dx)) { return FALSE; } break; case GTK_DIR_RIGHT: if (dx < 0 || ABS(dy) > ABS(dx)) { return FALSE; } break; case GTK_DIR_TAB_FORWARD: case GTK_DIR_TAB_BACKWARD: default: g_assert_not_reached(); } dist = dx*dx + dy*dy; best_dist = data; if (best_so_far == NULL) { *best_dist = dist; return TRUE; } if (dist < *best_dist) { *best_dist = dist; return TRUE; } return FALSE; } static EelDRect get_rubberband (NemoIcon *icon1, NemoIcon *icon2) { EelDRect rect1; EelDRect rect2; EelDRect ret; eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon1->item), &rect1.x0, &rect1.y0, &rect1.x1, &rect1.y1); eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon2->item), &rect2.x0, &rect2.y0, &rect2.x1, &rect2.y1); eel_drect_union (&ret, &rect1, &rect2); return ret; } static void keyboard_move_to (NemoIconContainer *container, NemoIcon *icon, NemoIcon *from, GdkEventKey *event) { if (icon == NULL) { return; } if (event != NULL && (event->state & GDK_CONTROL_MASK) != 0 && (event->state & GDK_SHIFT_MASK) == 0) { /* Move the keyboard focus. Use Control modifier * rather than Alt to avoid Sawfish conflict. */ set_keyboard_focus (container, icon); container->details->keyboard_rubberband_start = NULL; } else if (event != NULL && ((event->state & GDK_CONTROL_MASK) != 0 || !container->details->auto_layout) && (event->state & GDK_SHIFT_MASK) != 0) { /* Do rubberband selection */ EelDRect rect; if (from && !container->details->keyboard_rubberband_start) { set_keyboard_rubberband_start (container, from); } set_keyboard_focus (container, icon); if (icon && container->details->keyboard_rubberband_start) { rect = get_rubberband (container->details->keyboard_rubberband_start, icon); rubberband_select (container, NULL, &rect); } } else if (event != NULL && (event->state & GDK_CONTROL_MASK) == 0 && (event->state & GDK_SHIFT_MASK) != 0) { /* Select range */ NemoIcon *start_icon; start_icon = container->details->range_selection_base_icon; if (start_icon == NULL || !start_icon->is_selected) { start_icon = icon; container->details->range_selection_base_icon = icon; } set_keyboard_focus (container, icon); if (select_range (container, start_icon, icon, TRUE)) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } else { /* Select icons and get rid of the special keyboard focus. */ clear_keyboard_focus (container); clear_keyboard_rubberband_start (container); container->details->range_selection_base_icon = icon; if (select_one_unselect_others (container, icon)) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } schedule_keyboard_icon_reveal (container, icon); } static void keyboard_home (NemoIconContainer *container, GdkEventKey *event) { NemoIcon *from; NemoIcon *to; /* Home selects the first icon. * Control-Home sets the keyboard focus to the first icon. */ from = find_best_selected_icon (container, NULL, rightmost_in_bottom_row, NULL); to = find_best_icon (container, NULL, leftmost_in_top_row, NULL); keyboard_move_to (container, to, from, event); } static void keyboard_end (NemoIconContainer *container, GdkEventKey *event) { NemoIcon *to; NemoIcon *from; /* End selects the last icon. * Control-End sets the keyboard focus to the last icon. */ from = find_best_selected_icon (container, NULL, leftmost_in_top_row, NULL); to = find_best_icon (container, NULL, nemo_icon_container_is_layout_vertical (container) ? last_column_lowest : rightmost_in_bottom_row, NULL); keyboard_move_to (container, to, from, event); } static void record_arrow_key_start (NemoIconContainer *container, NemoIcon *icon, GtkDirectionType direction) { EelDRect world_rect; world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); eel_canvas_w2c (EEL_CANVAS (container), get_cmp_point_x (container, world_rect), get_cmp_point_y (container, world_rect), &container->details->arrow_key_start_x, &container->details->arrow_key_start_y); container->details->arrow_key_direction = direction; } static void keyboard_arrow_key (NemoIconContainer *container, GdkEventKey *event, GtkDirectionType direction, IsBetterIconFunction better_start, IsBetterIconFunction empty_start, IsBetterIconFunction better_destination, IsBetterIconFunction better_destination_fallback, IsBetterIconFunction better_destination_fallback_fallback, IsBetterIconFunction better_destination_manual) { NemoIcon *from; NemoIcon *to; int data; /* Chose the icon to start with. * If we have a keyboard focus, start with it. * Otherwise, use the single selected icon. * If there's multiple selection, use the icon farthest toward the end. */ from = container->details->keyboard_focus; if (from == NULL) { if (has_multiple_selection (container)) { if (all_selected (container)) { from = find_best_selected_icon (container, NULL, empty_start, NULL); } else { from = find_best_selected_icon (container, NULL, better_start, NULL); } } else { from = get_first_selected_icon (container); } } /* If there's no icon, select the icon farthest toward the end. * If there is an icon, select the next icon based on the arrow direction. */ if (from == NULL) { to = from = find_best_icon (container, NULL, empty_start, NULL); } else { record_arrow_key_start (container, from, direction); to = find_best_icon (container, from, container->details->auto_layout ? better_destination : better_destination_manual, &data); /* Wrap around to next/previous row/column */ if (to == NULL && better_destination_fallback != NULL) { to = find_best_icon (container, from, better_destination_fallback, &data); } /* With a layout like * 1 2 3 * 4 * (horizontal layout) * * or * * 1 4 * 2 * 3 * (vertical layout) * * * pressing down for any of 1,2,3 (horizontal layout) * * pressing right for any of 1,2,3 (vertical layout) * * Should select 4. */ if (to == NULL && container->details->auto_layout && better_destination_fallback_fallback != NULL) { to = find_best_icon (container, from, better_destination_fallback_fallback, &data); } if (to == NULL) { to = from; } } keyboard_move_to (container, to, from, event); } static gboolean is_rectangle_selection_event (GdkEventKey *event) { return (event->state & GDK_CONTROL_MASK) != 0 && (event->state & GDK_SHIFT_MASK) != 0; } static void keyboard_right (NemoIconContainer *container, GdkEventKey *event) { IsBetterIconFunction fallback; IsBetterIconFunction next_column_fallback; fallback = NULL; if (container->details->auto_layout && !nemo_icon_container_is_layout_vertical (container) && !is_rectangle_selection_event (event)) { fallback = next_row_leftmost; } next_column_fallback = NULL; if (nemo_icon_container_is_layout_vertical (container) && gtk_widget_get_direction (GTK_WIDGET (container)) != GTK_TEXT_DIR_RTL) { next_column_fallback = next_column_bottommost; } /* Right selects the next icon in the same row. * Control-Right sets the keyboard focus to the next icon in the same row. */ keyboard_arrow_key (container, event, GTK_DIR_RIGHT, rightmost_in_bottom_row, nemo_icon_container_is_layout_rtl (container) ? rightmost_in_top_row : leftmost_in_top_row, same_row_right_side_leftmost, fallback, next_column_fallback, closest_in_90_degrees); } static void keyboard_left (NemoIconContainer *container, GdkEventKey *event) { IsBetterIconFunction fallback; IsBetterIconFunction previous_column_fallback; fallback = NULL; if (container->details->auto_layout && !nemo_icon_container_is_layout_vertical (container) && !is_rectangle_selection_event (event)) { fallback = previous_row_rightmost; } previous_column_fallback = NULL; if (nemo_icon_container_is_layout_vertical (container) && gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) { previous_column_fallback = previous_column_lowest; } /* Left selects the next icon in the same row. * Control-Left sets the keyboard focus to the next icon in the same row. */ keyboard_arrow_key (container, event, GTK_DIR_LEFT, rightmost_in_bottom_row, nemo_icon_container_is_layout_rtl (container) ? rightmost_in_top_row : leftmost_in_top_row, same_row_left_side_rightmost, fallback, previous_column_fallback, closest_in_90_degrees); } static void keyboard_down (NemoIconContainer *container, GdkEventKey *event) { IsBetterIconFunction fallback; IsBetterIconFunction next_row_fallback; fallback = NULL; if (container->details->auto_layout && nemo_icon_container_is_layout_vertical (container) && !is_rectangle_selection_event (event)) { if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) { fallback = previous_column_highest; } else { fallback = next_column_highest; } } next_row_fallback = NULL; if (!nemo_icon_container_is_layout_vertical (container)) { if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) { next_row_fallback = next_row_leftmost; } else { next_row_fallback = next_row_rightmost; } } /* Down selects the next icon in the same column. * Control-Down sets the keyboard focus to the next icon in the same column. */ keyboard_arrow_key (container, event, GTK_DIR_DOWN, rightmost_in_bottom_row, nemo_icon_container_is_layout_rtl (container) ? rightmost_in_top_row : leftmost_in_top_row, same_column_below_highest, fallback, next_row_fallback, closest_in_90_degrees); } static void keyboard_up (NemoIconContainer *container, GdkEventKey *event) { IsBetterIconFunction fallback; fallback = NULL; if (container->details->auto_layout && nemo_icon_container_is_layout_vertical (container) && !is_rectangle_selection_event (event)) { if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) { fallback = next_column_bottommost; } else { fallback = previous_column_lowest; } } /* Up selects the next icon in the same column. * Control-Up sets the keyboard focus to the next icon in the same column. */ keyboard_arrow_key (container, event, GTK_DIR_UP, rightmost_in_bottom_row, nemo_icon_container_is_layout_rtl (container) ? rightmost_in_top_row : leftmost_in_top_row, same_column_above_lowest, fallback, NULL, closest_in_90_degrees); } static void keyboard_space (NemoIconContainer *container, GdkEventKey *event) { NemoIcon *icon; if (!has_selection (container) && container->details->keyboard_focus != NULL) { keyboard_move_to (container, container->details->keyboard_focus, NULL, NULL); } else if ((event->state & GDK_CONTROL_MASK) != 0 && (event->state & GDK_SHIFT_MASK) == 0) { /* Control-space toggles the selection state of the current icon. */ if (container->details->keyboard_focus != NULL) { icon_toggle_selected (container, container->details->keyboard_focus); g_signal_emit (container, signals[SELECTION_CHANGED], 0); if (container->details->keyboard_focus->is_selected) { container->details->range_selection_base_icon = container->details->keyboard_focus; } } else { icon = find_best_selected_icon (container, NULL, leftmost_in_top_row, NULL); if (icon == NULL) { icon = find_best_icon (container, NULL, leftmost_in_top_row, NULL); } if (icon != NULL) { set_keyboard_focus (container, icon); } } } else if ((event->state & GDK_SHIFT_MASK) != 0) { activate_selected_items_alternate (container, NULL); } else { preview_selected_items (container); } } /* look for the first icon that matches the longest part of a given * search pattern */ typedef struct { gunichar *name; int last_match_length; } BestNameMatch; #ifndef TAB_NAVIGATION_DISABLED static void select_previous_or_next_icon (NemoIconContainer *container, gboolean next, GdkEventKey *event) { NemoIcon *icon; const GList *item; item = NULL; /* Chose the icon to start with. * If we have a keyboard focus, start with it. * Otherwise, use the single selected icon. */ icon = container->details->keyboard_focus; if (icon == NULL) { icon = get_first_selected_icon (container); } if (icon != NULL) { /* must have at least @icon in the list */ g_assert (container->details->icons != NULL); item = g_list_find (container->details->icons, icon); g_assert (item != NULL); item = next ? item->next : item->prev; if (item == NULL) { item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons); } } else if (container->details->icons != NULL) { /* no selection yet, pick the first or last item to select */ item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons); } icon = (item != NULL) ? item->data : NULL; if (icon != NULL) { keyboard_move_to (container, icon, NULL, event); } } #endif static void destroy (GtkWidget *object) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (object); nemo_icon_container_clear (container); if (container->details->rubberband_info.timer_id != 0) { g_source_remove (container->details->rubberband_info.timer_id); container->details->rubberband_info.timer_id = 0; } if (container->details->idle_id != 0) { g_source_remove (container->details->idle_id); container->details->idle_id = 0; } if (container->details->stretch_idle_id != 0) { g_source_remove (container->details->stretch_idle_id); container->details->stretch_idle_id = 0; } if (container->details->align_idle_id != 0) { g_source_remove (container->details->align_idle_id); container->details->align_idle_id = 0; } if (container->details->selection_changed_id != 0) { g_source_remove (container->details->selection_changed_id); container->details->selection_changed_id = 0; } if (container->details->size_allocation_count_id != 0) { g_source_remove (container->details->size_allocation_count_id); container->details->size_allocation_count_id = 0; } /* destroy interactive search dialog */ if (container->details->search_window) { gtk_widget_destroy (container->details->search_window); container->details->search_window = NULL; container->details->search_entry = NULL; } remove_search_entry_timeout (container); GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->destroy (object); } static void finalize (GObject *object) { NemoIconContainerDetails *details; details = NEMO_ICON_CONTAINER (object)->details; g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, text_ellipsis_limit_changed_container_callback, object); g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, text_ellipsis_limit_changed_container_callback, object); g_signal_handlers_disconnect_by_func (nemo_preferences, tooltip_prefs_changed_callback, object); g_hash_table_destroy (details->icon_set); details->icon_set = NULL; g_free (details->font); if (details->a11y_item_action_queue != NULL) { while (!g_queue_is_empty (details->a11y_item_action_queue)) { g_free (g_queue_pop_head (details->a11y_item_action_queue)); } g_queue_free (details->a11y_item_action_queue); } if (details->a11y_item_action_idle_handler != 0) { g_source_remove (details->a11y_item_action_idle_handler); } g_slice_free (NemoViewLayoutConstants, details->view_constants); g_free (details); G_OBJECT_CLASS (nemo_icon_container_parent_class)->finalize (object); } /* GtkWidget methods. */ static gboolean clear_size_allocation_count (gpointer data) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (data); container->details->size_allocation_count_id = 0; container->details->size_allocation_count = 0; return FALSE; } static void size_allocate (GtkWidget *widget, GtkAllocation *allocation) { NemoIconContainer *container; gboolean need_layout_redone; GtkAllocation wid_allocation; container = NEMO_ICON_CONTAINER (widget); need_layout_redone = !container->details->has_been_allocated; gtk_widget_get_allocation (widget, &wid_allocation); if (allocation->width != wid_allocation.width) { need_layout_redone = TRUE; } if (allocation->height != wid_allocation.height) { need_layout_redone = TRUE; } /* Under some conditions we can end up in a loop when size allocating. * This happens when the icons don't fit without a scrollbar, but fits * when a scrollbar is added (bug #129963 for details). * We keep track of this looping by increasing a counter in size_allocate * and clearing it in a high-prio idle (the only way to detect the loop is * done). * When we've done at more than two iterations (with/without scrollbar) * we terminate this looping by not redoing the layout when the width * is wider than the current one (i.e when removing the scrollbar). */ if (container->details->size_allocation_count_id == 0) { container->details->size_allocation_count_id = g_idle_add_full (G_PRIORITY_HIGH, clear_size_allocation_count, container, NULL); } container->details->size_allocation_count++; if (container->details->size_allocation_count > 2 && allocation->width >= wid_allocation.width) { need_layout_redone = FALSE; } if (is_renaming (container)) { container->details->renaming_allocation_count++; if (container->details->renaming_allocation_count == 1) { need_layout_redone = FALSE; } } GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->size_allocate (widget, allocation); container->details->has_been_allocated = TRUE; if (need_layout_redone) { nemo_icon_container_redo_layout (container); } } static GtkSizeRequestMode get_request_mode (GtkWidget *widget) { /* Don't trade size at all, since we get whatever we get anyway. */ return GTK_SIZE_REQUEST_CONSTANT_SIZE; } /* We need to implement these since the GtkScrolledWindow uses them to guess whether to show scrollbars or not, and if we don't report anything it'll tend to get it wrong causing double calls to size_allocate (at different sizes) during its size allocation. */ static void get_prefered_width (GtkWidget *widget, gint *minimum_size, gint *natural_size) { EelCanvasGroup *root; double x1, x2; int cx1, cx2; int width; root = eel_canvas_root (EEL_CANVAS (widget)); eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root), &x1, NULL, &x2, NULL); eel_canvas_w2c (EEL_CANVAS (widget), x1, 0, &cx1, NULL); eel_canvas_w2c (EEL_CANVAS (widget), x2, 0, &cx2, NULL); width = cx2 - cx1; if (natural_size) { *natural_size = width; } if (minimum_size) { *minimum_size = width; } } static void get_prefered_height (GtkWidget *widget, gint *minimum_size, gint *natural_size) { EelCanvasGroup *root; double y1, y2; int cy1, cy2; int height; root = eel_canvas_root (EEL_CANVAS (widget)); eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root), NULL, &y1, NULL, &y2); eel_canvas_w2c (EEL_CANVAS (widget), 0, y1, NULL, &cy1); eel_canvas_w2c (EEL_CANVAS (widget), 0, y2, NULL, &cy2); height = cy2 - cy1; if (natural_size) { *natural_size = height; } if (minimum_size) { *minimum_size = height; } } static void realize (GtkWidget *widget) { GtkAdjustment *vadj, *hadj; NemoIconContainer *container; GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->realize (widget); container = NEMO_ICON_CONTAINER (widget); /* Set up DnD. */ nemo_icon_dnd_init (container); hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (widget)); g_signal_connect (hadj, "value_changed", G_CALLBACK (handle_hadjustment_changed), widget); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget)); g_signal_connect (vadj, "value_changed", G_CALLBACK (handle_vadjustment_changed), widget); } static void unrealize (GtkWidget *widget) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (widget); nemo_icon_dnd_fini (container); remove_search_entry_timeout (container); GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->unrealize (widget); } static void style_updated (GtkWidget *widget) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (widget); container->details->use_drop_shadows = container->details->drop_shadows_requested; /* Don't chain up to parent, if this is a desktop container, * because that resets the background of the window. */ if (!nemo_icon_container_get_is_desktop (container)) { GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->style_updated (widget); } if (gtk_widget_get_realized (widget)) { nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } } static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event) { NemoIconContainer *container; gboolean selection_changed; gboolean return_value; gboolean clicked_on_item; container = NEMO_ICON_CONTAINER (widget); container->details->button_down_time = event->time; /* Forget about the old keyboard selection now that we've started mousing. */ clear_keyboard_focus (container); clear_keyboard_rubberband_start (container); if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { /* We use our own double-click detection. */ return TRUE; } /* Invoke the canvas event handler and see if an item picks up the event. */ clicked_on_item = GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->button_press_event (widget, event); /* Move focus to icon container, unless we're still renaming (to avoid exiting * renaming mode) */ if (!gtk_widget_has_focus (widget) && !(is_renaming (container) || is_renaming_pending (container))) { gtk_widget_grab_focus (widget); } if (clicked_on_item) { NemoIcon *icon; // current icon which was clicked on /* when icon is in renaming mode and user clicks on the image part of icon renaming should get closed */ icon = get_first_selected_icon (container); // this function gets the clicked icon if (clicked_on_icon (container, icon, event) && icon == nemo_icon_container_get_icon_being_renamed (container)) { nemo_icon_container_end_renaming_mode (container, TRUE); } return TRUE; } if (event->button == DRAG_BUTTON && event->type == GDK_BUTTON_PRESS) { /* Clear the last click icon for double click */ container->details->double_click_icon[1] = container->details->double_click_icon[0]; container->details->double_click_icon[0] = NULL; } /* Button 1 does rubber banding. */ if (event->button == RUBBERBAND_BUTTON) { if (! button_event_modifies_selection (event)) { selection_changed = unselect_all (container); if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } start_rubberbanding (container, event); return TRUE; } /* Prevent multi-button weirdness such as bug 6181 */ if (container->details->rubberband_info.active) { return TRUE; } /* Button 2 may be passed to the window manager. */ if (event->button == MIDDLE_BUTTON) { selection_changed = unselect_all (container); if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } g_signal_emit (widget, signals[MIDDLE_CLICK], 0, event); return TRUE; } /* Button 3 does a contextual menu. */ if (event->button == CONTEXTUAL_MENU_BUTTON) { nemo_icon_container_end_renaming_mode (container, TRUE); selection_changed = unselect_all (container); if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } g_signal_emit (widget, signals[CONTEXT_CLICK_BACKGROUND], 0, event); return TRUE; } /* Otherwise, we emit a button_press message. */ g_signal_emit (widget, signals[BUTTON_PRESS], 0, event, &return_value); return return_value; } static void nemo_icon_container_did_not_drag (NemoIconContainer *container, GdkEventButton *event) { NemoIconContainerDetails *details; gboolean selection_changed; static gint64 last_click_time = 0; static gint click_count = 0; gint double_click_time; gint64 current_time; details = container->details; if (details->icon_selected_on_button_down && ((event->state & GDK_CONTROL_MASK) != 0 || (event->state & GDK_SHIFT_MASK) == 0)) { if (button_event_modifies_selection (event)) { details->range_selection_base_icon = NULL; icon_toggle_selected (container, details->drag_icon); g_signal_emit (container, signals[SELECTION_CHANGED], 0); } else { details->range_selection_base_icon = details->drag_icon; selection_changed = select_one_unselect_others (container, details->drag_icon); if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } } if (details->drag_icon != NULL && (details->single_click_mode || event->button == MIDDLE_BUTTON)) { /* Determine click count */ g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))), "gtk-double-click-time", &double_click_time, NULL); current_time = g_get_monotonic_time (); if (current_time - last_click_time < double_click_time * 1000) { click_count++; } else { click_count = 0; } /* Stash time for next compare */ last_click_time = current_time; /* If single-click mode, activate the selected icons, unless modifying * the selection or pressing for a very long time, or double clicking. */ if (click_count == 0 && event->time - details->button_down_time < MAX_CLICK_TIME && ! button_event_modifies_selection (event)) { /* It's a tricky UI issue whether this should activate * just the clicked item (as if it were a link), or all * the selected items (as if you were issuing an "activate * selection" command). For now, we're trying the activate * entire selection version to see how it feels. Note that * NemoList goes the other way because its "links" seem * much more link-like. */ if (event->button == MIDDLE_BUTTON) { activate_selected_items_alternate (container, NULL); } else { activate_selected_items (container); } } } if (details->drag_icon != NULL && handle_icon_slow_two_click (container, details->drag_icon, event)) { if (!details->skip_rename_on_release) nemo_icon_container_start_renaming_selected_item (container, FALSE); } } static gboolean clicked_within_double_click_interval (NemoIconContainer *container) { static gint64 last_click_time = 0; static gint click_count = 0; gint64 current_time; gint interval; /* fetch system double-click time */ g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))), "gtk-double-click-time", &interval, NULL); current_time = g_get_monotonic_time (); if (current_time - last_click_time < interval * 1000) { click_count++; } else { click_count = 0; } /* Stash time for next compare */ last_click_time = current_time; /* Only allow double click */ if (click_count == 1) { click_count = 0; return TRUE; } else { return FALSE; } } static gboolean clicked_within_slow_click_interval_on_text (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { static gint64 last_slow_click_time = 0; static gint slow_click_count = 0; gint64 current_time; gint interval; gint double_click_interval; /* fetch system double-click time */ g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))), "gtk-double-click-time", &double_click_interval, NULL); /* slow click interval is always 2 seconds longer than the system * double-click interval. */ interval = double_click_interval + 2000; current_time = g_get_monotonic_time (); if (current_time - last_slow_click_time < interval * 1000) { slow_click_count = 1; } else { slow_click_count = 0; } /* Stash time for next compare */ last_slow_click_time = current_time; /* Only allow second click on text to trigger this */ if (slow_click_count == 1 && icon == get_first_selected_icon (container) && clicked_on_text (container, icon, event)) { slow_click_count = 0; return TRUE; } else { return FALSE; } } static void clear_drag_state (NemoIconContainer *container) { container->details->drag_icon = NULL; container->details->drag_state = DRAG_STATE_INITIAL; } static gboolean start_stretching (NemoIconContainer *container) { NemoIconContainerDetails *details; NemoIcon *icon; GtkWidget *toplevel; GtkCornerType corner; GdkCursor *cursor; details = container->details; icon = details->stretch_icon; /* Check if we hit the stretch handles. */ if (!nemo_icon_canvas_item_hit_test_stretch_handles (icon->item, details->drag_x, details->drag_y, &corner)) { return FALSE; } switch (corner) { case GTK_CORNER_TOP_LEFT: cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER); break; case GTK_CORNER_BOTTOM_LEFT: cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER); break; case GTK_CORNER_TOP_RIGHT: cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER); break; case GTK_CORNER_BOTTOM_RIGHT: cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER); break; default: cursor = NULL; break; } /* Set up the dragging. */ details->drag_state = DRAG_STATE_STRETCH; eel_canvas_w2c (EEL_CANVAS (container), details->drag_x, details->drag_y, &details->stretch_start.pointer_x, &details->stretch_start.pointer_y); eel_canvas_w2c (EEL_CANVAS (container), icon->x, icon->y, &details->stretch_start.icon_x, &details->stretch_start.icon_y); icon_get_size (container, icon, &details->stretch_start.icon_size); eel_canvas_item_grab (EEL_CANVAS_ITEM (icon->item), (GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), cursor, GDK_CURRENT_TIME); if (cursor) g_object_unref (cursor); /* Ensure the window itself is focused.. */ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container)); if (toplevel != NULL && gtk_widget_get_realized (toplevel)) { gdk_window_focus (gtk_widget_get_window (toplevel), GDK_CURRENT_TIME); } return TRUE; } static gboolean update_stretch_at_idle (NemoIconContainer *container) { NemoIconContainerDetails *details; NemoIcon *icon; double world_x, world_y; StretchState stretch_state; details = container->details; icon = details->stretch_icon; if (icon == NULL) { container->details->stretch_idle_id = 0; return FALSE; } eel_canvas_w2c (EEL_CANVAS (container), details->world_x, details->world_y, &stretch_state.pointer_x, &stretch_state.pointer_y); compute_stretch (&details->stretch_start, &stretch_state); eel_canvas_c2w (EEL_CANVAS (container), stretch_state.icon_x, stretch_state.icon_y, &world_x, &world_y); nemo_icon_container_icon_set_position (container, icon, world_x, world_y); icon_set_size (container, icon, stretch_state.icon_size, FALSE, FALSE); container->details->stretch_idle_id = 0; return FALSE; } static void continue_stretching (NemoIconContainer *container, double world_x, double world_y) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->world_x = world_x; container->details->world_y = world_y; if (container->details->stretch_idle_id == 0) { container->details->stretch_idle_id = g_idle_add ((GSourceFunc) update_stretch_at_idle, container); } } static gboolean keyboard_stretching (NemoIconContainer *container, GdkEventKey *event) { NemoIcon *icon; guint size; icon = container->details->stretch_icon; if (icon == NULL || !icon->is_selected) { return FALSE; } icon_get_size (container, icon, &size); switch (event->keyval) { case GDK_KEY_equal: case GDK_KEY_plus: case GDK_KEY_KP_Add: icon_set_size (container, icon, size + 5, FALSE, FALSE); break; case GDK_KEY_minus: case GDK_KEY_KP_Subtract: icon_set_size (container, icon, size - 5, FALSE, FALSE); break; case GDK_KEY_0: case GDK_KEY_KP_0: nemo_icon_container_move_icon (container, icon, icon->x, icon->y, 1.0, FALSE, TRUE, TRUE); break; default: break; } return TRUE; } static void ungrab_stretch_icon (NemoIconContainer *container) { eel_canvas_item_ungrab (EEL_CANVAS_ITEM (container->details->stretch_icon->item), GDK_CURRENT_TIME); } static void end_stretching (NemoIconContainer *container, double world_x, double world_y) { NemoIconPosition position; NemoIcon *icon; continue_stretching (container, world_x, world_y); ungrab_stretch_icon (container); /* now that we're done stretching, update the icon's position */ icon = container->details->drag_icon; if (nemo_icon_container_is_layout_rtl (container)) { position.x = icon->saved_ltr_x = nemo_icon_container_get_mirror_x_position (container, icon, icon->x); } else { position.x = icon->x; } position.y = icon->y; position.scale = icon->scale; g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0, icon->data, &position); clear_drag_state (container); nemo_icon_container_redo_layout (container); } static gboolean undo_stretching (NemoIconContainer *container) { NemoIcon *stretched_icon; stretched_icon = container->details->stretch_icon; if (stretched_icon == NULL) { return FALSE; } if (container->details->drag_state == DRAG_STATE_STRETCH) { ungrab_stretch_icon (container); clear_drag_state (container); } nemo_icon_canvas_item_set_show_stretch_handles (stretched_icon->item, FALSE); nemo_icon_container_icon_set_position (container, stretched_icon, container->details->stretch_initial_x, container->details->stretch_initial_y); icon_set_size (container, stretched_icon, container->details->stretch_initial_size, TRUE, TRUE); container->details->stretch_icon = NULL; emit_stretch_ended (container, stretched_icon); nemo_icon_container_redo_layout (container); return TRUE; } static gboolean button_release_event (GtkWidget *widget, GdkEventButton *event) { NemoIconContainer *container; NemoIconContainerDetails *details; double world_x, world_y; container = NEMO_ICON_CONTAINER (widget); details = container->details; if (event->button == RUBBERBAND_BUTTON && details->rubberband_info.active) { stop_rubberbanding (container, event->time); return GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->button_release_event (widget, event); } if (event->button == details->drag_button) { details->drag_button = 0; switch (details->drag_state) { case DRAG_STATE_MOVE_OR_COPY: if (!details->drag_started) { nemo_icon_container_did_not_drag (container, event); } else { nemo_icon_dnd_end_drag (container); DEBUG ("Ending drag from icon container"); } break; case DRAG_STATE_STRETCH: eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &world_x, &world_y); end_stretching (container, world_x, world_y); break; case DRAG_STATE_INITIAL: default: break; } clear_drag_state (container); return TRUE; } return GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->button_release_event (widget, event); } static int motion_notify_event (GtkWidget *widget, GdkEventMotion *event) { NemoIconContainer *container; NemoIconContainerDetails *details; double world_x, world_y; int canvas_x, canvas_y; GdkDragAction actions; container = NEMO_ICON_CONTAINER (widget); details = container->details; if (details->drag_button != 0) { switch (details->drag_state) { case DRAG_STATE_MOVE_OR_COPY: if (details->drag_started) { break; } eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &world_x, &world_y); if (gtk_drag_check_threshold (widget, details->drag_x, details->drag_y, world_x, world_y)) { details->drag_started = TRUE; details->drag_state = DRAG_STATE_MOVE_OR_COPY; nemo_icon_container_end_renaming_mode (container, TRUE); eel_canvas_w2c (EEL_CANVAS (container), details->drag_x, details->drag_y, &canvas_x, &canvas_y); actions = GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK; if (container->details->drag_allow_moves) { actions |= GDK_ACTION_MOVE; } nemo_icon_dnd_begin_drag (container, actions, details->drag_button, event, canvas_x, canvas_y); DEBUG ("Beginning drag from icon container"); } break; case DRAG_STATE_STRETCH: eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, &world_x, &world_y); continue_stretching (container, world_x, world_y); break; case DRAG_STATE_INITIAL: default: break; } } return GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->motion_notify_event (widget, event); } static void nemo_icon_container_search_position_func (NemoIconContainer *container, GtkWidget *search_dialog) { gint x, y; gint cont_x, cont_y; gint cont_width, cont_height; GdkWindow *cont_window; GtkRequisition requisition; gint monitor_num; GdkRectangle monitor; cont_window = gtk_widget_get_window (GTK_WIDGET (container)); monitor_num = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); /* FIXME?? _NET_WORKAREA hint only provides accurate workarea geometry for the * primary monitor. Non-primary will return the full monitor geometry instead. */ nemo_desktop_utils_get_monitor_work_rect (monitor_num, &monitor); gtk_widget_realize (search_dialog); gdk_window_get_origin (cont_window, &cont_x, &cont_y); cont_width = gdk_window_get_width (cont_window); cont_height = gdk_window_get_height (cont_window); gtk_widget_get_preferred_size (search_dialog, &requisition, NULL); if (nemo_icon_container_get_is_desktop (container)) { x = cont_x + cont_width - requisition.width; y = cont_y + cont_height - requisition.height; } else { if (cont_x + cont_width > monitor.x + monitor.width) { x = monitor.x + monitor.width - requisition.width; } else if (cont_x + cont_width - requisition.width < 0) { x = 0; } else { x = cont_x + cont_width - requisition.width; } if (cont_y + cont_height + requisition.height > monitor.y + monitor.height) { y = monitor.y + monitor.height - requisition.height; } else if (cont_y + cont_height < 0) { y = 0; } else { y = cont_y + cont_height; } } gdk_window_move (gtk_widget_get_window (search_dialog), x, y); } /* Cut and paste from gtkwindow.c */ static void send_focus_change (GtkWidget *widget, gboolean in) { GdkEvent *fevent; fevent = gdk_event_new (GDK_FOCUS_CHANGE); g_object_ref (widget); ((GdkEventFocus *) fevent)->in = in; gtk_widget_send_focus_change (widget, fevent); fevent->focus_change.type = GDK_FOCUS_CHANGE; fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget)); fevent->focus_change.in = in; gtk_widget_event (widget, fevent); g_object_notify (G_OBJECT (widget), "has-focus"); g_object_unref (widget); gdk_event_free (fevent); } static void nemo_icon_container_search_dialog_hide (GtkWidget *search_dialog, NemoIconContainer *container) { if (container->details->search_entry_changed_id) { g_signal_handler_disconnect (container->details->search_entry, container->details->search_entry_changed_id); container->details->search_entry_changed_id = 0; } remove_search_entry_timeout (container); /* send focus-in event */ send_focus_change (GTK_WIDGET (container->details->search_entry), FALSE); gtk_widget_hide (search_dialog); gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), ""); } static gboolean nemo_icon_container_search_entry_flush_timeout (gpointer data) { NemoIconContainer *container = data; container->details->typeselect_flush_timeout = 0; nemo_icon_container_search_dialog_hide (container->details->search_window, container); return FALSE; } static void add_search_entry_timeout (NemoIconContainer *container) { container->details->typeselect_flush_timeout = g_timeout_add_seconds (NEMO_ICON_CONTAINER_SEARCH_DIALOG_TIMEOUT, nemo_icon_container_search_entry_flush_timeout, container); } static void remove_search_entry_timeout (NemoIconContainer *container) { if (container->details->typeselect_flush_timeout) { g_source_remove (container->details->typeselect_flush_timeout); container->details->typeselect_flush_timeout = 0; } } static void reset_search_entry_timeout (NemoIconContainer *container) { remove_search_entry_timeout (container); add_search_entry_timeout (container); } /* Because we're visible but offscreen, we just set a flag in the preedit * callback. */ static void nemo_icon_container_search_preedit_changed (GtkEntry *entry, gchar *preedit, NemoIconContainer *container) { container->details->imcontext_changed = 1; reset_search_entry_timeout (container); } static void nemo_icon_container_search_activate (GtkEntry *entry, NemoIconContainer *container) { nemo_icon_container_search_dialog_hide (container->details->search_window, container); activate_selected_items (container); } static gboolean nemo_icon_container_search_delete_event (GtkWidget *widget, GdkEventAny *event, NemoIconContainer *container) { nemo_icon_container_search_dialog_hide (widget, container); return TRUE; } static gboolean nemo_icon_container_search_button_press_event (GtkWidget *widget, GdkEventButton *event, NemoIconContainer *container) { nemo_icon_container_search_dialog_hide (widget, container); if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (container))) { button_press_event (GTK_WIDGET (container), event); } return TRUE; } static gboolean nemo_icon_container_search_entry_button_press_event (GtkWidget *widget, GdkEventButton *event, NemoIconContainer *container) { reset_search_entry_timeout (container); return FALSE; } static void nemo_icon_container_search_populate_popup (GtkEntry *entry, GtkMenu *menu, NemoIconContainer *container) { remove_search_entry_timeout (container); g_signal_connect_swapped (menu, "hide", G_CALLBACK (add_search_entry_timeout), container); } void nemo_icon_container_get_icon_text (NemoIconContainer *container, NemoIconData *data, char **editable_text, char **additional_text, gboolean *pinned, gboolean include_invisible) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->get_icon_text != NULL); klass->get_icon_text (container, data, editable_text, additional_text, pinned, include_invisible); } static gboolean nemo_icon_container_search_iter (NemoIconContainer *container, const char *key, gint n) { GList *p; NemoIcon *icon; char *name; int count; char *normalized_key, *case_normalized_key; char *normalized_name, *case_normalized_name; g_assert (key != NULL); g_assert (n >= 1); normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); if (!normalized_key) { return FALSE; } case_normalized_key = g_utf8_casefold (normalized_key, -1); g_free (normalized_key); if (!case_normalized_key) { return FALSE; } icon = NULL; name = NULL; count = 0; for (p = container->details->icons; p != NULL && count != n; p = p->next) { icon = p->data; nemo_icon_container_get_icon_text (container, icon->data, &name, NULL, NULL, TRUE); /* This can happen if a key event is handled really early while * loading the icon container, before the items have all been * updated once. */ if (!name) { continue; } normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL); if (!normalized_name) { continue; } case_normalized_name = g_utf8_casefold (normalized_name, -1); g_free (normalized_name); if (!case_normalized_name) { continue; } if (strncmp (case_normalized_key, case_normalized_name, strlen (case_normalized_key)) == 0) { count++; } g_free (case_normalized_name); g_free (name); name = NULL; } g_free (case_normalized_key); if (count == n) { if (select_one_unselect_others (container, icon)) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } schedule_keyboard_icon_reveal (container, icon); return TRUE; } return FALSE; } static void nemo_icon_container_search_move (GtkWidget *window, NemoIconContainer *container, gboolean up) { gboolean ret; gint len; const gchar *text; text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry)); g_assert (text != NULL); if (container->details->selected_iter == 0) { return; } if (up && container->details->selected_iter == 1) { return; } len = strlen (text); if (len < 1) { return; } /* search */ unselect_all (container); ret = nemo_icon_container_search_iter (container, text, up?((container->details->selected_iter) - 1):((container->details->selected_iter + 1))); if (ret) { /* found */ container->details->selected_iter += up?(-1):(1); } else { /* return to old iter */ nemo_icon_container_search_iter (container, text, container->details->selected_iter); } } static gboolean nemo_icon_container_search_scroll_event (GtkWidget *widget, GdkEventScroll *event, NemoIconContainer *container) { gboolean retval = FALSE; if (event->direction == GDK_SCROLL_UP) { nemo_icon_container_search_move (widget, container, TRUE); retval = TRUE; } else if (event->direction == GDK_SCROLL_DOWN) { nemo_icon_container_search_move (widget, container, FALSE); retval = TRUE; } reset_search_entry_timeout (container); return retval; } static gboolean nemo_icon_container_search_key_press_event (GtkWidget *widget, GdkEventKey *event, NemoIconContainer *container) { gboolean retval = FALSE; g_assert (GTK_IS_WIDGET (widget)); g_assert (NEMO_IS_ICON_CONTAINER (container)); /* close window and cancel the search */ if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Tab) { nemo_icon_container_search_dialog_hide (widget, container); return TRUE; } /* close window and activate alternate */ if (event->keyval == GDK_KEY_Return && event->state & GDK_SHIFT_MASK) { nemo_icon_container_search_dialog_hide (widget, container); activate_selected_items_alternate (container, NULL); return TRUE; } /* select previous matching iter */ if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) { nemo_icon_container_search_move (widget, container, TRUE); retval = TRUE; } if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) { nemo_icon_container_search_move (widget, container, TRUE); retval = TRUE; } /* select next matching iter */ if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) { nemo_icon_container_search_move (widget, container, FALSE); retval = TRUE; } if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK) && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) { nemo_icon_container_search_move (widget, container, FALSE); retval = TRUE; } reset_search_entry_timeout (container); return retval; } static void nemo_icon_container_search_init (GtkWidget *entry, NemoIconContainer *container) { gint ret; gint len; const gchar *text; g_assert (GTK_IS_ENTRY (entry)); g_assert (NEMO_IS_ICON_CONTAINER (container)); text = gtk_entry_get_text (GTK_ENTRY (entry)); len = strlen (text); /* search */ unselect_all (container); reset_search_entry_timeout (container); if (len < 1) { return; } ret = nemo_icon_container_search_iter (container, text, 1); if (ret) { container->details->selected_iter = 1; } } static void nemo_icon_container_ensure_interactive_directory (NemoIconContainer *container) { GtkWidget *frame, *vbox; if (container->details->search_window != NULL) { return; } container->details->search_window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_modal (GTK_WINDOW (container->details->search_window), TRUE); gtk_window_set_type_hint (GTK_WINDOW (container->details->search_window), GDK_WINDOW_TYPE_HINT_COMBO); g_signal_connect (container->details->search_window, "delete_event", G_CALLBACK (nemo_icon_container_search_delete_event), container); g_signal_connect (container->details->search_window, "key_press_event", G_CALLBACK (nemo_icon_container_search_key_press_event), container); g_signal_connect (container->details->search_window, "button_press_event", G_CALLBACK (nemo_icon_container_search_button_press_event), container); g_signal_connect (container->details->search_window, "scroll_event", G_CALLBACK (nemo_icon_container_search_scroll_event), container); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_widget_show (frame); gtk_container_add (GTK_CONTAINER (container->details->search_window), frame); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); /* add entry */ container->details->search_entry = gtk_entry_new (); gtk_widget_show (container->details->search_entry); g_signal_connect (container->details->search_entry, "populate-popup", G_CALLBACK (nemo_icon_container_search_populate_popup), container); g_signal_connect (container->details->search_entry, "activate", G_CALLBACK (nemo_icon_container_search_activate), container); g_signal_connect (container->details->search_entry, "preedit-changed", G_CALLBACK (nemo_icon_container_search_preedit_changed), container); g_signal_connect (container->details->search_entry, "button-press-event", G_CALLBACK (nemo_icon_container_search_entry_button_press_event), container); gtk_container_add (GTK_CONTAINER (vbox), container->details->search_entry); gtk_widget_realize (container->details->search_entry); } /* Pops up the interactive search entry. If keybinding is TRUE then the user * started this by typing the start_interactive_search keybinding. Otherwise, it came from */ static gboolean nemo_icon_container_start_interactive_search (NemoIconContainer *container) { /* We only start interactive search if we have focus. If one of our * children have focus, we don't want to start the search. */ GtkWidgetClass *entry_parent_class; if (container->details->search_window != NULL && gtk_widget_get_visible (container->details->search_window)) { return TRUE; } if (!gtk_widget_has_focus (GTK_WIDGET (container))) { return FALSE; } nemo_icon_container_ensure_interactive_directory (container); /* done, show it */ nemo_icon_container_search_position_func (container, container->details->search_window); gtk_widget_show (container->details->search_window); if (container->details->search_entry_changed_id == 0) { container->details->search_entry_changed_id = g_signal_connect (container->details->search_entry, "changed", G_CALLBACK (nemo_icon_container_search_init), container); } /* Grab focus will select all the text. We don't want that to happen, so we * call the parent instance and bypass the selection change. This is probably * really non-kosher. */ entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (container->details->search_entry)); (entry_parent_class->grab_focus) (container->details->search_entry); /* send focus-in event */ send_focus_change (container->details->search_entry, TRUE); /* search first matching iter */ nemo_icon_container_search_init (container->details->search_entry, container); return TRUE; } static gboolean handle_popups (NemoIconContainer *container, GdkEventKey *event, const char *signal) { GdkEventButton button_event = { 0 }; /* ensure we clear the drag state before showing the menu */ clear_drag_state (container); g_signal_emit_by_name (container, signal, &button_event); return TRUE; } static int key_press_event (GtkWidget *widget, GdkEventKey *event) { NemoIconContainer *container; gboolean handled; container = NEMO_ICON_CONTAINER (widget); handled = FALSE; if (is_renaming (container) || is_renaming_pending (container)) { switch (event->keyval) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: nemo_icon_container_end_renaming_mode (container, TRUE); handled = TRUE; break; case GDK_KEY_Escape: nemo_icon_container_end_renaming_mode (container, FALSE); handled = TRUE; break; default: break; } } else if (container->details->search_window != NULL && gtk_widget_get_visible (container->details->search_window)) { /* Workaround for BGO #662591, where container is still focused * although we're in search mode. Forward events to * search_entry, where they belong. */ GdkEvent *new_event = gdk_event_copy ((GdkEvent *) event); GdkWindow *window = ((GdkEventKey *) new_event)->window; ((GdkEventKey *) new_event)->window = gtk_widget_get_window (container->details->search_entry); handled = gtk_widget_event (container->details->search_window, new_event); ((GdkEventKey *) new_event)->window = window; gdk_event_free(new_event); } else { switch (event->keyval) { case GDK_KEY_Home: case GDK_KEY_KP_Home: keyboard_home (container, event); handled = TRUE; break; case GDK_KEY_End: case GDK_KEY_KP_End: keyboard_end (container, event); handled = TRUE; break; case GDK_KEY_Left: case GDK_KEY_KP_Left: /* Don't eat Alt-Left, as that is used for history browsing */ if ((event->state & GDK_MOD1_MASK) == 0) { keyboard_left (container, event); handled = TRUE; } break; case GDK_KEY_Up: case GDK_KEY_KP_Up: /* Don't eat Alt-Up, as that is used for alt-shift-Up */ if ((event->state & GDK_MOD1_MASK) == 0) { keyboard_up (container, event); handled = TRUE; } break; case GDK_KEY_Right: case GDK_KEY_KP_Right: /* Don't eat Alt-Right, as that is used for history browsing */ if ((event->state & GDK_MOD1_MASK) == 0) { keyboard_right (container, event); handled = TRUE; } break; case GDK_KEY_Down: case GDK_KEY_KP_Down: /* Don't eat Alt-Down, as that is used for Open */ if ((event->state & GDK_MOD1_MASK) == 0) { keyboard_down (container, event); handled = TRUE; } break; case GDK_KEY_space: keyboard_space (container, event); handled = TRUE; break; #ifndef TAB_NAVIGATION_DISABLED case GDK_KEY_Tab: case GDK_KEY_ISO_Left_Tab: select_previous_or_next_icon (container, (event->state & GDK_SHIFT_MASK) == 0, event); handled = TRUE; break; #endif case GDK_KEY_Return: case GDK_KEY_KP_Enter: if ((event->state & GDK_SHIFT_MASK) != 0) { activate_selected_items_alternate (container, NULL); } else { activate_selected_items (container); } handled = TRUE; break; case GDK_KEY_Escape: handled = undo_stretching (container); break; case GDK_KEY_plus: case GDK_KEY_minus: case GDK_KEY_equal: case GDK_KEY_KP_Add: case GDK_KEY_KP_Subtract: case GDK_KEY_0: case GDK_KEY_KP_0: if (event->state & GDK_CONTROL_MASK) { handled = keyboard_stretching (container, event); } break; case GDK_KEY_F10: /* handle Ctrl+F10 because we want to display the * background popup even if something is selected. * The other cases are handled by popup_menu(). */ if (event->state & GDK_CONTROL_MASK) { handled = handle_popups (container, event, "context_click_background"); } break; case GDK_KEY_v: /* Eat Control + v to not enable type ahead */ if ((event->state & GDK_CONTROL_MASK) != 0) { handled = TRUE; } break; default: break; } } if (!handled) { handled = GTK_WIDGET_CLASS (nemo_icon_container_parent_class)->key_press_event (widget, event); } /* We pass the event to the search_entry. If its text changes, then we * start the typeahead find capabilities. * Copied from NemoIconContainer */ if (!handled && event->keyval != GDK_KEY_asciitilde && event->keyval != GDK_KEY_KP_Divide && event->keyval != GDK_KEY_slash /* don't steal slash key events, used for "go to" */ && event->keyval != GDK_KEY_BackSpace && event->keyval != GDK_KEY_Delete) { GdkEvent *new_event; GdkWindow *window; char *old_text; const char *new_text; gboolean retval; gboolean text_modified; gulong popup_menu_id; nemo_icon_container_ensure_interactive_directory (container); /* Make a copy of the current text */ old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (container->details->search_entry))); new_event = gdk_event_copy ((GdkEvent *) event); window = ((GdkEventKey *) new_event)->window; ((GdkEventKey *) new_event)->window = gtk_widget_get_window (container->details->search_entry); gtk_widget_realize (container->details->search_window); popup_menu_id = g_signal_connect (container->details->search_entry, "popup_menu", G_CALLBACK (gtk_true), NULL); gtk_widget_show (container->details->search_window); /* Send the event to the window. If the preedit_changed signal is emitted * during this event, we will set priv->imcontext_changed */ container->details->imcontext_changed = FALSE; retval = gtk_widget_event (container->details->search_entry, new_event); gtk_widget_hide (container->details->search_window); g_signal_handler_disconnect (container->details->search_entry, popup_menu_id); /* We check to make sure that the entry tried to handle the text, and that * the text has changed. */ new_text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry)); text_modified = strcmp (old_text, new_text) != 0; g_free (old_text); if (container->details->imcontext_changed || /* we're in a preedit */ (retval && text_modified)) { /* ...or the text was modified */ if (nemo_icon_container_start_interactive_search (container)) { gtk_widget_grab_focus (GTK_WIDGET (container)); return TRUE; } else { gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), ""); return FALSE; } } ((GdkEventKey *) new_event)->window = window; gdk_event_free (new_event); } return handled; } static gboolean popup_menu (GtkWidget *widget) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (widget); if (has_selection (container)) { handle_popups (container, NULL, "context_click_selection"); } else { handle_popups (container, NULL, "context_click_background"); } return TRUE; } static void draw_canvas_background (EelCanvas *canvas, cairo_t *cr) { /* Don't chain up to the parent to avoid clearing and redrawing. * This is overridden by nemo-icon-view-grid-container. */ return; } static AtkObject * get_accessible (GtkWidget *widget) { AtkObject *accessible; if ((accessible = eel_accessibility_get_atk_object (widget))) { return accessible; } accessible = g_object_new (nemo_icon_container_accessible_get_type (), NULL); return eel_accessibility_set_atk_object_return (widget, accessible); } static void grab_notify_cb (GtkWidget *widget, gboolean was_grabbed) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (widget); if (container->details->rubberband_info.active && !was_grabbed) { /* we got a (un)grab-notify during rubberband. * This happens when a new modal dialog shows * up (e.g. authentication or an error). Stop * the rubberbanding so that we can handle the * dialog. */ stop_rubberbanding (container, GDK_CURRENT_TIME); } } static void text_ellipsis_limit_changed_container_callback (gpointer callback_data) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (callback_data); invalidate_label_sizes (container); schedule_redo_layout (container); } static void real_lay_down_icons (NemoIconContainer *container, GList *icons, double start_y) { g_assert_not_reached (); } static void real_icon_set_position (NemoIconContainer *container, NemoIcon *icon, double x, double y) { g_assert_not_reached (); } static void real_move_icon (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position) { g_assert_not_reached (); } static void real_update_icon (NemoIconContainer *container, NemoIcon *icon) { g_assert_not_reached (); } static void real_align_icons (NemoIconContainer *container) { g_assert_not_reached (); } static void real_icon_get_bounding_box (NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage) { g_assert_not_reached (); } static void real_set_zoom_level (NemoIconContainer *container, gint new_level) { g_assert_not_reached (); } /* Initialization. */ static void nemo_icon_container_class_init (NemoIconContainerClass *class) { GtkWidgetClass *widget_class; EelCanvasClass *canvas_class; G_OBJECT_CLASS (class)->finalize = finalize; class->lay_down_icons = real_lay_down_icons; class->icon_set_position = real_icon_set_position; class->move_icon = real_move_icon; class->update_icon = real_update_icon; class->align_icons = real_align_icons; class->finish_adding_new_icons = NULL; class->icon_get_bounding_box = real_icon_get_bounding_box; class->set_zoom_level = real_set_zoom_level; class->is_grid_container = FALSE; /* Signals. */ signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, selection_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[BUTTON_PRESS] = g_signal_new ("button_press", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, button_press), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT); signals[ACTIVATE] = g_signal_new ("activate", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, activate), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ACTIVATE_ALTERNATE] = g_signal_new ("activate_alternate", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, activate_alternate), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ACTIVATE_PREVIEWER] = g_signal_new ("activate_previewer", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, activate_previewer), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); signals[CONTEXT_CLICK_SELECTION] = g_signal_new ("context_click_selection", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, context_click_selection), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[CONTEXT_CLICK_BACKGROUND] = g_signal_new ("context_click_background", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, context_click_background), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[MIDDLE_CLICK] = g_signal_new ("middle_click", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, middle_click), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ICON_POSITION_CHANGED] = g_signal_new ("icon_position_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_position_changed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); signals[ICON_STRETCH_STARTED] = g_signal_new ("icon_stretch_started", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_stretch_started), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ICON_STRETCH_ENDED] = g_signal_new ("icon_stretch_ended", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_stretch_ended), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ICON_RENAME_STARTED] = g_signal_new ("icon_rename_started", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_rename_started), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ICON_RENAME_ENDED] = g_signal_new ("icon_rename_ended", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_rename_ended), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_STRING); signals[GET_ICON_URI] = g_signal_new ("get_icon_uri", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, get_icon_uri), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_STRING, 1, G_TYPE_POINTER); signals[GET_ICON_DROP_TARGET_URI] = g_signal_new ("get_icon_drop_target_uri", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, get_icon_drop_target_uri), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_STRING, 1, G_TYPE_POINTER); signals[MOVE_COPY_ITEMS] = g_signal_new ("move_copy_items", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, move_copy_items), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 6, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_NETSCAPE_URL] = g_signal_new ("handle_netscape_url", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, handle_netscape_url), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_URI_LIST] = g_signal_new ("handle_uri_list", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, handle_uri_list), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_TEXT] = g_signal_new ("handle_text", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, handle_text), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_RAW] = g_signal_new ("handle_raw", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, handle_raw), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 7, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[GET_CONTAINER_URI] = g_signal_new ("get_container_uri", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, get_container_uri), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_STRING, 0); signals[CAN_ACCEPT_ITEM] = g_signal_new ("can_accept_item", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, can_accept_item), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_INT, 2, G_TYPE_POINTER, G_TYPE_STRING); signals[GET_STORED_LAYOUT_TIMESTAMP] = g_signal_new ("get_stored_layout_timestamp", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, get_stored_layout_timestamp), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2, G_TYPE_POINTER, G_TYPE_POINTER); signals[STORE_LAYOUT_TIMESTAMP] = g_signal_new ("store_layout_timestamp", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, store_layout_timestamp), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2, G_TYPE_POINTER, G_TYPE_POINTER); signals[LAYOUT_CHANGED] = g_signal_new ("layout_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, layout_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[BAND_SELECT_STARTED] = g_signal_new ("band_select_started", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, band_select_started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[BAND_SELECT_ENDED] = g_signal_new ("band_select_ended", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, band_select_ended), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[ICON_ADDED] = g_signal_new ("icon_added", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_added), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[ICON_REMOVED] = g_signal_new ("icon_removed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, icon_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[CLEARED] = g_signal_new ("cleared", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoIconContainerClass, cleared), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[GET_TOOLTIP_TEXT] = g_signal_new ("get-tooltip-text", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_STRING, 1, G_TYPE_POINTER); /* GtkWidget class. */ widget_class = GTK_WIDGET_CLASS (class); widget_class->destroy = destroy; widget_class->size_allocate = size_allocate; widget_class->get_request_mode = get_request_mode; widget_class->get_preferred_width = get_prefered_width; widget_class->get_preferred_height = get_prefered_height; widget_class->realize = realize; widget_class->unrealize = unrealize; widget_class->button_press_event = button_press_event; widget_class->button_release_event = button_release_event; widget_class->motion_notify_event = motion_notify_event; widget_class->key_press_event = key_press_event; widget_class->popup_menu = popup_menu; widget_class->get_accessible = get_accessible; widget_class->style_updated = style_updated; widget_class->grab_notify = grab_notify_cb; canvas_class = EEL_CANVAS_CLASS (class); canvas_class->draw_background = draw_canvas_background; gtk_widget_class_install_style_property (widget_class, g_param_spec_boolean ("activate_prelight_icon_label", "Activate Prelight Icon Label", "Whether icon labels should make use of its prelight color in prelight state", TRUE, G_PARAM_READABLE)); } static void update_selected (NemoIconContainer *container) { GList *node; NemoIcon *icon; for (node = container->details->icons; node != NULL; node = node->next) { icon = node->data; if (icon->is_selected) { eel_canvas_item_request_update (EEL_CANVAS_ITEM (icon->item)); } } } static gboolean handle_focus_in_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { update_selected (NEMO_ICON_CONTAINER (widget)); return FALSE; } static gboolean handle_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { /* End renaming and commit change. */ nemo_icon_container_end_renaming_mode (NEMO_ICON_CONTAINER (widget), TRUE); update_selected (NEMO_ICON_CONTAINER (widget)); return FALSE; } static void nemo_icon_container_init (NemoIconContainer *container) { NemoIconContainerDetails *details; details = g_new0 (NemoIconContainerDetails, 1); details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal); details->layout_timestamp = UNDEFINED_TIME; details->zoom_level = NEMO_ZOOM_LEVEL_STANDARD; details->font_size_table[NEMO_ZOOM_LEVEL_SMALLEST] = -2 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_SMALLER] = -2 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_SMALL] = -0 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_STANDARD] = 0 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_LARGE] = 0 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_LARGER] = 0 * PANGO_SCALE; details->font_size_table[NEMO_ZOOM_LEVEL_LARGEST] = 0 * PANGO_SCALE; details->view_constants = g_slice_new0 (NemoViewLayoutConstants); container->details = details; g_signal_connect (container, "focus-in-event", G_CALLBACK (handle_focus_in_event), NULL); g_signal_connect (container, "focus-out-event", G_CALLBACK (handle_focus_out_event), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIPS_DESKTOP, G_CALLBACK (tooltip_prefs_changed_callback), container); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIPS_ICON_VIEW, G_CALLBACK (tooltip_prefs_changed_callback), container); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_FILE_TYPE, G_CALLBACK (tooltip_prefs_changed_callback), container); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_MOD_DATE, G_CALLBACK (tooltip_prefs_changed_callback), container); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_ACCESS_DATE, G_CALLBACK (tooltip_prefs_changed_callback), container); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_FULL_PATH, G_CALLBACK (tooltip_prefs_changed_callback), container); container->details->show_desktop_tooltips = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIPS_DESKTOP); container->details->show_icon_view_tooltips = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIPS_ICON_VIEW); container->details->tooltip_flags = nemo_global_preferences_get_tooltip_flags (); details->skip_rename_on_release = FALSE; details->dnd_grid = NULL; details->current_selection_count = -1; details->renaming_allocation_count = 0; details->h_adjust = 100; details->v_adjust = 100; } typedef struct { NemoIconContainer *container; GdkEventButton *event; } ContextMenuParameters; static gboolean handle_icon_double_click (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { NemoIconContainerDetails *details; if (event->button != DRAG_BUTTON) { return FALSE; } details = container->details; if (!details->single_click_mode && clicked_within_double_click_interval (container) && details->double_click_icon[0] == details->double_click_icon[1] && details->double_click_button[0] == details->double_click_button[1]) { if (!button_event_modifies_selection (event)) { activate_selected_items (container); return TRUE; } else if ((event->state & GDK_CONTROL_MASK) == 0 && (event->state & GDK_SHIFT_MASK) != 0) { activate_selected_items_alternate (container, icon); return TRUE; } } return FALSE; } static gboolean handle_icon_slow_two_click (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { NemoIconContainerDetails *details; NemoFile *file = NEMO_FILE (icon->data); if (!nemo_file_can_rename (file)) return FALSE; if (event->button != DRAG_BUTTON) { return FALSE; } details = container->details; if (!details->click_to_rename) return FALSE; GList *selection = nemo_icon_container_get_selection (container); gint selected_count = g_list_length (selection); g_list_free (selection); if (selected_count != 1) return FALSE; if (!details->single_click_mode && clicked_within_slow_click_interval_on_text (container, icon, event) && details->double_click_icon[0] == details->double_click_icon[1] && details->double_click_button[0] == details->double_click_button[1]) { if (!button_event_modifies_selection (event)) { return TRUE; } } return FALSE; } /* NemoIcon event handling. */ /* Conceptually, pressing button 1 together with CTRL or SHIFT toggles * selection of a single icon without affecting the other icons; * without CTRL or SHIFT, it selects a single icon and un-selects all * the other icons. But in this latter case, the de-selection should * only happen when the button is released if the icon is already * selected, because the user might select multiple icons and drag all * of them by doing a simple click-drag. */ static gboolean handle_icon_button_press (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { NemoIconContainerDetails *details; details = container->details; details->skip_rename_on_release = FALSE; if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { return TRUE; } if (event->button != DRAG_BUTTON && event->button != CONTEXTUAL_MENU_BUTTON && event->button != DRAG_MENU_BUTTON) { return TRUE; } if ((event->button == DRAG_BUTTON) && event->type == GDK_BUTTON_PRESS) { /* The next double click has to be on this icon */ details->double_click_icon[1] = details->double_click_icon[0]; details->double_click_icon[0] = icon; details->double_click_button[1] = details->double_click_button[0]; details->double_click_button[0] = event->button; } if (handle_icon_double_click (container, icon, event)) { /* Double clicking does not trigger a D&D action. */ details->drag_button = 0; details->drag_icon = NULL; return TRUE; } if (event->button == DRAG_BUTTON || event->button == DRAG_MENU_BUTTON) { details->drag_button = event->button; details->drag_icon = icon; details->drag_x = event->x; details->drag_y = event->y; details->drag_state = DRAG_STATE_MOVE_OR_COPY; details->drag_started = FALSE; /* Check to see if this is a click on the stretch handles. * If so, it won't modify the selection. */ if (icon == container->details->stretch_icon) { if (start_stretching (container)) { return TRUE; } } } /* Modify the selection as appropriate. Selection is modified * the same way for contextual menu as it would be without. */ details->icon_selected_on_button_down = icon->is_selected; GList *sel = nemo_icon_container_get_selected_icons (container); details->skip_rename_on_release = g_list_length (sel) > 1; g_list_free (sel); if ((event->button == DRAG_BUTTON || event->button == MIDDLE_BUTTON) && (event->state & GDK_SHIFT_MASK) != 0) { NemoIcon *start_icon; start_icon = details->range_selection_base_icon; if (start_icon == NULL || !start_icon->is_selected) { start_icon = icon; details->range_selection_base_icon = icon; } if (select_range (container, start_icon, icon, (event->state & GDK_CONTROL_MASK) == 0)) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } else if (!details->icon_selected_on_button_down) { details->range_selection_base_icon = icon; if (button_event_modifies_selection (event)) { icon_toggle_selected (container, icon); g_signal_emit (container, signals[SELECTION_CHANGED], 0); } else { select_one_unselect_others (container, icon); g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } if (event->button == CONTEXTUAL_MENU_BUTTON) { clear_drag_state (container); g_signal_emit (container, signals[CONTEXT_CLICK_SELECTION], 0, event); } return TRUE; } static int item_event_callback (EelCanvasItem *item, GdkEvent *event, gpointer data) { NemoIconContainer *container; NemoIcon *icon; container = NEMO_ICON_CONTAINER (data); icon = NEMO_ICON_CANVAS_ITEM (item)->user_data; g_assert (icon != NULL); if (event->type == GDK_BUTTON_PRESS) { if (handle_icon_button_press (container, icon, &event->button)) { /* Stop the event from being passed along further. Returning * TRUE ain't enough. */ return TRUE; } } return FALSE; } GtkWidget * nemo_icon_container_new (void) { return gtk_widget_new (NEMO_TYPE_ICON_CONTAINER, NULL); } /* Clear all of the icons in the container. */ void nemo_icon_container_clear (NemoIconContainer *container) { NemoIconContainerDetails *details; GList *p; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); details = container->details; details->layout_timestamp = UNDEFINED_TIME; details->store_layout_timestamps_when_finishing_new_icons = FALSE; if (details->icons == NULL) { return; } nemo_icon_container_end_renaming_mode (container, TRUE); clear_keyboard_focus (container); clear_keyboard_rubberband_start (container); unschedule_keyboard_icon_reveal (container); set_pending_icon_to_reveal (container, NULL); details->stretch_icon = NULL; details->drop_target = NULL; for (p = details->icons; p != NULL; p = p->next) { icon_free (p->data); } g_list_free (details->icons); details->icons = NULL; g_list_free (details->new_icons); details->new_icons = NULL; g_hash_table_destroy (details->icon_set); details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal); } gboolean nemo_icon_container_is_empty (NemoIconContainer *container) { return container->details->icons == NULL; } NemoIconData * nemo_icon_container_get_first_visible_icon (NemoIconContainer *container) { GList *l; NemoIcon *icon, *best_icon; double x, y; double x1, y1, x2, y2; double *pos, best_pos; double hadj_v, vadj_v, h_page_size; gboolean better_icon; gboolean compare_lt; hadj_v = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); vadj_v = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))); h_page_size = gtk_adjustment_get_page_size (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); if (nemo_icon_container_is_layout_rtl (container)) { x = hadj_v + h_page_size - GET_VIEW_CONSTANT (container, icon_pad_left) - 1; y = vadj_v; } else { x = hadj_v; y = vadj_v; } eel_canvas_c2w (EEL_CANVAS (container), x, y, &x, &y); l = container->details->icons; best_icon = NULL; best_pos = 0; while (l != NULL) { icon = l->data; if (nemo_icon_container_icon_is_positioned (icon)) { eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item), &x1, &y1, &x2, &y2); compare_lt = FALSE; if (nemo_icon_container_is_layout_vertical (container)) { pos = &x1; if (nemo_icon_container_is_layout_rtl (container)) { compare_lt = TRUE; better_icon = x1 < x + GET_VIEW_CONSTANT (container, icon_pad_left); } else { better_icon = x2 > x + GET_VIEW_CONSTANT (container, icon_pad_left); } } else { pos = &y1; better_icon = y2 > y + GET_VIEW_CONSTANT (container, icon_pad_top); } if (better_icon) { if (best_icon == NULL) { better_icon = TRUE; } else if (compare_lt) { better_icon = best_pos < *pos; } else { better_icon = best_pos > *pos; } if (better_icon) { best_icon = icon; best_pos = *pos; } } } l = l->next; } return best_icon ? best_icon->data : NULL; } /* puts the icon at the top of the screen */ void nemo_icon_container_scroll_to_icon (NemoIconContainer *container, NemoIconData *data) { GList *l; NemoIcon *icon; GtkAdjustment *hadj, *vadj; EelIRect bounds; GtkAllocation allocation; hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); /* We need to force a relayout now if there are updates queued * since we need the final positions */ nemo_icon_container_layout_now (container); l = container->details->icons; while (l != NULL) { icon = l->data; if (icon->data == data && nemo_icon_container_icon_is_positioned (icon)) { if (nemo_icon_container_is_auto_layout (container)) { /* ensure that we reveal the entire row/column */ icon_get_row_and_column_bounds (container, icon, &bounds, TRUE); } else { item_get_canvas_bounds (container, EEL_CANVAS_ITEM (icon->item), &bounds, TRUE); } if (nemo_icon_container_is_layout_vertical (container)) { if (nemo_icon_container_is_layout_rtl (container)) { gtk_adjustment_set_value (hadj, bounds.x1 - allocation.width); } else { gtk_adjustment_set_value (hadj, bounds.x0); } } else { gtk_adjustment_set_value (vadj, bounds.y0); } } l = l->next; } } /* Call a function for all the icons. */ typedef struct { NemoIconCallback callback; gpointer callback_data; } CallbackAndData; static void call_icon_callback (gpointer data, gpointer callback_data) { NemoIcon *icon; CallbackAndData *callback_and_data; icon = data; callback_and_data = callback_data; (* callback_and_data->callback) (icon->data, callback_and_data->callback_data); } void nemo_icon_container_for_each (NemoIconContainer *container, NemoIconCallback callback, gpointer callback_data) { CallbackAndData callback_and_data; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); callback_and_data.callback = callback; callback_and_data.callback_data = callback_data; g_list_foreach (container->details->icons, call_icon_callback, &callback_and_data); } static int selection_changed_at_idle_callback (gpointer data) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (data); g_signal_emit (container, signals[SELECTION_CHANGED], 0); container->details->selection_changed_id = 0; return FALSE; } /* utility routine to remove a single icon from the container */ static void icon_destroy (NemoIconContainer *container, NemoIcon *icon) { NemoIconContainerDetails *details; gboolean was_selected; NemoIcon *icon_to_focus; GList *item; details = container->details; item = g_list_find (details->icons, icon); item = item->next ? item->next : item->prev; icon_to_focus = (item != NULL) ? item->data : NULL; details->icons = g_list_remove (details->icons, icon); details->new_icons = g_list_remove (details->new_icons, icon); g_hash_table_remove (details->icon_set, icon->data); was_selected = icon->is_selected; if (details->keyboard_focus == icon || details->keyboard_focus == NULL) { if (icon_to_focus != NULL) { set_keyboard_focus (container, icon_to_focus); } else { clear_keyboard_focus (container); } } if (details->keyboard_rubberband_start == icon) { clear_keyboard_rubberband_start (container); } if (details->keyboard_icon_to_reveal == icon) { unschedule_keyboard_icon_reveal (container); } if (details->drag_icon == icon) { clear_drag_state (container); } if (details->drop_target == icon) { details->drop_target = NULL; } if (details->range_selection_base_icon == icon) { details->range_selection_base_icon = NULL; } if (details->pending_icon_to_reveal == icon) { set_pending_icon_to_reveal (container, NULL); } if (details->stretch_icon == icon) { details->stretch_icon = NULL; } icon_free (icon); if (was_selected) { /* Coalesce multiple removals causing multiple selection_changed events */ details->selection_changed_id = g_idle_add (selection_changed_at_idle_callback, container); } } /* activate any selected items in the container */ static void activate_selected_items (NemoIconContainer *container) { GList *selection; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); selection = nemo_icon_container_peek_selection (container); if (selection != NULL) { g_signal_emit (container, signals[ACTIVATE], 0, selection); } } static void preview_selected_items (NemoIconContainer *container) { GList *selection; GArray *locations; guint idx; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); selection = nemo_icon_container_peek_selection (container); locations = nemo_icon_container_get_selected_icon_locations (container); for (idx = 0; idx < locations->len; idx++) { GdkPoint *point = &(g_array_index (locations, GdkPoint, idx)); gint scroll_x, scroll_y; eel_canvas_get_scroll_offsets (EEL_CANVAS (container), &scroll_x, &scroll_y); point->x -= scroll_x; point->y -= scroll_y; } if (selection != NULL) { g_signal_emit (container, signals[ACTIVATE_PREVIEWER], 0, selection, locations); } } static void activate_selected_items_alternate (NemoIconContainer *container, NemoIcon *icon) { GList *selection; g_assert (NEMO_IS_ICON_CONTAINER (container)); if (icon != NULL) { selection = g_list_prepend (NULL, icon->data); } else { selection = nemo_icon_container_get_selection (container); } if (selection != NULL) { g_signal_emit (container, signals[ACTIVATE_ALTERNATE], 0, selection); } g_list_free (selection); } NemoIconInfo * nemo_icon_container_get_icon_images (NemoIconContainer *container, NemoIconData *data, int size, gboolean for_drag_accept, gboolean *has_open_window) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->get_icon_images != NULL); return klass->get_icon_images (container, data, size, for_drag_accept, has_open_window); } static void nemo_icon_container_freeze_updates (NemoIconContainer *container) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->freeze_updates != NULL); klass->freeze_updates (container); } static void nemo_icon_container_unfreeze_updates (NemoIconContainer *container) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->unfreeze_updates != NULL); klass->unfreeze_updates (container); } static void nemo_icon_container_prioritize_thumbnailing (NemoIconContainer *container, NemoIcon *icon) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->prioritize_thumbnailing != NULL); klass->prioritize_thumbnailing (container, icon->data); } static void nemo_icon_container_update_visible_icons (NemoIconContainer *container) { GtkAdjustment *vadj, *hadj; double min_y, max_y; double min_x, max_x; double x0, y0, x1, y1; GList *node; NemoIcon *icon; gboolean visible; GtkAllocation allocation; hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); min_x = gtk_adjustment_get_value (hadj); max_x = min_x + allocation.width; min_y = gtk_adjustment_get_value (vadj); max_y = min_y + allocation.height; eel_canvas_c2w (EEL_CANVAS (container), min_x, min_y, &min_x, &min_y); eel_canvas_c2w (EEL_CANVAS (container), max_x, max_y, &max_x, &max_y); /* Do the iteration in reverse to get the render-order from top to * bottom for the prioritized thumbnails. */ for (node = g_list_last (container->details->icons); node != NULL; node = node->prev) { icon = node->data; if (nemo_icon_container_icon_is_positioned (icon)) { eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item), &x0, &y0, &x1, &y1); eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent, &x0, &y0); eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent, &x1, &y1); if (nemo_icon_container_is_layout_vertical (container)) { visible = x1 >= min_x && x0 <= max_x; } else { visible = y1 >= min_y && y0 <= max_y; } if (visible) { nemo_icon_canvas_item_set_is_visible (icon->item, TRUE); nemo_icon_container_prioritize_thumbnailing (container, icon); } else { nemo_icon_canvas_item_set_is_visible (icon->item, FALSE); } } } } static void handle_vadjustment_changed (GtkAdjustment *adjustment, NemoIconContainer *container) { if (!nemo_icon_container_is_layout_vertical (container)) { nemo_icon_container_update_visible_icons (container); } } static void handle_hadjustment_changed (GtkAdjustment *adjustment, NemoIconContainer *container) { if (nemo_icon_container_is_layout_vertical (container)) { nemo_icon_container_update_visible_icons (container); } } static gboolean is_old_or_unknown_icon_data (NemoIconContainer *container, NemoIconData *data) { time_t timestamp; gboolean success; gboolean is_transient; /* Undefined at startup */ if (container->details->layout_timestamp == UNDEFINED_TIME) { return FALSE; } is_transient = NEMO_IS_DESKTOP_ICON_FILE (data) && container->details->keep_aligned; g_signal_emit (container, signals[GET_STORED_LAYOUT_TIMESTAMP], 0, data, ×tamp, &success); return (!success || is_transient || timestamp < container->details->layout_timestamp); } gboolean nemo_icon_container_icon_is_new_for_monitor (NemoIconContainer *container, NemoIcon *icon, gint current_monitor) { if (container->details->auto_layout || !container->details->is_desktop) { return FALSE; } return nemo_file_get_monitor_number (NEMO_FILE (icon->data)) != current_monitor; } /** * nemo_icon_container_add: * @container: A NemoIconContainer * @data: Icon data. * * Add icon to represent @data to container. * Returns FALSE if there was already such an icon. **/ gboolean nemo_icon_container_add (NemoIconContainer *container, NemoIconData *data) { NemoIconContainerDetails *details; NemoIcon *icon; EelCanvasItem *band, *item; g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); g_return_val_if_fail (data != NULL, FALSE); details = container->details; if (g_hash_table_lookup (details->icon_set, data) != NULL) { return FALSE; } /* Create the new icon, including the canvas item. */ icon = g_new0 (NemoIcon, 1); icon->data = data; icon->x = ICON_UNPOSITIONED_VALUE; icon->y = ICON_UNPOSITIONED_VALUE; /* Whether the saved icon position should only be used * if the previous icon position is free. If the position * is occupied, another position near the last one will */ icon->has_lazy_position = is_old_or_unknown_icon_data (container, data); icon->scale = 1.0; icon->item = NEMO_ICON_CANVAS_ITEM (eel_canvas_item_new (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root), nemo_icon_canvas_item_get_type (), "visible", FALSE, NULL)); icon->item->user_data = icon; /* Make sure the icon is under the selection_rectangle */ item = EEL_CANVAS_ITEM (icon->item); band = NEMO_ICON_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle; if (band) { eel_canvas_item_send_behind (item, band); } /* Put it on both lists. */ details->icons = g_list_prepend (details->icons, icon); details->new_icons = g_list_prepend (details->new_icons, icon); g_hash_table_insert (details->icon_set, data, icon); details->needs_resort = TRUE; /* Run an idle function to add the icons. */ schedule_redo_layout (container); return TRUE; } void nemo_icon_container_layout_now (NemoIconContainer *container) { if (container->details->idle_id != 0) { unschedule_redo_layout (container); redo_layout_internal (container); } /* Also need to make sure we're properly resized, for instance * newly added files may trigger a change in the size allocation and * thus toggle scrollbars on */ gtk_container_check_resize (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (container)))); } /** * nemo_icon_container_remove: * @container: A NemoIconContainer. * @data: Icon data. * * Remove the icon with this data. **/ gboolean nemo_icon_container_remove (NemoIconContainer *container, NemoIconData *data) { NemoIcon *icon; g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); g_return_val_if_fail (data != NULL, FALSE); nemo_icon_container_end_renaming_mode (container, FALSE); icon = g_hash_table_lookup (container->details->icon_set, data); if (icon == NULL) { return FALSE; } gtk_widget_set_tooltip_text (GTK_WIDGET (EEL_CANVAS_ITEM (icon->item)->canvas), ""); icon_destroy (container, icon); schedule_redo_layout (container); g_signal_emit (container, signals[ICON_REMOVED], 0, icon); return TRUE; } /** * nemo_icon_container_request_update: * @container: A NemoIconContainer. * @data: Icon data. * * Update the icon with this data. **/ void nemo_icon_container_request_update (NemoIconContainer *container, NemoIconData *data) { NemoIcon *icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (data != NULL); icon = g_hash_table_lookup (container->details->icon_set, data); if (icon != NULL) { nemo_icon_container_update_icon (container, icon); container->details->needs_resort = TRUE; schedule_redo_layout (container); } } /* invalidate the entire labels (i.e. their attributes) for all the icons */ void nemo_icon_container_invalidate_labels (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_canvas_item_invalidate_label (icon->item); } } /* zooming */ NemoZoomLevel nemo_icon_container_get_zoom_level (NemoIconContainer *container) { return container->details->zoom_level; } void nemo_icon_container_set_zoom_level (NemoIconContainer *container, gint new_level) { NEMO_ICON_CONTAINER_GET_CLASS (container)->set_zoom_level (container, new_level); nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } /** * nemo_icon_container_request_update_all: * For each icon, synchronizes the displayed information (image, text) with the * information from the model. * * @container: An icon container. **/ void nemo_icon_container_request_update_all (NemoIconContainer *container) { GList *node; NemoIcon *icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); for (node = container->details->icons; node != NULL; node = node->next) { icon = node->data; nemo_icon_container_update_icon (container, icon); } container->details->needs_resort = TRUE; nemo_icon_container_redo_layout (container); gtk_widget_queue_draw (GTK_WIDGET (container)); } /** * nemo_icon_container_reveal: * Change scroll position as necessary to reveal the specified item. */ void nemo_icon_container_reveal (NemoIconContainer *container, NemoIconData *data) { NemoIcon *icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (data != NULL); icon = g_hash_table_lookup (container->details->icon_set, data); if (icon != NULL) { reveal_icon (container, icon); } } GList * nemo_icon_container_get_real_selection (NemoIconContainer *container) { GList *list, *p; list = NULL; for (p = container->details->icons; p != NULL; p = p->next) { NemoIcon *icon; icon = p->data; if (icon->is_selected) { list = g_list_prepend (list, icon->data); } } return g_list_reverse (list); } /** * nemo_icon_container_get_selection: * @container: An icon container. * * Get a list of the icons currently selected in @container. * * Return value: A GList of the programmer-specified data associated to each * selected icon, or NULL if no icon is selected. The caller is expected to * free the list when it is not needed anymore. **/ GList * nemo_icon_container_get_selection (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), NULL); nemo_icon_container_update_selection (container); return g_list_copy (container->details->current_selection); } /** * nemo_icon_container_peek_selection: * @container: An icon container. * * Get an exiting list of the icons currently selected in @container. * * Return value: A GList of the programmer-specified data associated to each * selected icon, or NULL if no icon is selected. This list belongs to the * NemoIconContainer and should not be freed. **/ GList * nemo_icon_container_peek_selection (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), NULL); if (container->details->current_selection_count == -1) { nemo_icon_container_update_selection (container); } return container->details->current_selection; } gint nemo_icon_container_get_selection_count (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), 0); if (container->details->current_selection_count == -1) { nemo_icon_container_update_selection (container); } return container->details->current_selection_count; } static GList * nemo_icon_container_get_selected_icons (NemoIconContainer *container) { GList *list, *p; g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), NULL); list = NULL; for (p = container->details->icons; p != NULL; p = p->next) { NemoIcon *icon; icon = p->data; if (icon->is_selected) { list = g_list_prepend (list, icon); } } return g_list_reverse (list); } /** * nemo_icon_container_invert_selection: * @container: An icon container. * * Inverts the selection in @container. * **/ void nemo_icon_container_invert_selection (NemoIconContainer *container) { GList *p; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); for (p = container->details->icons; p != NULL; p = p->next) { NemoIcon *icon; icon = p->data; icon_toggle_selected (container, icon); } g_signal_emit (container, signals[SELECTION_CHANGED], 0); } /* Returns an array of GdkPoints of locations of the icons. */ static GArray * nemo_icon_container_get_icon_locations (NemoIconContainer *container, GList *icons) { GArray *result; GList *node; int index; result = g_array_new (FALSE, TRUE, sizeof (GdkPoint)); result = g_array_set_size (result, g_list_length (icons)); for (index = 0, node = icons; node != NULL; index++, node = node->next) { g_array_index (result, GdkPoint, index).x = ((NemoIcon *)node->data)->x; g_array_index (result, GdkPoint, index).y = ((NemoIcon *)node->data)->y; } return result; } /** * nemo_icon_container_get_selected_icon_locations: * @container: An icon container widget. * * Returns an array of GdkPoints of locations of the selected icons. **/ GArray * nemo_icon_container_get_selected_icon_locations (NemoIconContainer *container) { GArray *result; GList *icons; g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), NULL); icons = nemo_icon_container_get_selected_icons (container); result = nemo_icon_container_get_icon_locations (container, icons); g_list_free (icons); return result; } /** * nemo_icon_container_select_all: * @container: An icon container widget. * * Select all the icons in @container at once. **/ void nemo_icon_container_select_all (NemoIconContainer *container) { gboolean selection_changed; GList *p; NemoIcon *icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); selection_changed = FALSE; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; selection_changed |= icon_set_selected (container, icon, TRUE); } if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } /** * nemo_icon_container_set_selection: * @container: An icon container widget. * @selection: A list of NemoIconData *. * * Set the selection to exactly the icons in @container which have * programmer data matching one of the items in @selection. **/ void nemo_icon_container_set_selection (NemoIconContainer *container, GList *selection) { gboolean selection_changed; GHashTable *hash; GList *p; gboolean res; NemoIcon *icon, *selected_icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); selection_changed = FALSE; selected_icon = NULL; hash = g_hash_table_new (NULL, NULL); for (p = selection; p != NULL; p = p->next) { g_hash_table_insert (hash, p->data, p->data); } for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; res = icon_set_selected (container, icon, g_hash_table_lookup (hash, icon->data) != NULL); selection_changed |= res; if (res) { selected_icon = icon; } } g_hash_table_destroy (hash); if (selection_changed) { /* if only one item has been selected, use it as range * selection base (cf. handle_icon_button_press) */ if (g_list_length (selection) == 1) { container->details->range_selection_base_icon = selected_icon; } g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } /** * nemo_icon_container_select_list_unselect_others. * @container: An icon container widget. * @selection: A list of NemoIcon *. * * Set the selection to exactly the icons in @selection. **/ void nemo_icon_container_select_list_unselect_others (NemoIconContainer *container, GList *selection) { gboolean selection_changed; GHashTable *hash; GList *p; NemoIcon *icon; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); selection_changed = FALSE; hash = g_hash_table_new (NULL, NULL); for (p = selection; p != NULL; p = p->next) { g_hash_table_insert (hash, p->data, p->data); } for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; selection_changed |= icon_set_selected (container, icon, g_hash_table_lookup (hash, icon) != NULL); } g_hash_table_destroy (hash); if (selection_changed) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } /** * nemo_icon_container_unselect_all: * @container: An icon container widget. * * Deselect all the icons in @container. **/ void nemo_icon_container_unselect_all (NemoIconContainer *container) { if (unselect_all (container)) { g_signal_emit (container, signals[SELECTION_CHANGED], 0); } } /** * nemo_icon_container_get_icon_by_uri: * @container: An icon container widget. * @uri: The uri of an icon to find. * * Locate an icon, given the URI. The URI must match exactly. * Later we may have to have some way of figuring out if the * URI specifies the same object that does not require an exact match. **/ NemoIcon * nemo_icon_container_get_icon_by_uri (NemoIconContainer *container, const char *uri) { NemoIconContainerDetails *details; GList *p; /* Eventually, we must avoid searching the entire icon list, but it's OK for now. A hash table mapping uri to icon is one possibility. */ details = container->details; for (p = details->icons; p != NULL; p = p->next) { NemoIcon *icon; char *icon_uri; gboolean is_match; icon = p->data; icon_uri = nemo_icon_container_get_icon_uri (container, icon); is_match = strcmp (uri, icon_uri) == 0; g_free (icon_uri); if (is_match) { return icon; } } return NULL; } static NemoIcon * get_nth_selected_icon (NemoIconContainer *container, int index) { GList *p; NemoIcon *icon; int selection_count; g_assert (index > 0); /* Find the nth selected icon. */ selection_count = 0; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (icon->is_selected) { if (++selection_count == index) { return icon; } } } return NULL; } static NemoIcon * get_first_selected_icon (NemoIconContainer *container) { return get_nth_selected_icon (container, 1); } static gboolean has_multiple_selection (NemoIconContainer *container) { return get_nth_selected_icon (container, 2) != NULL; } static gboolean all_selected (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (!icon->is_selected) { return FALSE; } } return TRUE; } static gboolean has_selection (NemoIconContainer *container) { return get_nth_selected_icon (container, 1) != NULL; } /** * nemo_icon_container_show_stretch_handles: * @container: An icon container widget. * * Makes stretch handles visible on the first selected icon. **/ void nemo_icon_container_show_stretch_handles (NemoIconContainer *container) { NemoIconContainerDetails *details; NemoIcon *icon; guint initial_size; icon = get_first_selected_icon (container); if (icon == NULL) { return; } /* Check if it already has stretch handles. */ details = container->details; if (details->stretch_icon == icon) { return; } /* Get rid of the existing stretch handles and put them on the new icon. */ if (details->stretch_icon != NULL) { nemo_icon_canvas_item_set_show_stretch_handles (details->stretch_icon->item, FALSE); ungrab_stretch_icon (container); emit_stretch_ended (container, details->stretch_icon); } nemo_icon_canvas_item_set_show_stretch_handles (icon->item, TRUE); details->stretch_icon = icon; icon_get_size (container, icon, &initial_size); /* only need to keep size in one dimension, since they are constrained to be the same */ container->details->stretch_initial_x = icon->x; container->details->stretch_initial_y = icon->y; container->details->stretch_initial_size = initial_size; emit_stretch_started (container, icon); } /** * nemo_icon_container_has_stretch_handles * @container: An icon container widget. * * Returns true if the first selected item has stretch handles. **/ gboolean nemo_icon_container_has_stretch_handles (NemoIconContainer *container) { NemoIcon *icon; icon = get_first_selected_icon (container); if (icon == NULL) { return FALSE; } return icon == container->details->stretch_icon; } /** * nemo_icon_container_is_stretched * @container: An icon container widget. * * Returns true if the any selected item is stretched to a size other than 1.0. **/ gboolean nemo_icon_container_is_stretched (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (icon->is_selected && icon->scale != 1.0) { return TRUE; } } return FALSE; } /** * nemo_icon_container_unstretch * @container: An icon container widget. * * Gets rid of any icon stretching. **/ void nemo_icon_container_unstretch (NemoIconContainer *container) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (icon->is_selected) { nemo_icon_container_move_icon (container, icon, icon->x, icon->y, 1.0, FALSE, TRUE, TRUE); } } } static void compute_stretch (StretchState *start, StretchState *current) { gboolean right, bottom; int x_stretch, y_stretch; /* FIXME bugzilla.gnome.org 45390: This doesn't correspond to * the way the handles are drawn. */ /* Figure out which handle we are dragging. */ right = start->pointer_x > start->icon_x + (int) start->icon_size / 2; bottom = start->pointer_y > start->icon_y + (int) start->icon_size / 2; /* Figure out how big we should stretch. */ x_stretch = start->pointer_x - current->pointer_x; y_stretch = start->pointer_y - current->pointer_y; if (right) { x_stretch = - x_stretch; } if (bottom) { y_stretch = - y_stretch; } current->icon_size = MAX ((int) start->icon_size + MIN (x_stretch, y_stretch), (int) NEMO_ICON_SIZE_SMALLEST); /* Figure out where the corner of the icon should be. */ current->icon_x = start->icon_x; if (!right) { current->icon_x += start->icon_size - current->icon_size; } current->icon_y = start->icon_y; if (!bottom) { current->icon_y += start->icon_size - current->icon_size; } } char * nemo_icon_container_get_icon_uri (NemoIconContainer *container, NemoIcon *icon) { char *uri; uri = NULL; g_signal_emit (container, signals[GET_ICON_URI], 0, icon->data, &uri); return uri; } char * nemo_icon_container_get_icon_drop_target_uri (NemoIconContainer *container, NemoIcon *icon) { char *uri; uri = NULL; g_signal_emit (container, signals[GET_ICON_DROP_TARGET_URI], 0, icon->data, &uri); return uri; } void nemo_icon_container_update_tooltip_text (NemoIconContainer *container, NemoIconCanvasItem *item) { NemoIcon *icon; NemoFile *file; char *text; if (item == NULL) { gtk_widget_set_tooltip_text (GTK_WIDGET (container), ""); return; } icon = item->user_data; file = NEMO_FILE (icon->data); text = NULL; g_signal_emit (container, signals[GET_TOOLTIP_TEXT], 0, file, &text); gtk_widget_set_tooltip_text (GTK_WIDGET (container), text); g_free (text); } /* Call to reset the scroll region only if the container is not empty, * to avoid having the flag linger until the next file is added. */ static void reset_scroll_region_if_not_empty (NemoIconContainer *container) { if (!nemo_icon_container_is_empty (container)) { nemo_icon_container_reset_scroll_region (container); } } /* Switch from automatic layout to manual or vice versa. * If we switch to manual layout, we restore the icon positions from the * last manual layout. */ void nemo_icon_container_set_auto_layout (NemoIconContainer *container, gboolean auto_layout) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (auto_layout == FALSE || auto_layout == TRUE); if (container->details->auto_layout == auto_layout) { return; } reset_scroll_region_if_not_empty (container); container->details->stored_auto_layout = auto_layout; container->details->auto_layout = auto_layout; if (!auto_layout) { reload_icon_positions (container); nemo_icon_container_freeze_icon_positions (container); } container->details->needs_resort = TRUE; nemo_icon_container_redo_layout (container); g_signal_emit (container, signals[LAYOUT_CHANGED], 0); } void nemo_icon_container_set_horizontal_layout (NemoIconContainer *container, gboolean horizontal) { GtkTextDirection dir; NemoIconLayoutMode layout_mode; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (horizontal == FALSE || horizontal == TRUE); if (container->details->horizontal == horizontal) { return; } container->details->horizontal = horizontal; dir = gtk_widget_get_direction (GTK_WIDGET (container)); if (dir == GTK_TEXT_DIR_LTR) { layout_mode = horizontal ? NEMO_ICON_LAYOUT_L_R_T_B : NEMO_ICON_LAYOUT_T_B_L_R; } else { layout_mode = horizontal ? NEMO_ICON_LAYOUT_R_L_T_B : NEMO_ICON_LAYOUT_T_B_R_L; } container->details->layout_mode = layout_mode; } gboolean nemo_icon_container_get_horizontal_layout (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return container->details->horizontal; } void nemo_icon_container_set_grid_adjusts (NemoIconContainer *container, gint h_adjust, gint v_adjust) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->h_adjust = h_adjust; container->details->v_adjust = v_adjust; } gboolean nemo_icon_container_is_keep_aligned (NemoIconContainer *container) { return container->details->keep_aligned; } static gboolean align_icons_callback (gpointer callback_data) { NemoIconContainer *container; container = NEMO_ICON_CONTAINER (callback_data); align_icons (container); container->details->align_idle_id = 0; return FALSE; } static void unschedule_align_icons (NemoIconContainer *container) { if (container->details->align_idle_id != 0) { g_source_remove (container->details->align_idle_id); container->details->align_idle_id = 0; } } static void schedule_align_icons (NemoIconContainer *container) { if (container->details->align_idle_id == 0 && container->details->has_been_allocated) { container->details->align_idle_id = g_idle_add (align_icons_callback, container); } } void nemo_icon_container_set_keep_aligned (NemoIconContainer *container, gboolean keep_aligned) { if (container->details->keep_aligned != keep_aligned) { container->details->keep_aligned = keep_aligned; if (keep_aligned && !container->details->auto_layout) { schedule_align_icons (container); } else { unschedule_align_icons (container); } } } void nemo_icon_container_set_layout_mode (NemoIconContainer *container, NemoIconLayoutMode mode) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->layout_mode = mode; container->details->needs_resort = TRUE; if (gtk_widget_get_realized (GTK_WIDGET (container))) { nemo_icon_container_invalidate_labels (container); nemo_icon_container_redo_layout (container); g_signal_emit (container, signals[LAYOUT_CHANGED], 0); } } void nemo_icon_container_set_label_position (NemoIconContainer *container, NemoIconLabelPosition position) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (container->details->label_position != position) { container->details->label_position = position; nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); schedule_redo_layout (container); } } /* Switch from automatic to manual layout, freezing all the icons in their * current positions instead of restoring icon positions from the last manual * layout as set_auto_layout does. */ void nemo_icon_container_freeze_icon_positions (NemoIconContainer *container) { gboolean changed; GList *p; NemoIcon *icon; NemoIconPosition position; changed = container->details->auto_layout; container->details->auto_layout = FALSE; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; position.x = icon->saved_ltr_x; position.y = icon->y; position.scale = icon->scale; position.monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0, icon->data, &position); } if (changed) { g_signal_emit (container, signals[LAYOUT_CHANGED], 0); } } /* Re-sort, switching to automatic layout if it was in manual layout. */ void nemo_icon_container_sort (NemoIconContainer *container) { gboolean changed; container->details->stored_auto_layout = container->details->auto_layout; changed = !container->details->auto_layout; container->details->auto_layout = TRUE; reset_scroll_region_if_not_empty (container); container->details->needs_resort = TRUE; nemo_icon_container_redo_layout (container); if (changed) { g_signal_emit (container, signals[LAYOUT_CHANGED], 0); } } gboolean nemo_icon_container_is_auto_layout (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return container->details->auto_layout; } static void pending_icon_to_rename_destroy_callback (NemoIconCanvasItem *item, NemoIconContainer *container) { g_assert (container->details->pending_icon_to_rename != NULL); g_assert (container->details->pending_icon_to_rename->item == item); container->details->pending_icon_to_rename = NULL; } static NemoIcon* get_pending_icon_to_rename (NemoIconContainer *container) { return container->details->pending_icon_to_rename; } static void set_pending_icon_to_rename (NemoIconContainer *container, NemoIcon *icon) { NemoIcon *old_icon; old_icon = container->details->pending_icon_to_rename; if (icon == old_icon) { return; } if (old_icon != NULL) { g_signal_handlers_disconnect_by_func (old_icon->item, G_CALLBACK (pending_icon_to_rename_destroy_callback), container); } if (icon != NULL) { g_signal_connect (icon->item, "destroy", G_CALLBACK (pending_icon_to_rename_destroy_callback), container); } container->details->pending_icon_to_rename = icon; } static void process_pending_icon_to_rename (NemoIconContainer *container) { NemoIcon *pending_icon_to_rename; pending_icon_to_rename = get_pending_icon_to_rename (container); if (pending_icon_to_rename != NULL) { if (pending_icon_to_rename->is_selected && !has_multiple_selection (container)) { nemo_icon_container_start_renaming_selected_item (container, FALSE); } else { set_pending_icon_to_rename (container, NULL); } } } static gboolean is_renaming_pending (NemoIconContainer *container) { return get_pending_icon_to_rename (container) != NULL; } static gboolean is_renaming (NemoIconContainer *container) { return container->details->renaming; } /** * nemo_icon_container_start_renaming_selected_item * @container: An icon container widget. * @select_all: Whether the whole file should initially be selected, or * only its basename (i.e. everything except its extension). * * Displays the edit name widget on the first selected icon **/ void nemo_icon_container_start_renaming_selected_item (NemoIconContainer *container, gboolean select_all) { NemoIconContainerDetails *details; NemoIcon *icon; EelDRect icon_rect; EelDRect text_rect; PangoContext *context; PangoFontDescription *desc; const char *editable_text; int x, y, width; int start_offset, end_offset; /* Check if it already in renaming mode, if so - select all */ details = container->details; if (details->renaming) { eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget), 0, -1); return; } /* Find selected icon */ icon = get_first_selected_icon (container); if (icon == NULL) { return; } g_assert (!has_multiple_selection (container)); if (!nemo_icon_container_icon_is_positioned (icon)) { set_pending_icon_to_rename (container, icon); return; } set_pending_icon_to_rename (container, NULL); /* Make a copy of the original editable text for a later compare */ editable_text = nemo_icon_canvas_item_get_editable_text (icon->item); /* This could conceivably be NULL if a rename was triggered really early. */ if (editable_text == NULL) { return; } details->original_text = g_strdup (editable_text); /* Freeze updates so files added while renaming don't cause rename to loose focus, bug #318373 */ nemo_icon_container_freeze_updates (container); /* Create text renaming widget, if it hasn't been created already. * We deal with the broken icon text item widget by keeping it around * so its contents can still be cut and pasted as part of the clipboard */ if (details->rename_widget == NULL) { details->rename_widget = eel_editable_label_new ("Test text"); eel_editable_label_set_line_wrap (EEL_EDITABLE_LABEL (details->rename_widget), TRUE); eel_editable_label_set_line_wrap_mode (EEL_EDITABLE_LABEL (details->rename_widget), PANGO_WRAP_WORD_CHAR); eel_editable_label_set_draw_outline (EEL_EDITABLE_LABEL (details->rename_widget), TRUE); if (details->label_position != NEMO_ICON_LABEL_POSITION_BESIDE) { eel_editable_label_set_justify (EEL_EDITABLE_LABEL (details->rename_widget), GTK_JUSTIFY_CENTER); } gtk_misc_set_padding (GTK_MISC (details->rename_widget), 1, 1); gtk_layout_put (GTK_LAYOUT (container), details->rename_widget, 0, 0); } /* Set the right font */ if (details->font && g_strcmp0 (details->font, "") != 0) { desc = pango_font_description_from_string (details->font); } else { context = gtk_widget_get_pango_context (GTK_WIDGET (container)); desc = pango_font_description_copy (pango_context_get_font_description (context)); } if (pango_font_description_get_size (desc) > 0) { pango_font_description_set_size (desc, pango_font_description_get_size (desc) + container->details->font_size_table [container->details->zoom_level]); } eel_editable_label_set_font_description (EEL_EDITABLE_LABEL (details->rename_widget), desc); pango_font_description_free (desc); icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); text_rect = nemo_icon_canvas_item_get_text_rectangle (icon->item, TRUE); if (nemo_icon_container_is_layout_vertical (container) && container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { /* for one-line editables, the width changes dynamically */ width = -1; } else { width = nemo_icon_canvas_item_get_max_text_width (icon->item); } if (details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { eel_canvas_w2c (EEL_CANVAS_ITEM (icon->item)->canvas, text_rect.x0, text_rect.y0, &x, &y); } else { eel_canvas_w2c (EEL_CANVAS_ITEM (icon->item)->canvas, (icon_rect.x0 + icon_rect.x1) / 2, icon_rect.y1, &x, &y); x = x - width / 2 - 1; } gtk_layout_move (GTK_LAYOUT (container), details->rename_widget, x, y); gtk_widget_set_size_request (details->rename_widget, width, -1); eel_editable_label_set_text (EEL_EDITABLE_LABEL (details->rename_widget), editable_text); if (select_all) { start_offset = 0; end_offset = -1; } else { /* if it is a directory it should select all of the text regardless of select_all option */ if (nemo_file_is_directory (NEMO_FILE (icon->data))) { start_offset = 0; end_offset = -1; } else { eel_filename_get_rename_region (editable_text, &start_offset, &end_offset); } } gtk_widget_show (details->rename_widget); gtk_widget_grab_focus (details->rename_widget); eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget), start_offset, end_offset); g_signal_emit (container, signals[ICON_RENAME_STARTED], 0, GTK_EDITABLE (details->rename_widget)); nemo_icon_container_update_icon (container, icon); details->renaming_allocation_count = 0; /* We are in renaming mode */ details->renaming = TRUE; nemo_icon_canvas_item_set_renaming (icon->item, TRUE); } NemoIcon * nemo_icon_container_get_icon_being_renamed (NemoIconContainer *container) { NemoIcon *rename_icon; if (!is_renaming (container)) { return NULL; } g_assert (!has_multiple_selection (container)); rename_icon = get_first_selected_icon (container); g_assert (rename_icon != NULL); return rename_icon; } void nemo_icon_container_end_renaming_mode (NemoIconContainer *container, gboolean commit) { NemoIcon *icon; const char *changed_text = NULL; set_pending_icon_to_rename (container, NULL); icon = nemo_icon_container_get_icon_being_renamed (container); if (icon == NULL) { return; } /* We are not in renaming mode */ container->details->renaming = FALSE; nemo_icon_canvas_item_set_renaming (icon->item, FALSE); container->details->renaming_allocation_count = 0; if (commit) { set_pending_icon_to_reveal (container, icon); } gtk_widget_grab_focus (GTK_WIDGET (container)); if (commit) { /* Verify that text has been modified before signalling change. */ changed_text = eel_editable_label_get_text (EEL_EDITABLE_LABEL (container->details->rename_widget)); if (strcmp (container->details->original_text, changed_text) == 0) { changed_text = NULL; } } g_signal_emit (container, signals[ICON_RENAME_ENDED], 0, icon->data, changed_text); gtk_widget_hide (container->details->rename_widget); g_free (container->details->original_text); nemo_icon_container_unfreeze_updates (container); } void nemo_icon_container_set_single_click_mode (NemoIconContainer *container, gboolean single_click_mode) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->single_click_mode = single_click_mode; } void nemo_icon_container_set_click_to_rename_enabled (NemoIconContainer *container, gboolean enabled) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->click_to_rename = enabled; } /* Return if the icon container is a fixed size */ gboolean nemo_icon_container_get_is_fixed_size (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return container->details->is_fixed_size; } /* Set the icon container to be a fixed size */ void nemo_icon_container_set_is_fixed_size (NemoIconContainer *container, gboolean is_fixed_size) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->is_fixed_size = is_fixed_size; } gboolean nemo_icon_container_get_is_desktop (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return container->details->is_desktop; } void nemo_icon_container_set_is_desktop (NemoIconContainer *container, gboolean is_desktop) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->is_desktop = is_desktop; g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, text_ellipsis_limit_changed_container_callback, container); g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, text_ellipsis_limit_changed_container_callback, container); if (is_desktop) { GtkStyleContext *context; context = gtk_widget_get_style_context (GTK_WIDGET (container)); gtk_style_context_add_class (context, "nemo-desktop"); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (text_ellipsis_limit_changed_container_callback), container); } else { g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (text_ellipsis_limit_changed_container_callback), container); } } void nemo_icon_container_set_margins (NemoIconContainer *container, int left_margin, int right_margin, int top_margin, int bottom_margin) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->left_margin = left_margin; container->details->right_margin = right_margin; container->details->top_margin = top_margin; container->details->bottom_margin = bottom_margin; /* redo layout of icons as the margins have changed */ schedule_redo_layout (container); } void nemo_icon_container_set_use_drop_shadows (NemoIconContainer *container, gboolean use_drop_shadows) { if (container->details->drop_shadows_requested == use_drop_shadows) { return; } container->details->drop_shadows_requested = use_drop_shadows; container->details->use_drop_shadows = use_drop_shadows; gtk_widget_queue_draw (GTK_WIDGET (container)); } /* handle theme changes */ void nemo_icon_container_set_font (NemoIconContainer *container, const char *font) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (g_strcmp0 (container->details->font, font) == 0) { return; } g_free (container->details->font); container->details->font = g_strdup (font); nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); gtk_widget_queue_draw (GTK_WIDGET (container)); } void nemo_icon_container_set_font_size_table (NemoIconContainer *container, const int font_size_table[NEMO_ZOOM_LEVEL_LARGEST + 1]) { int old_font_size; int i; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (font_size_table != NULL); old_font_size = container->details->font_size_table[container->details->zoom_level]; for (i = 0; i <= NEMO_ZOOM_LEVEL_LARGEST; i++) { if (container->details->font_size_table[i] != font_size_table[i]) { container->details->font_size_table[i] = font_size_table[i]; } } if (old_font_size != container->details->font_size_table[container->details->zoom_level]) { nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } } /** * nemo_icon_container_get_icon_description * @container: An icon container widget. * @data: Icon data * * Gets the description for the icon. This function may return NULL. **/ char* nemo_icon_container_get_icon_description (NemoIconContainer *container, NemoIconData *data) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); if (klass->get_icon_description) { return klass->get_icon_description (container, data); } else { return NULL; } } gboolean nemo_icon_container_get_allow_moves (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return container->details->drag_allow_moves; } void nemo_icon_container_set_allow_moves (NemoIconContainer *container, gboolean allow_moves) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->drag_allow_moves = allow_moves; } void nemo_icon_container_set_forced_icon_size (NemoIconContainer *container, int forced_icon_size) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (forced_icon_size != container->details->forced_icon_size) { container->details->forced_icon_size = forced_icon_size; invalidate_label_sizes (container); update_icons (container); nemo_icon_container_request_update_all (container); } } void nemo_icon_container_set_all_columns_same_width (NemoIconContainer *container, gboolean all_columns_same_width) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (all_columns_same_width != container->details->all_columns_same_width) { container->details->all_columns_same_width = all_columns_same_width; nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } } /** * nemo_icon_container_set_highlighted_for_clipboard * @container: An icon container widget. * @data: Icon Data associated with all icons that should be highlighted. * Others will be unhighlighted. **/ void nemo_icon_container_set_highlighted_for_clipboard (NemoIconContainer *container, GList *clipboard_icon_data) { GList *l; NemoIcon *icon; gboolean highlighted_for_clipboard; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); for (l = container->details->icons; l != NULL; l = l->next) { icon = l->data; highlighted_for_clipboard = (g_list_find (clipboard_icon_data, icon->data) != NULL); eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item), "highlighted-for-clipboard", highlighted_for_clipboard, NULL); } } /* NemoIconContainerAccessible */ static NemoIconContainerAccessiblePrivate * accessible_get_priv (AtkObject *accessible) { NemoIconContainerAccessiblePrivate *priv; priv = g_object_get_qdata (G_OBJECT (accessible), accessible_private_data_quark); return priv; } /* AtkAction interface */ static gboolean nemo_icon_container_accessible_do_action (AtkAction *accessible, int i) { GtkWidget *widget; NemoIconContainer *container; GList *selection; g_return_val_if_fail (i < LAST_ACTION, FALSE); widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); switch (i) { case ACTION_ACTIVATE : selection = nemo_icon_container_peek_selection (container); if (selection) { g_signal_emit_by_name (container, "activate", selection); } break; case ACTION_MENU : handle_popups (container, NULL,"context_click_background"); break; default : g_warning ("Invalid action passed to NemoIconContainerAccessible::do_action"); return FALSE; } return TRUE; } static int nemo_icon_container_accessible_get_n_actions (AtkAction *accessible) { return LAST_ACTION; } static const char * nemo_icon_container_accessible_action_get_description (AtkAction *accessible, int i) { NemoIconContainerAccessiblePrivate *priv; g_assert (i < LAST_ACTION); priv = accessible_get_priv (ATK_OBJECT (accessible)); if (priv->action_descriptions[i]) { return priv->action_descriptions[i]; } else { return nemo_icon_container_accessible_action_descriptions[i]; } } static const char * nemo_icon_container_accessible_action_get_name (AtkAction *accessible, int i) { g_assert (i < LAST_ACTION); return nemo_icon_container_accessible_action_names[i]; } static const char * nemo_icon_container_accessible_action_get_keybinding (AtkAction *accessible, int i) { g_assert (i < LAST_ACTION); return NULL; } static gboolean nemo_icon_container_accessible_action_set_description (AtkAction *accessible, int i, const char *description) { NemoIconContainerAccessiblePrivate *priv; g_assert (i < LAST_ACTION); priv = accessible_get_priv (ATK_OBJECT (accessible)); if (priv->action_descriptions[i]) { g_free (priv->action_descriptions[i]); } priv->action_descriptions[i] = g_strdup (description); return FALSE; } static void nemo_icon_container_accessible_action_interface_init (AtkActionIface *iface) { iface->do_action = nemo_icon_container_accessible_do_action; iface->get_n_actions = nemo_icon_container_accessible_get_n_actions; iface->get_description = nemo_icon_container_accessible_action_get_description; iface->get_name = nemo_icon_container_accessible_action_get_name; iface->get_keybinding = nemo_icon_container_accessible_action_get_keybinding; iface->set_description = nemo_icon_container_accessible_action_set_description; } /* AtkSelection interface */ static void nemo_icon_container_accessible_update_selection (AtkObject *accessible) { NemoIconContainer *container; NemoIconContainerAccessiblePrivate *priv; GList *l; NemoIcon *icon; container = NEMO_ICON_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible))); priv = accessible_get_priv (accessible); if (priv->selection) { g_list_free (priv->selection); priv->selection = NULL; } for (l = container->details->icons; l != NULL; l = l->next) { icon = l->data; if (icon->is_selected) { priv->selection = g_list_prepend (priv->selection, icon); } } priv->selection = g_list_reverse (priv->selection); } static void nemo_icon_container_accessible_selection_changed_cb (NemoIconContainer *container, gpointer data) { g_signal_emit_by_name (data, "selection_changed"); } static void nemo_icon_container_accessible_icon_added_cb (NemoIconContainer *container, NemoIconData *icon_data, gpointer data) { NemoIcon *icon; AtkObject *atk_parent; AtkObject *atk_child; int index; icon = g_hash_table_lookup (container->details->icon_set, icon_data); if (icon) { atk_parent = ATK_OBJECT (data); atk_child = atk_gobject_accessible_for_object (G_OBJECT (icon->item)); index = g_list_index (container->details->icons, icon); g_signal_emit_by_name (atk_parent, "children_changed::add", index, atk_child, NULL); } } static void nemo_icon_container_accessible_icon_removed_cb (NemoIconContainer *container, NemoIconData *icon_data, gpointer data) { NemoIcon *icon; AtkObject *atk_parent; AtkObject *atk_child; int index; icon = g_hash_table_lookup (container->details->icon_set, icon_data); if (icon) { atk_parent = ATK_OBJECT (data); atk_child = atk_gobject_accessible_for_object (G_OBJECT (icon->item)); index = g_list_index (container->details->icons, icon); g_signal_emit_by_name (atk_parent, "children_changed::remove", index, atk_child, NULL); } } static void nemo_icon_container_accessible_cleared_cb (NemoIconContainer *container, gpointer data) { g_signal_emit_by_name (data, "children_changed", 0, NULL, NULL); } static gboolean nemo_icon_container_accessible_add_selection (AtkSelection *accessible, int i) { GtkWidget *widget; NemoIconContainer *container; GList *selection; NemoIcon *icon; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); icon = g_list_nth_data (container->details->icons, i); if (icon) { selection = nemo_icon_container_get_selection (container); selection = g_list_prepend (selection, icon->data); nemo_icon_container_set_selection (container, selection); g_list_free (selection); return TRUE; } return FALSE; } static gboolean nemo_icon_container_accessible_clear_selection (AtkSelection *accessible) { GtkWidget *widget; NemoIconContainer *container; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); nemo_icon_container_unselect_all (container); return TRUE; } static AtkObject * nemo_icon_container_accessible_ref_selection (AtkSelection *accessible, int i) { AtkObject *atk_object; NemoIconContainerAccessiblePrivate *priv; NemoIcon *icon; nemo_icon_container_accessible_update_selection (ATK_OBJECT (accessible)); priv = accessible_get_priv (ATK_OBJECT (accessible)); icon = g_list_nth_data (priv->selection, i); if (icon) { atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item)); if (atk_object) { g_object_ref (atk_object); } return atk_object; } else { return NULL; } } static int nemo_icon_container_accessible_get_selection_count (AtkSelection *accessible) { int count; NemoIconContainerAccessiblePrivate *priv; nemo_icon_container_accessible_update_selection (ATK_OBJECT (accessible)); priv = accessible_get_priv (ATK_OBJECT (accessible)); count = g_list_length (priv->selection); return count; } static gboolean nemo_icon_container_accessible_is_child_selected (AtkSelection *accessible, int i) { NemoIconContainer *container; NemoIcon *icon; GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); icon = g_list_nth_data (container->details->icons, i); return icon ? icon->is_selected : FALSE; } static gboolean nemo_icon_container_accessible_remove_selection (AtkSelection *accessible, int i) { NemoIconContainer *container; NemoIconContainerAccessiblePrivate *priv; GList *selection; NemoIcon *icon; GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } nemo_icon_container_accessible_update_selection (ATK_OBJECT (accessible)); priv = accessible_get_priv (ATK_OBJECT (accessible)); container = NEMO_ICON_CONTAINER (widget); icon = g_list_nth_data (priv->selection, i); if (icon) { selection = nemo_icon_container_get_selection (container); selection = g_list_remove (selection, icon->data); nemo_icon_container_set_selection (container, selection); g_list_free (selection); return TRUE; } return FALSE; } static gboolean nemo_icon_container_accessible_select_all_selection (AtkSelection *accessible) { NemoIconContainer *container; GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); nemo_icon_container_select_all (container); return TRUE; } void nemo_icon_container_widget_to_file_operation_position (NemoIconContainer *container, GdkPoint *position) { double x, y; g_return_if_fail (position != NULL); x = position->x; y = position->y; eel_canvas_window_to_world (EEL_CANVAS (container), x, y, &x, &y); position->x = (int) x; position->y = (int) y; /* ensure that we end up in the middle of the icon */ position->x -= nemo_get_icon_size_for_zoom_level (container->details->zoom_level) / 2; position->y -= nemo_get_icon_size_for_zoom_level (container->details->zoom_level) / 2; } static void nemo_icon_container_accessible_selection_interface_init (AtkSelectionIface *iface) { iface->add_selection = nemo_icon_container_accessible_add_selection; iface->clear_selection = nemo_icon_container_accessible_clear_selection; iface->ref_selection = nemo_icon_container_accessible_ref_selection; iface->get_selection_count = nemo_icon_container_accessible_get_selection_count; iface->is_child_selected = nemo_icon_container_accessible_is_child_selected; iface->remove_selection = nemo_icon_container_accessible_remove_selection; iface->select_all_selection = nemo_icon_container_accessible_select_all_selection; } static gint nemo_icon_container_accessible_get_n_children (AtkObject *accessible) { NemoIconContainer *container; GtkWidget *widget; gint i; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return FALSE; } container = NEMO_ICON_CONTAINER (widget); i = g_hash_table_size (container->details->icon_set); if (container->details->rename_widget) { i++; } return i; } static AtkObject* nemo_icon_container_accessible_ref_child (AtkObject *accessible, int i) { AtkObject *atk_object; NemoIconContainer *container; NemoIcon *icon; GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); if (!widget) { return NULL; } container = NEMO_ICON_CONTAINER (widget); icon = g_list_nth_data (container->details->icons, i); if (icon) { atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item)); g_object_ref (atk_object); return atk_object; } else { if (i == (int)g_list_length (container->details->icons)) { if (container->details->rename_widget) { atk_object = gtk_widget_get_accessible (container->details->rename_widget); g_object_ref (atk_object); return atk_object; } } return NULL; } } static void nemo_icon_container_accessible_initialize (AtkObject *accessible, gpointer data) { NemoIconContainer *container; NemoIconContainerAccessiblePrivate *priv; if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize) { ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data); } priv = g_new0 (NemoIconContainerAccessiblePrivate, 1); g_object_set_qdata (G_OBJECT (accessible), accessible_private_data_quark, priv); if (GTK_IS_ACCESSIBLE (accessible)) { nemo_icon_container_accessible_update_selection (ATK_OBJECT (accessible)); container = NEMO_ICON_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible))); g_signal_connect (G_OBJECT (container), "selection_changed", G_CALLBACK (nemo_icon_container_accessible_selection_changed_cb), accessible); g_signal_connect (G_OBJECT (container), "icon_added", G_CALLBACK (nemo_icon_container_accessible_icon_added_cb), accessible); g_signal_connect (G_OBJECT (container), "icon_removed", G_CALLBACK (nemo_icon_container_accessible_icon_removed_cb), accessible); g_signal_connect (G_OBJECT (container), "cleared", G_CALLBACK (nemo_icon_container_accessible_cleared_cb), accessible); } } static void nemo_icon_container_accessible_finalize (GObject *object) { NemoIconContainerAccessiblePrivate *priv; int i; priv = accessible_get_priv (ATK_OBJECT (object)); if (priv->selection) { g_list_free (priv->selection); } for (i = 0; i < LAST_ACTION; i++) { if (priv->action_descriptions[i]) { g_free (priv->action_descriptions[i]); } } g_free (priv); G_OBJECT_CLASS (accessible_parent_class)->finalize (object); } static void nemo_icon_container_accessible_class_init (AtkObjectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); accessible_parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = nemo_icon_container_accessible_finalize; klass->get_n_children = nemo_icon_container_accessible_get_n_children; klass->ref_child = nemo_icon_container_accessible_ref_child; klass->initialize = nemo_icon_container_accessible_initialize; accessible_private_data_quark = g_quark_from_static_string ("icon-container-accessible-private-data"); } static GType nemo_icon_container_accessible_get_type (void) { static GType type = 0; if (!type) { static GInterfaceInfo atk_action_info = { (GInterfaceInitFunc) nemo_icon_container_accessible_action_interface_init, (GInterfaceFinalizeFunc) NULL, NULL }; static GInterfaceInfo atk_selection_info = { (GInterfaceInitFunc) nemo_icon_container_accessible_selection_interface_init, (GInterfaceFinalizeFunc) NULL, NULL }; type = eel_accessibility_create_derived_type ("NemoIconContainerAccessible", EEL_TYPE_CANVAS, nemo_icon_container_accessible_class_init); g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info); g_type_add_interface_static (type, ATK_TYPE_SELECTION, &atk_selection_info); } return type; } #if ! defined (NEMO_OMIT_SELF_CHECK) static char * check_compute_stretch (int icon_x, int icon_y, int icon_size, int start_pointer_x, int start_pointer_y, int end_pointer_x, int end_pointer_y) { StretchState start, current; start.icon_x = icon_x; start.icon_y = icon_y; start.icon_size = icon_size; start.pointer_x = start_pointer_x; start.pointer_y = start_pointer_y; current.pointer_x = end_pointer_x; current.pointer_y = end_pointer_y; compute_stretch (&start, ¤t); return g_strdup_printf ("%d,%d:%d", current.icon_x, current.icon_y, current.icon_size); } void nemo_self_check_icon_container (void) { EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 0, 0, 0, 0), "0,0:16"); EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 17), "0,0:17"); EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 16), "0,0:16"); EEL_CHECK_STRING_RESULT (check_compute_stretch (100, 100, 64, 105, 105, 40, 40), "35,35:129"); } gboolean nemo_icon_container_is_layout_rtl (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), 0); return gtk_widget_get_direction (GTK_WIDGET(container)) == GTK_TEXT_DIR_RTL; } gboolean nemo_icon_container_is_layout_vertical (NemoIconContainer *container) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); return (container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_L_R || container->details->layout_mode == NEMO_ICON_LAYOUT_T_B_R_L); } gint nemo_icon_container_get_max_layout_lines_for_pango (NemoIconContainer *container) { return NEMO_ICON_CONTAINER_GET_CLASS (container)->get_max_layout_lines_for_pango (container); } gint nemo_icon_container_get_max_layout_lines (NemoIconContainer *container) { return NEMO_ICON_CONTAINER_GET_CLASS (container)->get_max_layout_lines (container); } void nemo_icon_container_begin_loading (NemoIconContainer *container) { gboolean dummy; if (nemo_icon_container_get_store_layout_timestamps (container)) { container->details->layout_timestamp = UNDEFINED_TIME; g_signal_emit (container, signals[GET_STORED_LAYOUT_TIMESTAMP], 0, NULL, &container->details->layout_timestamp, &dummy); } } void nemo_icon_container_store_layout_timestamps_now (NemoIconContainer *container) { NemoIcon *icon; GList *p; gboolean dummy; container->details->layout_timestamp = time (NULL); g_signal_emit (container, signals[STORE_LAYOUT_TIMESTAMP], 0, NULL, &container->details->layout_timestamp, &dummy); for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; g_signal_emit (container, signals[STORE_LAYOUT_TIMESTAMP], 0, icon->data, &container->details->layout_timestamp, &dummy); } } void nemo_icon_container_end_loading (NemoIconContainer *container, gboolean all_icons_added) { if (all_icons_added && nemo_icon_container_get_store_layout_timestamps (container)) { if (container->details->new_icons == NULL) { nemo_icon_container_store_layout_timestamps_now (container); } else { container->details->store_layout_timestamps_when_finishing_new_icons = TRUE; } } } gboolean nemo_icon_container_get_store_layout_timestamps (NemoIconContainer *container) { return container->details->store_layout_timestamps; } void nemo_icon_container_set_store_layout_timestamps (NemoIconContainer *container, gboolean store_layout_timestamps) { container->details->store_layout_timestamps = store_layout_timestamps; } gint nemo_icon_container_get_canvas_height (NemoIconContainer *container, GtkAllocation allocation) { return (allocation.height - container->details->top_margin - container->details->bottom_margin) / EEL_CANVAS (container)->pixels_per_unit; } gint nemo_icon_container_get_canvas_width (NemoIconContainer *container, GtkAllocation allocation) { return (allocation.width - container->details->left_margin - container->details->right_margin) / EEL_CANVAS (container)->pixels_per_unit; } double nemo_icon_container_get_mirror_x_position (NemoIconContainer *container, NemoIcon *icon, double x) { EelDRect icon_bounds; GtkAllocation allocation; gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); return nemo_icon_container_get_canvas_width (container, allocation) - x - (icon_bounds.x1 - icon_bounds.x0); } void nemo_icon_container_set_rtl_positions (NemoIconContainer *container) { GList *l; NemoIcon *icon; double x; if (!container->details->icons) { return; } for (l = container->details->icons; l != NULL; l = l->next) { icon = l->data; x = nemo_icon_container_get_mirror_x_position (container, icon, icon->saved_ltr_x); nemo_icon_container_icon_set_position (container, icon, x, icon->y); } } void nemo_icon_container_sort_icons (NemoIconContainer *container, GList **icons) { NemoIconContainerClass *klass; klass = NEMO_ICON_CONTAINER_GET_CLASS (container); g_assert (klass->compare_icons != NULL); *icons = g_list_sort_with_data (*icons, compare_icons, container); } void nemo_icon_container_resort (NemoIconContainer *container) { nemo_icon_container_sort_icons (container, &container->details->icons); } void nemo_icon_container_icon_raise (NemoIconContainer *container, NemoIcon *icon) { EelCanvasItem *item, *band; item = EEL_CANVAS_ITEM (icon->item); band = container->details->rubberband_info.selection_rectangle; eel_canvas_item_send_behind (item, band); } void nemo_icon_container_finish_adding_icon (NemoIconContainer *container, NemoIcon *icon) { eel_canvas_item_show (EEL_CANVAS_ITEM (icon->item)); g_signal_connect_object (icon->item, "event", G_CALLBACK (item_event_callback), container, 0); g_signal_emit (container, signals[ICON_ADDED], 0, icon->data); } void nemo_icon_container_update_selection (NemoIconContainer *container) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (container->details->current_selection != NULL) { g_list_free (container->details->current_selection); container->details->current_selection = NULL; container->details->current_selection_count = 0; } container->details->current_selection = nemo_icon_container_get_real_selection (container); container->details->current_selection_count = g_list_length (container->details->current_selection); } void nemo_icon_container_move_icon (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position) { NEMO_ICON_CONTAINER_GET_CLASS (container)->move_icon (container, icon, x, y, scale, raise, snap, update_position); } void nemo_icon_container_icon_set_position (NemoIconContainer *container, NemoIcon *icon, gdouble x, gdouble y) { NEMO_ICON_CONTAINER_GET_CLASS (container)->icon_set_position (container, icon, x, y); } void nemo_icon_container_icon_get_bounding_box (NemoIconContainer *container, NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage) { NEMO_ICON_CONTAINER_GET_CLASS (container)->icon_get_bounding_box (icon, x1_return, y1_return, x2_return, y2_return, usage); } void nemo_icon_container_update_icon (NemoIconContainer *container, NemoIcon *icon) { NEMO_ICON_CONTAINER_GET_CLASS (container)->update_icon (container, icon); } #endif /* ! NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/libnemo-private/nemo-icon-container.h000066400000000000000000000463111357442400300216000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* gnome-icon-container.h - Icon container widget. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ettore Perazzoli , Darin Adler */ #ifndef NEMO_ICON_CONTAINER_H #define NEMO_ICON_CONTAINER_H #include #include #include #define NEMO_TYPE_ICON_CONTAINER nemo_icon_container_get_type() #define NEMO_ICON_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ICON_CONTAINER, NemoIconContainer)) #define NEMO_ICON_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ICON_CONTAINER, NemoIconContainerClass)) #define NEMO_IS_ICON_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ICON_CONTAINER)) #define NEMO_IS_ICON_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ICON_CONTAINER)) #define NEMO_ICON_CONTAINER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ICON_CONTAINER, NemoIconContainerClass)) /* Initial unpositioned icon value */ #define ICON_UNPOSITIONED_VALUE -1 typedef struct { int x; int y; double scale; int monitor; } NemoIconPosition; typedef enum { NEMO_ICON_LAYOUT_L_R_T_B, NEMO_ICON_LAYOUT_R_L_T_B, NEMO_ICON_LAYOUT_T_B_L_R, NEMO_ICON_LAYOUT_T_B_R_L } NemoIconLayoutMode; typedef enum { NEMO_ICON_LABEL_POSITION_UNDER, NEMO_ICON_LABEL_POSITION_BESIDE } NemoIconLabelPosition; #define NEMO_ICON_CONTAINER_TYPESELECT_FLUSH_DELAY 1000000 typedef struct NemoIconContainerDetails NemoIconContainerDetails; typedef struct { EelCanvas canvas; NemoIconContainerDetails *details; } NemoIconContainer; typedef struct { EelCanvasClass parent_slot; gboolean is_grid_container; /* Operations on the container. */ int (* button_press) (NemoIconContainer *container, GdkEventButton *event); void (* context_click_background) (NemoIconContainer *container, GdkEventButton *event); void (* middle_click) (NemoIconContainer *container, GdkEventButton *event); /* Operations on icons. */ void (* activate) (NemoIconContainer *container, NemoIconData *data); void (* activate_alternate) (NemoIconContainer *container, NemoIconData *data); void (* activate_previewer) (NemoIconContainer *container, GList *files, GArray *locations); void (* context_click_selection) (NemoIconContainer *container, GdkEventButton *event); void (* move_copy_items) (NemoIconContainer *container, const GList *item_uris, GdkPoint *relative_item_points, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_netscape_url) (NemoIconContainer *container, const char *url, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_uri_list) (NemoIconContainer *container, const char *uri_list, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_text) (NemoIconContainer *container, const char *text, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_raw) (NemoIconContainer *container, char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y); /* Queries on the container for subclass/client. * These must be implemented. The default "do nothing" is not good enough. */ char * (* get_container_uri) (NemoIconContainer *container); /* Queries on icons for subclass/client. * These must be implemented. The default "do nothing" is not * good enough, these are _not_ signals. */ NemoIconInfo *(* get_icon_images) (NemoIconContainer *container, NemoIconData *data, int icon_size, gboolean for_drag_accept, gboolean *has_window_open); void (* get_icon_text) (NemoIconContainer *container, NemoIconData *data, char **editable_text, char **additional_text, gboolean *pinned, gboolean include_invisible); void (* update_icon) (NemoIconContainer *container, NemoIcon *icon); char * (* get_icon_description) (NemoIconContainer *container, NemoIconData *data); int (* compare_icons) (NemoIconContainer *container, NemoIconData *icon_a, NemoIconData *icon_b); void (* freeze_updates) (NemoIconContainer *container); void (* unfreeze_updates) (NemoIconContainer *container); void (* prioritize_thumbnailing) (NemoIconContainer *container, NemoIconData *data); gint (* get_max_layout_lines_for_pango) (NemoIconContainer *container); gint (* get_max_layout_lines) (NemoIconContainer *container); /* Queries on icons for subclass/client. * These must be implemented => These are signals ! * The default "do nothing" is not good enough. */ gboolean (* can_accept_item) (NemoIconContainer *container, NemoIconData *target, const char *item_uri); char * (* get_icon_uri) (NemoIconContainer *container, NemoIconData *data); char * (* get_icon_drop_target_uri) (NemoIconContainer *container, NemoIconData *data); /* If icon data is NULL, the layout timestamp of the container should be retrieved. * That is the time when the container displayed a fully loaded directory with * all icon positions assigned. * * If icon data is not NULL, the position timestamp of the icon should be retrieved. * That is the time when the file (i.e. icon data payload) was last displayed in a * fully loaded directory with all icon positions assigned. */ gboolean (* get_stored_layout_timestamp) (NemoIconContainer *container, NemoIconData *data, time_t *time); /* If icon data is NULL, the layout timestamp of the container should be stored. * If icon data is not NULL, the position timestamp of the container should be stored. */ gboolean (* store_layout_timestamp) (NemoIconContainer *container, NemoIconData *data, const time_t *time); void (*lay_down_icons) (NemoIconContainer *container, GList *icons, double start_y); void (*icon_set_position) (NemoIconContainer *container, NemoIcon *icon, double x, double y); void (*move_icon) (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position); void (*align_icons) (NemoIconContainer *container); void (*finish_adding_new_icons) (NemoIconContainer *container); void (*reload_icon_positions) (NemoIconContainer *container); void (*icon_get_bounding_box) (NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage); void (*set_zoom_level) (NemoIconContainer *container, gint new_level); /* Notifications for the whole container. */ void (* band_select_started) (NemoIconContainer *container); void (* band_select_ended) (NemoIconContainer *container); void (* selection_changed) (NemoIconContainer *container); void (* layout_changed) (NemoIconContainer *container); /* Notifications for icons. */ void (* icon_position_changed) (NemoIconContainer *container, NemoIconData *data, const NemoIconPosition *position); void (* icon_rename_started) (NemoIconContainer *container, GtkWidget *renaming_widget); void (* icon_rename_ended) (NemoIconContainer *container, NemoIconData *data, const char *text); void (* icon_stretch_started) (NemoIconContainer *container, NemoIconData *data); void (* icon_stretch_ended) (NemoIconContainer *container, NemoIconData *data); int (* preview) (NemoIconContainer *container, NemoIconData *data, gboolean start_flag); void (* icon_added) (NemoIconContainer *container, NemoIconData *data); void (* icon_removed) (NemoIconContainer *container, NemoIconData *data); void (* cleared) (NemoIconContainer *container); gboolean (* start_interactive_search) (NemoIconContainer *container); } NemoIconContainerClass; /* GtkObject */ GType nemo_icon_container_get_type (void); GtkWidget * nemo_icon_container_new (void); /* adding, removing, and managing icons */ void nemo_icon_container_clear (NemoIconContainer *view); gboolean nemo_icon_container_icon_is_new_for_monitor (NemoIconContainer *container, NemoIcon *icon, gint current_monitor); gboolean nemo_icon_container_add (NemoIconContainer *view, NemoIconData *data); void nemo_icon_container_layout_now (NemoIconContainer *container); gboolean nemo_icon_container_remove (NemoIconContainer *view, NemoIconData *data); void nemo_icon_container_for_each (NemoIconContainer *view, NemoIconCallback callback, gpointer callback_data); void nemo_icon_container_request_update (NemoIconContainer *view, NemoIconData *data); void nemo_icon_container_invalidate_labels (NemoIconContainer *container); void nemo_icon_container_request_update_all (NemoIconContainer *container); void nemo_icon_container_reveal (NemoIconContainer *container, NemoIconData *data); gboolean nemo_icon_container_is_empty (NemoIconContainer *container); NemoIconData *nemo_icon_container_get_first_visible_icon (NemoIconContainer *container); void nemo_icon_container_scroll_to_icon (NemoIconContainer *container, NemoIconData *data); void nemo_icon_container_begin_loading (NemoIconContainer *container); void nemo_icon_container_end_loading (NemoIconContainer *container, gboolean all_icons_added); /* control the layout */ gboolean nemo_icon_container_is_auto_layout (NemoIconContainer *container); void nemo_icon_container_set_auto_layout (NemoIconContainer *container, gboolean auto_layout); gboolean nemo_icon_container_is_keep_aligned (NemoIconContainer *container); void nemo_icon_container_set_keep_aligned (NemoIconContainer *container, gboolean keep_aligned); void nemo_icon_container_set_layout_mode (NemoIconContainer *container, NemoIconLayoutMode mode); void nemo_icon_container_set_horizontal_layout (NemoIconContainer *container, gboolean horizontal); gboolean nemo_icon_container_get_horizontal_layout (NemoIconContainer *container); void nemo_icon_container_set_grid_adjusts (NemoIconContainer *container, gint h_adjust, gint v_adjust); void nemo_icon_container_set_label_position (NemoIconContainer *container, NemoIconLabelPosition pos); void nemo_icon_container_sort (NemoIconContainer *container); void nemo_icon_container_freeze_icon_positions (NemoIconContainer *container); gint nemo_icon_container_get_max_layout_lines (NemoIconContainer *container); gint nemo_icon_container_get_max_layout_lines_for_pango (NemoIconContainer *container); void nemo_icon_container_set_highlighted_for_clipboard (NemoIconContainer *container, GList *clipboard_icon_data); /* operations on all icons */ void nemo_icon_container_unselect_all (NemoIconContainer *view); void nemo_icon_container_select_all (NemoIconContainer *view); /* operations on the selection */ void nemo_icon_container_update_selection (NemoIconContainer *container); GList * nemo_icon_container_get_selection (NemoIconContainer *view); GList * nemo_icon_container_peek_selection (NemoIconContainer *view); gint nemo_icon_container_get_selection_count (NemoIconContainer *container); void nemo_icon_container_invert_selection (NemoIconContainer *view); void nemo_icon_container_set_selection (NemoIconContainer *view, GList *selection); GArray * nemo_icon_container_get_selected_icon_locations (NemoIconContainer *view); gboolean nemo_icon_container_has_stretch_handles (NemoIconContainer *container); gboolean nemo_icon_container_is_stretched (NemoIconContainer *container); void nemo_icon_container_show_stretch_handles (NemoIconContainer *container); void nemo_icon_container_unstretch (NemoIconContainer *container); void nemo_icon_container_start_renaming_selected_item (NemoIconContainer *container, gboolean select_all); /* options */ NemoZoomLevel nemo_icon_container_get_zoom_level (NemoIconContainer *view); void nemo_icon_container_set_zoom_level (NemoIconContainer *view, int new_zoom_level); void nemo_icon_container_set_single_click_mode (NemoIconContainer *container, gboolean single_click_mode); void nemo_icon_container_set_click_to_rename_enabled (NemoIconContainer *container, gboolean enabled); void nemo_icon_container_enable_linger_selection (NemoIconContainer *view, gboolean enable); gboolean nemo_icon_container_get_is_fixed_size (NemoIconContainer *container); void nemo_icon_container_set_is_fixed_size (NemoIconContainer *container, gboolean is_fixed_size); gboolean nemo_icon_container_get_is_desktop (NemoIconContainer *container); void nemo_icon_container_set_is_desktop (NemoIconContainer *container, gboolean is_desktop); gboolean nemo_icon_container_get_show_desktop_tooltips (NemoIconContainer *container); void nemo_icon_container_set_show_desktop_tooltips (NemoIconContainer *container, gboolean show_tooltips); void nemo_icon_container_reset_scroll_region (NemoIconContainer *container); void nemo_icon_container_set_font (NemoIconContainer *container, const char *font); void nemo_icon_container_set_font_size_table (NemoIconContainer *container, const int font_size_table[NEMO_ZOOM_LEVEL_LARGEST + 1]); void nemo_icon_container_set_margins (NemoIconContainer *container, int left_margin, int right_margin, int top_margin, int bottom_margin); void nemo_icon_container_set_use_drop_shadows (NemoIconContainer *container, gboolean use_drop_shadows); char* nemo_icon_container_get_icon_description (NemoIconContainer *container, NemoIconData *data); gboolean nemo_icon_container_get_allow_moves (NemoIconContainer *container); void nemo_icon_container_set_allow_moves (NemoIconContainer *container, gboolean allow_moves); void nemo_icon_container_set_forced_icon_size (NemoIconContainer *container, int forced_icon_size); void nemo_icon_container_set_all_columns_same_width (NemoIconContainer *container, gboolean all_columns_same_width); gboolean nemo_icon_container_is_layout_rtl (NemoIconContainer *container); gboolean nemo_icon_container_is_layout_vertical (NemoIconContainer *container); gboolean nemo_icon_container_get_store_layout_timestamps (NemoIconContainer *container); void nemo_icon_container_set_store_layout_timestamps (NemoIconContainer *container, gboolean store_layout); void nemo_icon_container_widget_to_file_operation_position (NemoIconContainer *container, GdkPoint *position); void nemo_icon_container_setup_tooltip_preference_callback (NemoIconContainer *container); void nemo_icon_container_update_tooltip_text (NemoIconContainer *container, NemoIconCanvasItem *item); #endif /* NEMO_ICON_CONTAINER_H */ nemo-4.4.2/libnemo-private/nemo-icon-dnd.c000066400000000000000000001757331357442400300203710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-icon-dnd.c - Drag & drop handling for the icon container widget. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ettore Perazzoli , Darin Adler , Andy Hertzfeld Pavel Cisler XDS support: Benedikt Meurer (adapted by Amos Brocco ) */ #include #include #include "nemo-icon-dnd.h" #include "nemo-file-dnd.h" #include "nemo-icon-private.h" #include "libnemo-private/nemo-icon.h" #include "nemo-link.h" #include "nemo-metadata.h" #include "nemo-selection-canvas-item.h" #include "nemo-desktop-utils.h" #include "nemo-global-preferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_ICON_CONTAINER #include "nemo-debug.h" static const GtkTargetEntry drag_types [] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST }, { (char *)NEMO_ICON_DND_URI_LIST_TYPE, 0, NEMO_ICON_DND_URI_LIST }, }; static const GtkTargetEntry drop_types [] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST }, /* prefer XDS Protocol Type over "_NETSCAPE_URL" to make DnD work in Firefox. */ { (char *)NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, 0, NEMO_ICON_DND_XDNDDIRECTSAVE }, /* prefer "_NETSCAPE_URL" over "text/uri-list" to satisfy web browsers. */ { (char *)NEMO_ICON_DND_NETSCAPE_URL_TYPE, 0, NEMO_ICON_DND_NETSCAPE_URL }, { (char *)NEMO_ICON_DND_URI_LIST_TYPE, 0, NEMO_ICON_DND_URI_LIST }, { (char *)NEMO_ICON_DND_RAW_TYPE, 0, NEMO_ICON_DND_RAW }, /* Must be last: */ { (char *)NEMO_ICON_DND_ROOTWINDOW_DROP_TYPE, 0, NEMO_ICON_DND_ROOTWINDOW_DROP } }; static void stop_dnd_highlight (GtkWidget *widget); static void dnd_highlight_queue_redraw (GtkWidget *widget); static GtkTargetList *drop_types_list = NULL; static GtkTargetList *drop_types_list_root = NULL; static char * nemo_icon_container_find_drop_target (NemoIconContainer *container, GdkDragContext *context, int x, int y, gboolean *icon_hit, gboolean rewrite_desktop); static void initialize_dnd_grid (NemoIconContainer *container) { GList *selection, *p; if (!NEMO_ICON_CONTAINER_GET_CLASS (container)->is_grid_container) { return; } if (container->details->dnd_grid != NULL) { nemo_centered_placement_grid_free (container->details->dnd_grid); } container->details->dnd_grid = nemo_centered_placement_grid_new (container, container->details->horizontal); nemo_centered_placement_grid_pre_populate (container->details->dnd_grid, container->details->icons, FALSE); selection = nemo_icon_container_get_selection (container); for (p = selection; p != NULL; p = p->next) { NemoFile *file; NemoIcon *icon; gchar *uri; file = p->data; uri = nemo_file_get_uri (file); icon = nemo_icon_container_get_icon_by_uri (container, uri); if (icon != NULL) { nemo_centered_placement_grid_unmark_icon (container->details->dnd_grid, icon); } g_free (uri); } if (!container->details->auto_layout && container->details->keep_aligned) { container->details->insert_dnd_mode = TRUE; } g_list_free (selection); gtk_widget_queue_draw (GTK_WIDGET (container)); } static void free_dnd_grid (NemoIconContainer *container) { g_clear_pointer (&container->details->dnd_grid, nemo_centered_placement_grid_free); container->details->insert_dnd_mode = FALSE; gtk_widget_queue_draw (GTK_WIDGET (container)); } static EelCanvasItem * create_selection_shadow (NemoIconContainer *container, GList *list) { EelCanvasGroup *group; EelCanvas *canvas; int max_x, max_y; int min_x, min_y; GList *p; GtkAllocation allocation; if (list == NULL) { return NULL; } /* if we're only dragging a single item, don't worry about the shadow */ if (list->next == NULL) { return NULL; } canvas = EEL_CANVAS (container); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); /* Creating a big set of rectangles in the canvas can be expensive, so we try to be smart and only create the maximum number of rectangles that we will need, in the vertical/horizontal directions. */ max_x = allocation.width; min_x = -max_x; max_y = allocation.height; min_y = -max_y; /* Create a group, so that it's easier to move all the items around at once. */ group = EEL_CANVAS_GROUP (eel_canvas_item_new (EEL_CANVAS_GROUP (canvas->root), eel_canvas_group_get_type (), NULL)); for (p = list; p != NULL; p = p->next) { NemoDragSelectionItem *item; int x1, y1, x2, y2; GdkRGBA black = { 0, 0, 0, 1 }; item = p->data; if (!item->got_icon_position) { continue; } x1 = item->icon_x; y1 = item->icon_y; x2 = x1 + item->icon_width; y2 = y1 + item->icon_height; if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) eel_canvas_item_new (group, NEMO_TYPE_SELECTION_CANVAS_ITEM, "x1", (double) x1, "y1", (double) y1, "x2", (double) x2, "y2", (double) y2, "outline-color-rgba", &black, "outline-stippling", TRUE, "width_pixels", 1, NULL); } return EEL_CANVAS_ITEM (group); } /* Set the affine instead of the x and y position. * Simple, and setting x and y was broken at one point. */ static void set_shadow_position (EelCanvasItem *shadow, double x, double y) { eel_canvas_item_set (shadow, "x", x, "y", y, NULL); } /* Source-side handling of the drag. */ /* iteration glue struct */ typedef struct { gpointer iterator_context; NemoDragEachSelectedItemDataGet iteratee; gpointer iteratee_data; } IconGetDataBinderContext; static void canvas_rect_world_to_widget (EelCanvas *canvas, EelDRect *world_rect, EelIRect *widget_rect) { EelDRect window_rect; GtkAdjustment *hadj, *vadj; hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)); eel_canvas_world_to_window (canvas, world_rect->x0, world_rect->y0, &window_rect.x0, &window_rect.y0); eel_canvas_world_to_window (canvas, world_rect->x1, world_rect->y1, &window_rect.x1, &window_rect.y1); widget_rect->x0 = (int) window_rect.x0 - gtk_adjustment_get_value (hadj); widget_rect->y0 = (int) window_rect.y0 - gtk_adjustment_get_value (vadj); widget_rect->x1 = (int) window_rect.x1 - gtk_adjustment_get_value (hadj); widget_rect->y1 = (int) window_rect.y1 - gtk_adjustment_get_value (vadj); } static void canvas_widget_to_world (EelCanvas *canvas, double widget_x, double widget_y, double *world_x, double *world_y) { eel_canvas_window_to_world (canvas, widget_x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas))), widget_y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas))), world_x, world_y); } static gboolean icon_get_data_binder (NemoIcon *icon, gpointer data) { IconGetDataBinderContext *context; EelDRect world_rect; EelIRect widget_rect; char *uri; NemoIconContainer *container; context = (IconGetDataBinderContext *)data; g_assert (NEMO_IS_ICON_CONTAINER (context->iterator_context)); container = NEMO_ICON_CONTAINER (context->iterator_context); world_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); canvas_rect_world_to_widget (EEL_CANVAS (container), &world_rect, &widget_rect); uri = nemo_icon_container_get_icon_uri (container, icon); if (uri == NULL) { g_warning ("no URI for one of the iterated icons"); return TRUE; } widget_rect = eel_irect_offset_by (widget_rect, - container->details->dnd_info->drag_info.start_x, - container->details->dnd_info->drag_info.start_y); widget_rect = eel_irect_scale_by (widget_rect, 1 / EEL_CANVAS (container)->pixels_per_unit); /* pass the uri, mouse-relative x/y and icon width/height */ context->iteratee (uri, (int) widget_rect.x0, (int) widget_rect.y0, widget_rect.x1 - widget_rect.x0, widget_rect.y1 - widget_rect.y0, context->iteratee_data); g_free (uri); return TRUE; } /* Iterate over each selected icon in a NemoIconContainer, * calling each_function on each. */ static void nemo_icon_container_each_selected_icon (NemoIconContainer *container, gboolean (*each_function) (NemoIcon *, gpointer), gpointer data) { GList *p; NemoIcon *icon; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (!icon->is_selected) { continue; } if (!each_function (icon, data)) { return; } } } /* Adaptor function used with nemo_icon_container_each_selected_icon * to help iterate over all selected items, passing uris, x, y, w and h * values to the iteratee */ static void each_icon_get_data_binder (NemoDragEachSelectedItemDataGet iteratee, gpointer iterator_context, gpointer data) { IconGetDataBinderContext context; NemoIconContainer *container; g_assert (NEMO_IS_ICON_CONTAINER (iterator_context)); container = NEMO_ICON_CONTAINER (iterator_context); context.iterator_context = iterator_context; context.iteratee = iteratee; context.iteratee_data = data; nemo_icon_container_each_selected_icon (container, icon_get_data_binder, &context); } /* Called when the data for drag&drop is needed */ static void drag_data_get_callback (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, gpointer data) { g_assert (widget != NULL); g_assert (NEMO_IS_ICON_CONTAINER (widget)); g_return_if_fail (context != NULL); /* Call common function from nemo-drag that set's up * the selection data in the right format. Pass it means to * iterate all the selected icons. */ nemo_drag_drag_data_get (widget, context, selection_data, info, time, widget, each_icon_get_data_binder); } /* Target-side handling of the drag. */ static void nemo_icon_container_position_shadow (NemoIconContainer *container, int x, int y) { EelCanvasItem *shadow; double world_x, world_y; shadow = container->details->dnd_info->shadow; if (shadow == NULL) { return; } canvas_widget_to_world (EEL_CANVAS (container), x, y, &world_x, &world_y); set_shadow_position (shadow, world_x, world_y); eel_canvas_item_show (shadow); } static void nemo_icon_container_dropped_icon_feedback (GtkWidget *widget, GtkSelectionData *data, int x, int y) { NemoIconContainer *container; NemoIconDndInfo *dnd_info; container = NEMO_ICON_CONTAINER (widget); dnd_info = container->details->dnd_info; /* Delete old selection list. */ nemo_drag_destroy_selection_list (dnd_info->drag_info.selection_list); dnd_info->drag_info.selection_list = NULL; /* Delete old shadow if any. */ if (dnd_info->shadow != NULL) { /* FIXME bugzilla.gnome.org 42484: * Is a destroy really sufficient here? Who does the unref? */ eel_canvas_item_destroy (dnd_info->shadow); } /* Build the selection list and the shadow. */ dnd_info->drag_info.selection_list = nemo_drag_build_selection_list (data); dnd_info->shadow = create_selection_shadow (container, dnd_info->drag_info.selection_list); nemo_icon_container_position_shadow (container, x, y); } static char * get_direct_save_filename (GdkDragContext *context) { guchar *prop_text; gint prop_len; if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern (NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL, &prop_len, &prop_text)) { return NULL; } /* Zero-terminate the string */ prop_text = g_realloc (prop_text, prop_len + 1); prop_text[prop_len] = '\0'; /* Verify that the file name provided by the source is valid */ if (*prop_text == '\0' || strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) != NULL) { DEBUG ("Invalid filename provided by XDS drag site"); g_free (prop_text); return NULL; } return (gchar *) prop_text; } static void set_direct_save_uri (GtkWidget *widget, GdkDragContext *context, NemoDragInfo *drag_info, int x, int y) { GFile *base, *child; char *filename, *drop_target; gchar *uri; drag_info->got_drop_data_type = TRUE; drag_info->data_type = NEMO_ICON_DND_XDNDDIRECTSAVE; uri = NULL; filename = get_direct_save_filename (context); drop_target = nemo_icon_container_find_drop_target (NEMO_ICON_CONTAINER (widget), context, x, y, NULL, TRUE); if (drop_target && eel_uri_is_trash (drop_target)) { g_free (drop_target); drop_target = NULL; /* Cannot save to trash ...*/ } if (filename != NULL && drop_target != NULL) { /* Resolve relative path */ base = g_file_new_for_uri (drop_target); child = g_file_get_child (base, filename); uri = g_file_get_uri (child); g_object_unref (base); g_object_unref (child); /* Change the uri property */ gdk_property_change (gdk_drag_context_get_source_window (context), gdk_atom_intern (NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), gdk_atom_intern ("text/plain", FALSE), 8, GDK_PROP_MODE_REPLACE, (const guchar *) uri, strlen (uri)); drag_info->direct_save_uri = uri; } g_free (filename); g_free (drop_target); } /* FIXME bugzilla.gnome.org 47445: Needs to become a shared function */ static void get_data_on_first_target_we_support (GtkWidget *widget, GdkDragContext *context, guint32 time, int x, int y) { GtkTargetList *list; GdkAtom target; if (drop_types_list == NULL) { drop_types_list = gtk_target_list_new (drop_types, G_N_ELEMENTS (drop_types) - 1); gtk_target_list_add_text_targets (drop_types_list, NEMO_ICON_DND_TEXT); } if (drop_types_list_root == NULL) { drop_types_list_root = gtk_target_list_new (drop_types, G_N_ELEMENTS (drop_types)); gtk_target_list_add_text_targets (drop_types_list_root, NEMO_ICON_DND_TEXT); } if (nemo_icon_container_get_is_desktop (NEMO_ICON_CONTAINER (widget))) { list = drop_types_list_root; } else { list = drop_types_list; } target = gtk_drag_dest_find_target (widget, context, list); if (target != GDK_NONE) { guint info; NemoDragInfo *drag_info; gboolean found; drag_info = &(NEMO_ICON_CONTAINER (widget)->details->dnd_info->drag_info); found = gtk_target_list_find (list, target, &info); g_assert (found); /* Don't get_data for destructive ops */ if ((info == NEMO_ICON_DND_ROOTWINDOW_DROP || info == NEMO_ICON_DND_XDNDDIRECTSAVE) && !drag_info->drop_occured) { /* We can't call get_data here, because that would make the source execute the rootwin action or the direct save */ drag_info->got_drop_data_type = TRUE; drag_info->data_type = info; } else { if (info == NEMO_ICON_DND_XDNDDIRECTSAVE) { set_direct_save_uri (widget, context, drag_info, x, y); } gtk_drag_get_data (GTK_WIDGET (widget), context, target, time); } } } static void nemo_icon_container_ensure_drag_data (NemoIconContainer *container, GdkDragContext *context, guint32 time) { NemoIconDndInfo *dnd_info; dnd_info = container->details->dnd_info; if (!dnd_info->drag_info.got_drop_data_type) { get_data_on_first_target_we_support (GTK_WIDGET (container), context, time, 0, 0); } } static void drag_end_callback (GtkWidget *widget, GdkDragContext *context, gpointer data) { NemoIconContainer *container; NemoIconDndInfo *dnd_info; container = NEMO_ICON_CONTAINER (widget); free_dnd_grid (container); dnd_info = container->details->dnd_info; nemo_drag_destroy_selection_list (dnd_info->drag_info.selection_list); dnd_info->drag_info.selection_list = NULL; g_clear_pointer (&dnd_info->drag_info.source_fs, g_free); } static NemoIcon * nemo_icon_container_item_at (NemoIconContainer *container, int x, int y) { GList *p; int size; EelDRect point; EelIRect canvas_point; /* build the hit-test rectangle. Base the size on the scale factor to ensure that it is * non-empty even at the smallest scale factor */ size = MAX (1, 1 + (1 / EEL_CANVAS (container)->pixels_per_unit)); point.x0 = x; point.y0 = y; point.x1 = x + size; point.y1 = y + size; for (p = container->details->icons; p != NULL; p = p->next) { NemoIcon *icon; icon = p->data; eel_canvas_w2c (EEL_CANVAS (container), point.x0, point.y0, &canvas_point.x0, &canvas_point.y0); eel_canvas_w2c (EEL_CANVAS (container), point.x1, point.y1, &canvas_point.x1, &canvas_point.y1); if (nemo_icon_canvas_item_hit_test_rectangle (icon->item, canvas_point)) { return icon; } } return NULL; } static char * get_container_uri (NemoIconContainer *container) { char *uri; /* get the URI associated with the container */ uri = NULL; g_signal_emit_by_name (container, "get_container_uri", &uri); return uri; } static gboolean nemo_icon_container_selection_items_local (NemoIconContainer *container, GList *items) { char *container_uri_string; gboolean result; /* must have at least one item */ g_assert (items); /* get the URI associated with the container */ container_uri_string = get_container_uri (container); if (eel_uri_is_desktop (container_uri_string)) { result = nemo_drag_items_on_desktop (items); } else { result = nemo_drag_items_local (container_uri_string, items); } g_free (container_uri_string); return result; } /* handle dropped url */ static void receive_dropped_netscape_url (NemoIconContainer *container, const char *encoded_url, GdkDragContext *context, int x, int y) { char *drop_target; if (encoded_url == NULL) { return; } drop_target = nemo_icon_container_find_drop_target (container, context, x, y, NULL, TRUE); g_signal_emit_by_name (container, "handle_netscape_url", encoded_url, drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } /* handle dropped uri list */ static void receive_dropped_uri_list (NemoIconContainer *container, const char *uri_list, GdkDragContext *context, int x, int y) { char *drop_target; if (uri_list == NULL) { return; } drop_target = nemo_icon_container_find_drop_target (container, context, x, y, NULL, TRUE); g_signal_emit_by_name (container, "handle_uri_list", uri_list, drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } /* handle dropped text */ static void receive_dropped_text (NemoIconContainer *container, const char *text, GdkDragContext *context, int x, int y) { char *drop_target; if (text == NULL) { return; } drop_target = nemo_icon_container_find_drop_target (container, context, x, y, NULL, TRUE); g_signal_emit_by_name (container, "handle_text", text, drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } /* handle dropped raw data */ static void receive_dropped_raw (NemoIconContainer *container, const char *raw_data, int length, const char *direct_save_uri, GdkDragContext *context, int x, int y) { char *drop_target; if (raw_data == NULL) { return; } drop_target = nemo_icon_container_find_drop_target (container, context, x, y, NULL, TRUE); g_signal_emit_by_name (container, "handle_raw", raw_data, length, drop_target, direct_save_uri, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } static int auto_scroll_timeout_callback (gpointer data) { NemoIconContainer *container; GtkWidget *widget; float x_scroll_delta, y_scroll_delta; GdkRectangle exposed_area; GtkAllocation allocation; g_assert (NEMO_IS_ICON_CONTAINER (data)); widget = GTK_WIDGET (data); container = NEMO_ICON_CONTAINER (widget); if (container->details->dnd_info->drag_info.waiting_to_autoscroll && container->details->dnd_info->drag_info.start_auto_scroll_in > g_get_monotonic_time ()) { /* not yet */ return TRUE; } container->details->dnd_info->drag_info.waiting_to_autoscroll = FALSE; nemo_drag_autoscroll_calculate_delta (widget, &x_scroll_delta, &y_scroll_delta); if (x_scroll_delta == 0 && y_scroll_delta == 0) { /* no work */ return TRUE; } /* Clear the old dnd highlight frame */ dnd_highlight_queue_redraw (widget); if (!nemo_icon_container_scroll (container, (int)x_scroll_delta, (int)y_scroll_delta)) { /* the scroll value got pinned to a min or max adjustment value, * we ended up not scrolling */ return TRUE; } /* Make sure the dnd highlight frame is redrawn */ dnd_highlight_queue_redraw (widget); /* update cached drag start offsets */ container->details->dnd_info->drag_info.start_x -= x_scroll_delta; container->details->dnd_info->drag_info.start_y -= y_scroll_delta; /* Due to a glitch in GtkLayout, whe need to do an explicit draw of the exposed * area. * Calculate the size of the area we need to draw */ gtk_widget_get_allocation (widget, &allocation); exposed_area.x = allocation.x; exposed_area.y = allocation.y; exposed_area.width = allocation.width; exposed_area.height = allocation.height; if (x_scroll_delta > 0) { exposed_area.x = exposed_area.width - x_scroll_delta; } else if (x_scroll_delta < 0) { exposed_area.width = -x_scroll_delta; } if (y_scroll_delta > 0) { exposed_area.y = exposed_area.height - y_scroll_delta; } else if (y_scroll_delta < 0) { exposed_area.height = -y_scroll_delta; } /* offset it to 0, 0 */ exposed_area.x -= allocation.x; exposed_area.y -= allocation.y; gtk_widget_queue_draw_area (widget, exposed_area.x, exposed_area.y, exposed_area.width, exposed_area.height); return TRUE; } static void set_up_auto_scroll_if_needed (NemoIconContainer *container) { nemo_drag_autoscroll_start (&container->details->dnd_info->drag_info, GTK_WIDGET (container), auto_scroll_timeout_callback, container); } static void stop_auto_scroll (NemoIconContainer *container) { nemo_drag_autoscroll_stop (&container->details->dnd_info->drag_info); } static NemoIcon * get_icon_from_drag_info (NemoIconContainer *container, NemoDragSelectionItem *item, time_t now, gint monitor) { NemoIcon *icon; NemoFile *file; icon = nemo_icon_container_get_icon_by_uri (container, item->uri); if (icon == NULL) { /* probably dragged from another monitor or screen. Add it to * this screen */ file = nemo_file_get_by_uri (item->uri); nemo_file_set_time_metadata (file, NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP, now); nemo_file_set_is_desktop_orphan (file, FALSE); nemo_file_set_monitor_number (file, monitor); nemo_icon_container_add (container, NEMO_ICON_CONTAINER_ICON_DATA (file)); icon = nemo_icon_container_get_icon_by_uri (container, item->uri); } return icon; } static void handle_local_move (NemoIconContainer *container, double world_x, double world_y) { GList *moved_icons, *p; NemoDragSelectionItem *item; NemoIcon *icon; NemoFile *file = NULL; gint monitor; time_t now; if (container->details->auto_layout) { return; } monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); time (&now); /* Move and select the icons. */ moved_icons = NULL; for (p = container->details->dnd_info->drag_info.selection_list; p != NULL; p = p->next) { item = p->data; icon = nemo_icon_container_get_icon_by_uri (container, item->uri); icon = get_icon_from_drag_info (container, item, now, monitor); file = NEMO_FILE (icon->data); nemo_file_set_is_desktop_orphan (file, FALSE); if (item->got_icon_position) { nemo_icon_container_move_icon (container, icon, world_x + item->icon_x, world_y + item->icon_y, icon->scale, TRUE, TRUE, TRUE); } moved_icons = g_list_prepend (moved_icons, icon); } nemo_icon_container_select_list_unselect_others (container, moved_icons); /* Might have been moved in a way that requires adjusting scroll region. */ nemo_icon_container_update_scroll_region (container); g_list_free (moved_icons); } static void handle_local_grid_container_move (NemoIconContainer *container, double world_x, double world_y) { GList *moved_icons, *p; NemoDragSelectionItem *item; NemoIcon *icon; NemoFile *file; gint monitor; gint drop_x, drop_y; time_t now; if (container->details->auto_layout) { if (nemo_icon_container_get_is_desktop (container)) { item = container->details->dnd_info->drag_info.selection_list->data; if (nemo_icon_container_get_icon_by_uri (container, item->uri)) { return; } } else { return; } } drop_x = (gint)(world_x + 0.5); drop_y = (gint)(world_y + 0.5); monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); time (&now); /* Now move and select the icons of the original drag selection */ moved_icons = NULL; for (p = container->details->dnd_info->drag_info.selection_list; p != NULL; p = p->next) { item = p->data; icon = get_icon_from_drag_info (container, item, now, monitor); file = NEMO_FILE (icon->data); nemo_file_set_is_desktop_orphan (file, FALSE); nemo_icon_container_move_icon (container, icon, item->icon_x + drop_x, item->icon_y + drop_y, icon->scale, TRUE, TRUE, TRUE); moved_icons = g_list_prepend (moved_icons, icon); } nemo_icon_container_select_list_unselect_others (container, moved_icons); g_list_free (moved_icons); } static void handle_nonlocal_move (NemoIconContainer *container, GdkDragAction action, int x, int y, const char *target_uri, gboolean icon_hit) { GList *source_uris, *p; GArray *source_item_locations; gboolean free_target_uri, is_rtl; int index, item_x; GtkAllocation allocation; if (container->details->dnd_info->drag_info.selection_list == NULL) { return; } source_uris = NULL; for (p = container->details->dnd_info->drag_info.selection_list; p != NULL; p = p->next) { /* do a shallow copy of all the uri strings of the copied files */ source_uris = g_list_prepend (source_uris, ((NemoDragSelectionItem *)p->data)->uri); } source_uris = g_list_reverse (source_uris); is_rtl = nemo_icon_container_is_layout_rtl (container); source_item_locations = g_array_new (FALSE, TRUE, sizeof (GdkPoint)); if (!icon_hit) { /* Drop onto a container. Pass along the item points to allow placing * the items in their same relative positions in the new container. */ source_item_locations = g_array_set_size (source_item_locations, g_list_length (container->details->dnd_info->drag_info.selection_list)); for (index = 0, p = container->details->dnd_info->drag_info.selection_list; p != NULL; index++, p = p->next) { item_x = ((NemoDragSelectionItem *)p->data)->icon_x; if (is_rtl) item_x = -item_x - ((NemoDragSelectionItem *)p->data)->icon_width; g_array_index (source_item_locations, GdkPoint, index).x = item_x; g_array_index (source_item_locations, GdkPoint, index).y = ((NemoDragSelectionItem *)p->data)->icon_y; } } free_target_uri = FALSE; /* Rewrite internal desktop URIs to the normal target uri */ if (eel_uri_is_desktop (target_uri)) { target_uri = nemo_get_desktop_directory_uri (); free_target_uri = TRUE; } if (is_rtl) { gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); x = nemo_icon_container_get_canvas_width (container, allocation) - x; } /* start the copy */ g_signal_emit_by_name (container, "move_copy_items", source_uris, source_item_locations, target_uri, action, x, y); if (free_target_uri) { g_free ((char *)target_uri); } g_list_free (source_uris); g_array_free (source_item_locations, TRUE); } static char * nemo_icon_container_find_drop_target (NemoIconContainer *container, GdkDragContext *context, int x, int y, gboolean *icon_hit, gboolean rewrite_desktop) { NemoIcon *drop_target_icon; double world_x, world_y; NemoFile *file; char *icon_uri; char *container_uri; if (icon_hit) { *icon_hit = FALSE; } if (!container->details->dnd_info->drag_info.got_drop_data_type) { return NULL; } canvas_widget_to_world (EEL_CANVAS (container), x, y, &world_x, &world_y); /* FIXME bugzilla.gnome.org 42485: * These "can_accept_items" tests need to be done by * the icon view, not here. This file is not supposed to know * that the target is a file. */ /* Find the item we hit with our drop, if any */ drop_target_icon = nemo_icon_container_item_at (container, world_x, world_y); if (drop_target_icon != NULL) { icon_uri = nemo_icon_container_get_icon_uri (container, drop_target_icon); if (icon_uri != NULL) { file = nemo_file_get_by_uri (icon_uri); if (!nemo_drag_can_accept_info (file, container->details->dnd_info->drag_info.data_type, container->details->dnd_info->drag_info.selection_list)) { /* the item we dropped our selection on cannot accept the items, * do the same thing as if we just dropped the items on the canvas */ drop_target_icon = NULL; } g_free (icon_uri); nemo_file_unref (file); } } if (drop_target_icon == NULL) { if (icon_hit) { *icon_hit = FALSE; } container_uri = get_container_uri (container); if (rewrite_desktop && container_uri != NULL && eel_uri_is_desktop (container_uri)) { g_free (container_uri); container_uri = nemo_get_desktop_directory_uri (); } return container_uri; } if (icon_hit) { *icon_hit = TRUE; } return nemo_icon_container_get_icon_drop_target_uri (container, drop_target_icon); } static void prep_selection (NemoIconContainer *container, double world_x, double world_y) { NemoCenteredPlacementGrid *grid; gint drop_x, drop_y; GList *p, *push_list; GdkRectangle drop_rect, iter_rect; NemoDragSelectionItem *item; NemoIcon *icon; NemoFile *file; gint monitor; time_t now; gboolean drop_position_free; gboolean iter_is_free; if (!NEMO_ICON_CONTAINER_GET_CLASS (container)->is_grid_container) { return; } drop_x = (gint)(world_x + 0.5); drop_y = (gint)(world_y + 0.5); monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); time (&now); /* For keep-aligned mode, we need to determine: * * - If our 'drop point' is in a grid position currently occupied by another icon * (one not in the selection list itself,) then we're in 'insert_dnd_mode' - which means, * we'll push existing icons in 'front' of our drop point (according to our grid * direction) to make room to place our selection list in order from that point. * * - If we're not in insert_dnd_mode, we check if the apparent drop positions of each * icon are empty - if they are, we just drop the icons where their DnD clone was * when we ended the drag. If they aren't empty, we apply our grid functions to * find an available spot for the ones that don't fit */ grid = container->details->dnd_grid; nemo_centered_placement_grid_get_current_position_rect (grid, drop_x, drop_y, &drop_rect, &drop_position_free); if (container->details->keep_aligned) { if (drop_position_free) { /* Not insert mode, but with keep_aligned active, try to drop icons in their * new relative spots, or, failing that, lay down the positions in some valid * position */ GList *unplaced_list, *placed_list; unplaced_list = placed_list = NULL; for (p = container->details->dnd_info->drag_info.selection_list; p != NULL; p = p->next) { item = p->data; /* Clear the grid of any items in the selection list as we go * this may be null if this is a non-local move, which is fine - the * icon won't be there anyhow. */ icon = nemo_icon_container_get_icon_by_uri (grid->container, item->uri); if (icon != NULL) { nemo_centered_placement_grid_unmark_icon (grid, icon); } if (item->got_icon_position) { gint y_shift; if (icon && icon->item) { gdouble y1, y2; y1 = y2 = 0; nemo_icon_canvas_item_get_bounds_for_entire_item (icon->item, NULL, &y1, NULL, &y2); y_shift = (gint) ((y2 - y1) / 2); } else { y_shift = item->icon_height / 2; } nemo_centered_placement_grid_get_current_position_rect (grid, drop_x + item->icon_x + item->icon_width / 2, drop_y + item->icon_y + y_shift, &iter_rect, &iter_is_free); if (!iter_is_free) { item->got_icon_position = FALSE; unplaced_list = g_list_prepend (unplaced_list, item); } else { nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, /* may be null - it's ok */ iter_rect.x - drop_x, iter_rect.y - drop_y, &item->icon_x, &item->icon_y); nemo_centered_placement_grid_mark_position (grid, iter_rect.x, iter_rect.y); placed_list = g_list_prepend (placed_list, item); } } else { unplaced_list = g_list_prepend (unplaced_list, item); } } /* Start searching for free spots beyond our drop point * and reposition the unplaced icons by our rules */ iter_rect.x = drop_rect.x; iter_rect.y = drop_rect.y; unplaced_list = g_list_reverse (unplaced_list); for (p = unplaced_list; p != NULL; p = p->next) { item = p->data; icon = nemo_icon_container_get_icon_by_uri (container, item->uri); nemo_centered_placement_grid_get_next_position_rect (grid, &iter_rect, &iter_rect, &iter_is_free); if (iter_is_free) { item->icon_x = iter_rect.x; item->icon_y = iter_rect.y; } else { while (!iter_is_free) { nemo_centered_placement_grid_get_next_position_rect (grid, &iter_rect, &iter_rect, &iter_is_free); } item->icon_x = iter_rect.x; item->icon_y = iter_rect.y; } nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, iter_rect.x - drop_x, iter_rect.y - drop_y, &item->icon_x, &item->icon_y); nemo_centered_placement_grid_mark_position (grid, iter_rect.x, iter_rect.y); } } else { /* If we're inserting items, we need to also shift icons over that are in our way. * To do this, let's append icons that are subsequent to the drop point until we've * got a contiguous space long enough to hold our original selection *plus* the icons * we've picked up to accomodate them */ push_list = NULL; push_list = nemo_centered_placement_grid_clear_grid_for_selection (grid, drop_x, drop_y, container->details->dnd_info->drag_info.selection_list); /* Move the extra icons that were needed to accomodate the selection, * but don't add them to moved_icons - we don't want them highlighted * when we're done * * The push list has already been adjusted for grid<->nominal, etc.. so * we just move them here. */ for (p = push_list; p != NULL; p = p->next) { item = p->data; /* This icon should exist always */ icon = get_icon_from_drag_info (container, item, now, monitor); if (icon != NULL) { file = NEMO_FILE (icon->data); nemo_file_set_is_desktop_orphan (file, FALSE); nemo_icon_container_move_icon (container, icon, item->icon_x + drop_x, item->icon_y + drop_y, icon->scale, TRUE, TRUE, TRUE); } } nemo_drag_destroy_selection_list (push_list); } } else { iter_rect.x = drop_rect.x; iter_rect.y = drop_rect.y; /* Just a normal move - no alignment - if we're provided a position, let it go wherever it wants. */ for (p = container->details->dnd_info->drag_info.selection_list; p != NULL; p = p->next) { item = p->data; icon = nemo_icon_container_get_icon_by_uri (container, item->uri); if (!item->got_icon_position) { /* If there's no position, place it by grid rules */ nemo_centered_placement_grid_get_next_position_rect (grid, &iter_rect, &iter_rect, &iter_is_free); if (iter_is_free) { item->icon_x = iter_rect.x; item->icon_y = iter_rect.y; } else { while (!iter_is_free) { nemo_centered_placement_grid_get_next_position_rect (grid, &iter_rect, &iter_rect, &iter_is_free); } item->icon_x = iter_rect.x; item->icon_y = iter_rect.y; } nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, item->icon_x - drop_x, item->icon_y - drop_y, &item->icon_x, &item->icon_y); } } } } static void nemo_icon_container_receive_dropped_icons (NemoIconContainer *container, GdkDragContext *context, int x, int y) { char *drop_target; gboolean local_move_only; double world_x, world_y; gboolean icon_hit; GdkDragAction action, real_action; drop_target = NULL; if (container->details->dnd_info->drag_info.selection_list == NULL) { return; } real_action = gdk_drag_context_get_selected_action (context); if (real_action == GDK_ACTION_ASK) { /* FIXME bugzilla.gnome.org 42485: This belongs in FMDirectoryView, not here. */ /* Check for special case items in selection list */ if (nemo_drag_selection_includes_special_link (container->details->dnd_info->drag_info.selection_list)) { /* We only want to move the trash */ action = GDK_ACTION_MOVE; } else { action = GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK; } real_action = nemo_drag_drop_action_ask (GTK_WIDGET (container), action); } if (real_action > 0) { eel_canvas_window_to_world (EEL_CANVAS (container), x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))), y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))), &world_x, &world_y); drop_target = nemo_icon_container_find_drop_target (container, context, x, y, &icon_hit, FALSE); local_move_only = FALSE; if (!icon_hit && real_action == GDK_ACTION_MOVE) { /* we can just move the icon positions if the move ended up in * the item's parent container */ local_move_only = nemo_icon_container_selection_items_local (container, container->details->dnd_info->drag_info.selection_list); } if (local_move_only) { prep_selection (container, world_x, world_y); if (NEMO_ICON_CONTAINER_GET_CLASS (container)->is_grid_container) { handle_local_grid_container_move (container, world_x, world_y); } else { handle_local_move (container, world_x, world_y); } } else { if (!icon_hit) { prep_selection (container, world_x, world_y); } handle_nonlocal_move (container, real_action, world_x, world_y, drop_target, icon_hit); } } g_free (drop_target); nemo_drag_destroy_selection_list (container->details->dnd_info->drag_info.selection_list); g_clear_pointer (&container->details->dnd_info->drag_info.source_fs, g_free); container->details->dnd_info->drag_info.selection_list = NULL; free_dnd_grid (container); } static void nemo_icon_container_get_drop_action (NemoIconContainer *container, GdkDragContext *context, int x, int y, int *action) { char *drop_target; gboolean icon_hit; double world_x, world_y; icon_hit = FALSE; if (!container->details->dnd_info->drag_info.got_drop_data_type) { /* drag_data_received_callback didn't get called yet */ return; } /* find out if we're over an icon */ canvas_widget_to_world (EEL_CANVAS (container), x, y, &world_x, &world_y); *action = 0; /* case out on the type of object being dragged */ switch (container->details->dnd_info->drag_info.data_type) { case NEMO_ICON_DND_GNOME_ICON_LIST: if (container->details->dnd_info->drag_info.selection_list == NULL) { return; } drop_target = nemo_icon_container_find_drop_target (container, context, x, y, &icon_hit, FALSE); if (!drop_target) { return; } nemo_drag_default_drop_action_for_icons (context, drop_target, container->details->dnd_info->drag_info.selection_list, action, &container->details->dnd_info->drag_info.source_fs, &container->details->dnd_info->drag_info.can_delete_source); g_free (drop_target); break; case NEMO_ICON_DND_URI_LIST: drop_target = nemo_icon_container_find_drop_target (container, context, x, y, &icon_hit, FALSE); *action = nemo_drag_default_drop_action_for_uri_list (context, drop_target); g_free (drop_target); break; case NEMO_ICON_DND_NETSCAPE_URL: *action = nemo_drag_default_drop_action_for_netscape_url (context); break; case NEMO_ICON_DND_ROOTWINDOW_DROP: *action = gdk_drag_context_get_suggested_action (context); break; case NEMO_ICON_DND_TEXT: case NEMO_ICON_DND_XDNDDIRECTSAVE: case NEMO_ICON_DND_RAW: *action = GDK_ACTION_COPY; break; default: break; } } static void set_drop_target (NemoIconContainer *container, NemoIcon *icon) { NemoIcon *old_icon; /* Check if current drop target changed, update icon drop * higlight if needed. */ old_icon = container->details->drop_target; if (icon == old_icon) { return; } /* Remember the new drop target for the next round. */ container->details->drop_target = icon; nemo_icon_container_update_icon (container, old_icon); nemo_icon_container_update_icon (container, icon); if (icon != NULL) { nemo_icon_container_icon_raise (container, icon); } } static void nemo_icon_dnd_update_drop_target (NemoIconContainer *container, GdkDragContext *context, int x, int y) { NemoIcon *icon; NemoFile *file; double world_x, world_y; char *uri; g_assert (NEMO_IS_ICON_CONTAINER (container)); canvas_widget_to_world (EEL_CANVAS (container), x, y, &world_x, &world_y); /* Find the item we hit with our drop, if any. */ icon = nemo_icon_container_item_at (container, world_x, world_y); /* FIXME bugzilla.gnome.org 42485: * These "can_accept_items" tests need to be done by * the icon view, not here. This file is not supposed to know * that the target is a file. */ /* Find if target icon accepts our drop. */ if (icon != NULL) { uri = nemo_icon_container_get_icon_uri (container, icon); file = nemo_file_get_by_uri (uri); g_free (uri); if (!nemo_drag_can_accept_info (file, container->details->dnd_info->drag_info.data_type, container->details->dnd_info->drag_info.selection_list)) { icon = NULL; } nemo_file_unref (file); } set_drop_target (container, icon); } static void nemo_icon_container_free_drag_data (NemoIconContainer *container) { NemoIconDndInfo *dnd_info; dnd_info = container->details->dnd_info; dnd_info->drag_info.got_drop_data_type = FALSE; if (dnd_info->shadow != NULL) { eel_canvas_item_destroy (dnd_info->shadow); dnd_info->shadow = NULL; } if (dnd_info->drag_info.selection_data != NULL) { gtk_selection_data_free (dnd_info->drag_info.selection_data); dnd_info->drag_info.selection_data = NULL; } if (dnd_info->drag_info.direct_save_uri != NULL) { g_free (dnd_info->drag_info.direct_save_uri); dnd_info->drag_info.direct_save_uri = NULL; } } static void drag_leave_callback (GtkWidget *widget, GdkDragContext *context, guint32 time, gpointer data) { NemoIconDndInfo *dnd_info; dnd_info = NEMO_ICON_CONTAINER (widget)->details->dnd_info; if (dnd_info->shadow != NULL) eel_canvas_item_hide (dnd_info->shadow); stop_dnd_highlight (widget); set_drop_target (NEMO_ICON_CONTAINER (widget), NULL); stop_auto_scroll (NEMO_ICON_CONTAINER (widget)); nemo_icon_container_free_drag_data(NEMO_ICON_CONTAINER (widget)); } static void drag_begin_callback (GtkWidget *widget, GdkDragContext *context, gpointer data) { NemoIconContainer *container; cairo_surface_t *surface; double x1, y1, x2, y2, winx, winy; int x_offset, y_offset; int start_x, start_y; container = NEMO_ICON_CONTAINER (widget); start_x = container->details->dnd_info->drag_info.start_x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); start_y = container->details->dnd_info->drag_info.start_y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))); /* create a pixmap and mask to drag with */ surface = nemo_icon_canvas_item_get_drag_surface (container->details->drag_icon->item); /* compute the image's offset */ eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (container->details->drag_icon->item), &x1, &y1, &x2, &y2); eel_canvas_world_to_window (EEL_CANVAS (container), x1, y1, &winx, &winy); x_offset = start_x - winx; y_offset = start_y - winy; cairo_surface_set_device_offset (surface, -x_offset, -y_offset); gtk_drag_set_icon_surface (context, surface); cairo_surface_destroy (surface); } void nemo_icon_dnd_begin_drag (NemoIconContainer *container, GdkDragAction actions, int button, GdkEventMotion *event, int start_x, int start_y) { NemoIconDndInfo *dnd_info; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); g_return_if_fail (event != NULL); dnd_info = container->details->dnd_info; g_return_if_fail (dnd_info != NULL); /* Notice that the event is in bin_window coordinates, because of the way the canvas handles events. */ dnd_info->drag_info.start_x = start_x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))); dnd_info->drag_info.start_y = start_y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))); /* start the drag */ gtk_drag_begin (GTK_WIDGET (container), dnd_info->drag_info.target_list, actions, button, (GdkEvent *) event); } static gboolean drag_highlight_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) { gint width, height; GdkWindow *window; GtkStyleContext *style; window = gtk_widget_get_window (widget); width = gdk_window_get_width (window); height = gdk_window_get_height (window); style = gtk_widget_get_style_context (widget); gtk_style_context_save (style); gtk_style_context_add_class (style, GTK_STYLE_CLASS_DND); gtk_style_context_set_state (style, GTK_STATE_FLAG_FOCUSED); gtk_render_frame (style, cr, 0, 0, width, height); gtk_style_context_restore (style); return FALSE; } /* Queue a redraw of the dnd highlight rect */ static void dnd_highlight_queue_redraw (GtkWidget *widget) { NemoIconDndInfo *dnd_info; int width, height; GtkAllocation allocation; dnd_info = NEMO_ICON_CONTAINER (widget)->details->dnd_info; if (!dnd_info->highlighted) { return; } gtk_widget_get_allocation (widget, &allocation); width = allocation.width; height = allocation.height; /* we don't know how wide the shadow is exactly, * so we expose a 10-pixel wide border */ gtk_widget_queue_draw_area (widget, 0, 0, width, 10); gtk_widget_queue_draw_area (widget, 0, 0, 10, height); gtk_widget_queue_draw_area (widget, 0, height - 10, width, 10); gtk_widget_queue_draw_area (widget, width - 10, 0, 10, height); } static void start_dnd_highlight (GtkWidget *widget) { NemoIconDndInfo *dnd_info; GtkWidget *toplevel; dnd_info = NEMO_ICON_CONTAINER (widget)->details->dnd_info; toplevel = gtk_widget_get_toplevel (widget); if (toplevel != NULL && g_object_get_data (G_OBJECT (toplevel), "is_desktop_window")) { return; } if (!dnd_info->highlighted) { dnd_info->highlighted = TRUE; g_signal_connect_after (widget, "draw", G_CALLBACK (drag_highlight_draw), NULL); dnd_highlight_queue_redraw (widget); } } static void stop_dnd_highlight (GtkWidget *widget) { NemoIconDndInfo *dnd_info; dnd_info = NEMO_ICON_CONTAINER (widget)->details->dnd_info; if (dnd_info->highlighted) { g_signal_handlers_disconnect_by_func (widget, drag_highlight_draw, NULL); dnd_highlight_queue_redraw (widget); dnd_info->highlighted = FALSE; } } static gboolean drag_motion_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, guint32 time) { NemoIconContainer *container; int action; container = NEMO_ICON_CONTAINER (widget); nemo_icon_container_ensure_drag_data (container, context, time); nemo_icon_container_position_shadow (container, x, y); if (container->details->dnd_grid == NULL) { initialize_dnd_grid (container); gtk_widget_queue_draw (widget); } container->details->current_dnd_x = x; container->details->current_dnd_y = y; nemo_icon_dnd_update_drop_target (container, context, x, y); set_up_auto_scroll_if_needed (container); /* Find out what the drop actions are based on our drag selection and * the drop target. */ action = 0; nemo_icon_container_get_drop_action (container, context, x, y, &action); if (action != 0) { start_dnd_highlight (widget); gtk_widget_queue_draw (widget); } gdk_drag_status (context, action, time); return TRUE; } static gboolean drag_drop_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, guint32 time, gpointer data) { NemoIconDndInfo *dnd_info; dnd_info = NEMO_ICON_CONTAINER (widget)->details->dnd_info; /* tell the drag_data_received callback that the drop occured and that it can actually process the actions. make sure it is going to be called at least once. */ dnd_info->drag_info.drop_occured = TRUE; get_data_on_first_target_we_support (widget, context, time, x, y); return TRUE; } void nemo_icon_dnd_end_drag (NemoIconContainer *container) { NemoIconDndInfo *dnd_info; g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); dnd_info = container->details->dnd_info; g_return_if_fail (dnd_info != NULL); stop_auto_scroll (container); /* Do nothing. * Can that possibly be right? */ } /** this callback is called in 2 cases. It is called upon drag_motion events to get the actual data In that case, it just makes sure it gets the data. It is called upon drop_drop events to execute the actual actions on the received action. In that case, it actually first makes sure that we have got the data then processes it. */ static void drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *data, guint info, guint32 time, gpointer user_data) { NemoDragInfo *drag_info; guchar *tmp; const guchar *tmp_raw; int length; gboolean success; drag_info = &(NEMO_ICON_CONTAINER (widget)->details->dnd_info->drag_info); drag_info->got_drop_data_type = TRUE; drag_info->data_type = info; switch (info) { case NEMO_ICON_DND_GNOME_ICON_LIST: nemo_icon_container_dropped_icon_feedback (widget, data, x, y); break; case NEMO_ICON_DND_URI_LIST: case NEMO_ICON_DND_TEXT: case NEMO_ICON_DND_XDNDDIRECTSAVE: case NEMO_ICON_DND_RAW: /* Save the data so we can do the actual work on drop. */ if (drag_info->selection_data != NULL) { gtk_selection_data_free (drag_info->selection_data); } drag_info->selection_data = gtk_selection_data_copy (data); break; /* Netscape keeps sending us the data, even though we accept the first drag */ case NEMO_ICON_DND_NETSCAPE_URL: if (drag_info->selection_data != NULL) { gtk_selection_data_free (drag_info->selection_data); drag_info->selection_data = gtk_selection_data_copy (data); } break; case NEMO_ICON_DND_ROOTWINDOW_DROP: /* Do nothing, this won't even happen, since we don't want to call get_data twice */ break; default: break; } /* this is the second use case of this callback. * we have to do the actual work for the drop. */ if (drag_info->drop_occured) { success = FALSE; switch (info) { case NEMO_ICON_DND_GNOME_ICON_LIST: nemo_icon_container_receive_dropped_icons (NEMO_ICON_CONTAINER (widget), context, x, y); break; case NEMO_ICON_DND_NETSCAPE_URL: receive_dropped_netscape_url (NEMO_ICON_CONTAINER (widget), (char *) gtk_selection_data_get_data (data), context, x, y); success = TRUE; free_dnd_grid (NEMO_ICON_CONTAINER (widget)); break; case NEMO_ICON_DND_URI_LIST: receive_dropped_uri_list (NEMO_ICON_CONTAINER (widget), (char *) gtk_selection_data_get_data (data), context, x, y); success = TRUE; free_dnd_grid (NEMO_ICON_CONTAINER (widget)); break; case NEMO_ICON_DND_TEXT: tmp = gtk_selection_data_get_text (data); receive_dropped_text (NEMO_ICON_CONTAINER (widget), (char *) tmp, context, x, y); success = TRUE; g_free (tmp); free_dnd_grid (NEMO_ICON_CONTAINER (widget)); break; case NEMO_ICON_DND_RAW: length = gtk_selection_data_get_length (data); tmp_raw = gtk_selection_data_get_data (data); receive_dropped_raw (NEMO_ICON_CONTAINER (widget), (const gchar *) tmp_raw, length, drag_info->direct_save_uri, context, x, y); success = TRUE; free_dnd_grid (NEMO_ICON_CONTAINER (widget)); break; case NEMO_ICON_DND_ROOTWINDOW_DROP: /* Do nothing, everything is done by the sender */ break; case NEMO_ICON_DND_XDNDDIRECTSAVE: { const guchar *selection_data; gint selection_length; gint selection_format; selection_data = gtk_selection_data_get_data (drag_info->selection_data); selection_length = gtk_selection_data_get_length (drag_info->selection_data); selection_format = gtk_selection_data_get_format (drag_info->selection_data); if (selection_format == 8 && selection_length == 1 && selection_data[0] == 'F') { gtk_drag_get_data (widget, context, gdk_atom_intern (NEMO_ICON_DND_RAW_TYPE, FALSE), time); return; } else if (selection_format == 8 && selection_length == 1 && selection_data[0] == 'F' && drag_info->direct_save_uri != NULL) { GdkPoint p; GFile *location; location = g_file_new_for_uri (drag_info->direct_save_uri); nemo_file_changes_queue_file_added (location); p.x = x; p.y = y; nemo_file_changes_queue_schedule_position_set ( location, p, nemo_desktop_utils_get_monitor_for_widget (widget)); g_object_unref (location); nemo_file_changes_consume_changes (TRUE); success = TRUE; } free_dnd_grid (NEMO_ICON_CONTAINER (widget)); break; } /* NEMO_ICON_DND_XDNDDIRECTSAVE */ default: break; } gtk_drag_finish (context, success, FALSE, time); nemo_icon_container_free_drag_data (NEMO_ICON_CONTAINER (widget)); set_drop_target (NEMO_ICON_CONTAINER (widget), NULL); /* reinitialise it for the next dnd */ drag_info->drop_occured = FALSE; } } void nemo_icon_dnd_init (NemoIconContainer *container) { GtkTargetList *targets; int n_elements; g_return_if_fail (container != NULL); g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); container->details->dnd_info = g_new0 (NemoIconDndInfo, 1); nemo_drag_init (&container->details->dnd_info->drag_info, drag_types, G_N_ELEMENTS (drag_types), TRUE); /* Set up the widget as a drag destination. * (But not a source, as drags starting from this widget will be * implemented by dealing with events manually.) */ n_elements = G_N_ELEMENTS (drop_types); if (!nemo_icon_container_get_is_desktop (container)) { /* Don't set up rootwindow drop */ n_elements -= 1; } gtk_drag_dest_set (GTK_WIDGET (container), 0, drop_types, n_elements, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); targets = gtk_drag_dest_get_target_list (GTK_WIDGET (container)); gtk_target_list_add_text_targets (targets, NEMO_ICON_DND_TEXT); /* Messages for outgoing drag. */ g_signal_connect (container, "drag_begin", G_CALLBACK (drag_begin_callback), NULL); g_signal_connect (container, "drag_data_get", G_CALLBACK (drag_data_get_callback), NULL); g_signal_connect (container, "drag_end", G_CALLBACK (drag_end_callback), NULL); /* Messages for incoming drag. */ g_signal_connect (container, "drag_data_received", G_CALLBACK (drag_data_received_callback), NULL); g_signal_connect (container, "drag_motion", G_CALLBACK (drag_motion_callback), NULL); g_signal_connect (container, "drag_drop", G_CALLBACK (drag_drop_callback), NULL); g_signal_connect (container, "drag_leave", G_CALLBACK (drag_leave_callback), NULL); } void nemo_icon_dnd_fini (NemoIconContainer *container) { g_return_if_fail (NEMO_IS_ICON_CONTAINER (container)); if (container->details->dnd_info != NULL) { stop_auto_scroll (container); nemo_drag_finalize (&container->details->dnd_info->drag_info); container->details->dnd_info = NULL; } } nemo-4.4.2/libnemo-private/nemo-icon-dnd.h000066400000000000000000000037621357442400300203660ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-icon-dnd.h - Drag & drop handling for the icon container widget. Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Ettore Perazzoli , Darin Adler , Andy Hertzfeld */ #ifndef NEMO_ICON_DND_H #define NEMO_ICON_DND_H #include #include /* DnD-related information. */ typedef struct { /* inherited drag info context */ NemoDragInfo drag_info; gboolean highlighted; /* Shadow for the icons being dragged. */ EelCanvasItem *shadow; } NemoIconDndInfo; void nemo_icon_dnd_init (NemoIconContainer *container); void nemo_icon_dnd_fini (NemoIconContainer *container); void nemo_icon_dnd_begin_drag (NemoIconContainer *container, GdkDragAction actions, gint button, GdkEventMotion *event, int start_x, int start_y); void nemo_icon_dnd_end_drag (NemoIconContainer *container); #endif /* NEMO_ICON_DND_H */ nemo-4.4.2/libnemo-private/nemo-icon-info.c000066400000000000000000000441041357442400300205420ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-icon-info.c * Copyright (C) 2007 Red Hat, Inc., Alexander Larsson * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include "nemo-icon-info.h" #include "nemo-icon-names.h" #include "nemo-default-file-icon.h" #include #include static void schedule_reap_cache (void); static void pixbuf_toggle_notify (gpointer info, GObject *object, gboolean is_last_ref) { NemoIconInfo *icon = info; if (is_last_ref) { icon->sole_owner = TRUE; g_object_remove_toggle_ref (object, pixbuf_toggle_notify, info); icon->last_use_time = g_get_monotonic_time (); schedule_reap_cache (); } } static void nemo_icon_info_free (NemoIconInfo *icon) { g_return_if_fail (icon != NULL); if (!icon->sole_owner && icon->pixbuf) { g_object_remove_toggle_ref (G_OBJECT (icon->pixbuf), pixbuf_toggle_notify, icon); } if (icon->pixbuf) { g_object_unref (icon->pixbuf); } g_free (icon->icon_name); g_slice_free (NemoIconInfo, icon); } NemoIconInfo * nemo_icon_info_ref (NemoIconInfo *icon) { g_return_val_if_fail (icon != NULL, NULL); icon->ref_count++; return icon; } void nemo_icon_info_unref (NemoIconInfo *icon) { g_return_if_fail (icon != NULL); g_return_if_fail (icon->ref_count > 0); icon->ref_count--; if (icon->ref_count == 0) { nemo_icon_info_free (icon); } } void nemo_icon_info_clear (NemoIconInfo **info) { gpointer _info; _info = *info; if (_info) { *info = NULL; nemo_icon_info_unref (_info); } } static NemoIconInfo * nemo_icon_info_create (void) { NemoIconInfo *icon; icon = g_slice_new0 (NemoIconInfo); icon->last_use_time = g_get_monotonic_time (); icon->sole_owner = TRUE; icon->ref_count = 1; return icon; } gboolean nemo_icon_info_is_fallback (NemoIconInfo *icon) { return icon->pixbuf == NULL; } NemoIconInfo * nemo_icon_info_new_for_pixbuf (GdkPixbuf *pixbuf, gint scale) { NemoIconInfo *icon; icon = nemo_icon_info_create (); if (pixbuf) { icon->pixbuf = g_object_ref (pixbuf); } icon->orig_scale = scale; return icon; } static NemoIconInfo * nemo_icon_info_new_for_icon_info (GtkIconInfo *icon_info, gint scale) { NemoIconInfo *icon; const char *filename; char *basename, *p; icon = nemo_icon_info_create (); icon->pixbuf = gtk_icon_info_load_icon (icon_info, NULL); filename = gtk_icon_info_get_filename (icon_info); if (filename != NULL) { basename = g_path_get_basename (filename); p = strrchr (basename, '.'); if (p) { *p = 0; } icon->icon_name = basename; } icon->orig_scale = scale; return icon; } typedef struct { GIcon *icon; int size; } IconKey; static GHashTable *loadable_icon_cache = NULL; static GHashTable *themed_icon_cache = NULL; static guint reap_cache_timeout = 0; #define MICROSEC_PER_SEC ((guint64)1000000L) static guint time_now; static gboolean reap_old_icon (gpointer key, gpointer value, gpointer user_info) { NemoIconInfo *icon = value; gboolean *reapable_icons_left = user_info; if (icon->sole_owner) { if (time_now - icon->last_use_time > (gint64)(30 * MICROSEC_PER_SEC)) { /* This went unused 30 secs ago. reap */ return TRUE; } else { /* We can reap this soon */ *reapable_icons_left = TRUE; } } return FALSE; } static gboolean reap_cache (gpointer data) { gboolean reapable_icons_left; reapable_icons_left = TRUE; time_now = g_get_monotonic_time (); if (loadable_icon_cache) { g_hash_table_foreach_remove (loadable_icon_cache, reap_old_icon, &reapable_icons_left); } if (themed_icon_cache) { g_hash_table_foreach_remove (themed_icon_cache, reap_old_icon, &reapable_icons_left); } if (reapable_icons_left) { return TRUE; } else { reap_cache_timeout = 0; return FALSE; } } static void schedule_reap_cache (void) { if (reap_cache_timeout == 0) { reap_cache_timeout = g_timeout_add_seconds_full (0, 5, reap_cache, NULL, NULL); } } void nemo_icon_info_clear_caches (void) { if (loadable_icon_cache) { g_hash_table_remove_all (loadable_icon_cache); } if (themed_icon_cache) { g_hash_table_remove_all (themed_icon_cache); } } static guint icon_key_hash (IconKey *key) { return g_icon_hash (key->icon) ^ key->size; } static gboolean icon_key_equal (const IconKey *a, const IconKey *b) { return a->size == b->size && g_icon_equal (a->icon, b->icon); } static IconKey * icon_key_new (GIcon *icon, int size) { IconKey *key; key = g_slice_new (IconKey); key->icon = g_object_ref (icon); key->size = size; return key; } static void icon_key_free (IconKey *key) { g_object_unref (key->icon); g_slice_free (IconKey, key); } NemoIconInfo * nemo_icon_info_lookup (GIcon *icon, int size, int scale) { GtkIconTheme *icon_theme; GtkIconInfo *gtkicon_info; NemoIconInfo *icon_info; icon_theme = gtk_icon_theme_get_default (); if (G_IS_LOADABLE_ICON (icon)) { GdkPixbuf *pixbuf; IconKey lookup_key; IconKey *key; GInputStream *stream; if (loadable_icon_cache == NULL) { loadable_icon_cache = g_hash_table_new_full ((GHashFunc) icon_key_hash, (GEqualFunc) icon_key_equal, (GDestroyNotify) icon_key_free, (GDestroyNotify) nemo_icon_info_free); } lookup_key.icon = icon; lookup_key.size = size; icon_info = g_hash_table_lookup (loadable_icon_cache, &lookup_key); if (icon_info) { return nemo_icon_info_ref (icon_info); } pixbuf = NULL; stream = g_loadable_icon_load (G_LOADABLE_ICON (icon), size * scale, NULL, NULL, NULL); if (stream) { pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, size * scale, size * scale, TRUE, NULL, NULL); g_input_stream_close (stream, NULL, NULL); g_object_unref (stream); } if (!pixbuf) { gtkicon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, "text-x-generic", size, scale, GTK_ICON_LOOKUP_FORCE_SIZE); pixbuf = gtk_icon_info_load_icon (gtkicon_info, NULL); } icon_info = nemo_icon_info_new_for_pixbuf (pixbuf, scale); key = icon_key_new (icon, size); g_hash_table_insert (loadable_icon_cache, key, icon_info); g_clear_object (&pixbuf); return nemo_icon_info_ref (icon_info); } else { IconKey lookup_key; IconKey *key; if (themed_icon_cache == NULL) { themed_icon_cache = g_hash_table_new_full ((GHashFunc) icon_key_hash, (GEqualFunc) icon_key_equal, (GDestroyNotify) icon_key_free, (GDestroyNotify) nemo_icon_info_free); } lookup_key.icon = icon; lookup_key.size = size; icon_info = g_hash_table_lookup (themed_icon_cache, &lookup_key); if (icon_info) { return nemo_icon_info_ref (icon_info); } gtkicon_info = NULL; gtkicon_info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, icon, size, scale, GTK_ICON_LOOKUP_FORCE_SIZE); if (!gtkicon_info) { gtkicon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, "text-x-generic", size, scale, GTK_ICON_LOOKUP_FORCE_SIZE); } icon_info = nemo_icon_info_new_for_icon_info (gtkicon_info, scale); g_object_unref (gtkicon_info); key = icon_key_new (icon, size); g_hash_table_insert (themed_icon_cache, key, icon_info); return nemo_icon_info_ref (icon_info); } } NemoIconInfo * nemo_icon_info_lookup_from_name (const char *name, int size, int scale) { GIcon *icon; NemoIconInfo *info; icon = g_themed_icon_new (name); info = nemo_icon_info_lookup (icon, size, scale); g_object_unref (icon); return info; } NemoIconInfo * nemo_icon_info_lookup_from_path (const char *path, int size, int scale) { GFile *icon_file; GIcon *icon; NemoIconInfo *info; icon_file = g_file_new_for_path (path); icon = g_file_icon_new (icon_file); info = nemo_icon_info_lookup (icon, size, scale); g_object_unref (icon); g_object_unref (icon_file); return info; } GdkPixbuf * nemo_icon_info_get_pixbuf_nodefault (NemoIconInfo *icon) { GdkPixbuf *res; if (icon->pixbuf == NULL) { res = NULL; } else { res = g_object_ref (icon->pixbuf); if (icon->sole_owner) { icon->sole_owner = FALSE; g_object_add_toggle_ref (G_OBJECT (res), pixbuf_toggle_notify, icon); } } return res; } GdkPixbuf * nemo_icon_info_get_pixbuf (NemoIconInfo *icon) { GdkPixbuf *res; res = nemo_icon_info_get_pixbuf_nodefault (icon); if (res == NULL) { res = gdk_pixbuf_new_from_data (nemo_default_file_icon, GDK_COLORSPACE_RGB, TRUE, 8, nemo_default_file_icon_width, nemo_default_file_icon_height, nemo_default_file_icon_width * 4, /* stride */ NULL, /* don't destroy info */ NULL); } return res; } GdkPixbuf * nemo_icon_info_get_pixbuf_nodefault_at_size (NemoIconInfo *icon, gsize forced_size) { GdkPixbuf *pixbuf, *scaled_pixbuf; guint w, h, s; double scale; pixbuf = nemo_icon_info_get_pixbuf_nodefault (icon); if (pixbuf == NULL) return NULL; w = gdk_pixbuf_get_width (pixbuf) / icon->orig_scale; h = gdk_pixbuf_get_height (pixbuf) / icon->orig_scale; s = MAX (w, h); if (s == forced_size) { return pixbuf; } scale = (double)forced_size / s; scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, MAX (w * scale, 1), MAX (h * scale, 1), GDK_INTERP_BILINEAR); g_object_unref (pixbuf); return scaled_pixbuf; } GdkPixbuf * nemo_icon_info_get_pixbuf_at_size (NemoIconInfo *icon, gsize forced_size) { GdkPixbuf *pixbuf, *scaled_pixbuf; guint w, h, s; double scale; pixbuf = nemo_icon_info_get_pixbuf (icon); w = gdk_pixbuf_get_width (pixbuf) / icon->orig_scale; h = gdk_pixbuf_get_height (pixbuf) / icon->orig_scale; s = MAX (w, h); if (s == forced_size) { return pixbuf; } scale = (double)forced_size / s; scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, MAX (w * scale, 1), MAX (h * scale, 1), GDK_INTERP_BILINEAR); g_object_unref (pixbuf); return scaled_pixbuf; } GdkPixbuf * nemo_icon_info_get_desktop_pixbuf_at_size (NemoIconInfo *icon, gsize max_height, gsize max_width) { GdkPixbuf *pixbuf, *scaled_pixbuf; guint w, h; double scale; pixbuf = nemo_icon_info_get_pixbuf (icon); w = gdk_pixbuf_get_width (pixbuf) / icon->orig_scale; h = gdk_pixbuf_get_height (pixbuf) / icon->orig_scale; if (w == max_width || h == max_height) { return pixbuf; } scale = (gdouble) max_height / h; if (w * scale > max_width) { scale = (gdouble) max_width / w; } scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, MAX (w * scale, 1), MAX (h * scale, 1), GDK_INTERP_BILINEAR); g_object_unref (pixbuf); return scaled_pixbuf; } const char * nemo_icon_info_get_used_name (NemoIconInfo *icon) { return icon->icon_name; } /* Return nominal icon size for given zoom level. * @zoom_level: zoom level for which to find matching icon size. * * Return value: icon size between NEMO_ICON_SIZE_SMALLEST and * NEMO_ICON_SIZE_LARGEST, inclusive. */ guint nemo_get_icon_size_for_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLEST: return NEMO_ICON_SIZE_SMALLEST; case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_ICON_SIZE_SMALLER; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_ICON_SIZE_SMALL; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_ICON_SIZE_STANDARD; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_ICON_SIZE_LARGE; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_ICON_SIZE_LARGER; case NEMO_ZOOM_LEVEL_LARGEST: return NEMO_ICON_SIZE_LARGEST; case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_ICON_SIZE_STANDARD); } } guint nemo_get_icon_text_width_for_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLEST: return NEMO_ICON_TEXT_WIDTH_SMALLEST; case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_ICON_TEXT_WIDTH_SMALLER; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_ICON_TEXT_WIDTH_SMALL; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_ICON_TEXT_WIDTH_STANDARD; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_ICON_TEXT_WIDTH_LARGE; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_ICON_TEXT_WIDTH_LARGER; case NEMO_ZOOM_LEVEL_LARGEST: return NEMO_ICON_TEXT_WIDTH_LARGEST; case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_ICON_TEXT_WIDTH_STANDARD); } } guint nemo_get_desktop_icon_size_for_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_DESKTOP_ICON_SIZE_SMALLER; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_DESKTOP_ICON_SIZE_SMALL; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_DESKTOP_ICON_SIZE_STANDARD; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_DESKTOP_ICON_SIZE_LARGE; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_DESKTOP_ICON_SIZE_LARGER; case NEMO_ZOOM_LEVEL_SMALLEST: case NEMO_ZOOM_LEVEL_LARGEST: case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_ICON_SIZE_STANDARD); } } guint nemo_get_desktop_text_width_for_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_DESKTOP_TEXT_WIDTH_SMALLER; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_DESKTOP_TEXT_WIDTH_SMALL; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_DESKTOP_TEXT_WIDTH_STANDARD; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_DESKTOP_TEXT_WIDTH_LARGE; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_DESKTOP_TEXT_WIDTH_LARGER; case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_DESKTOP_TEXT_WIDTH_STANDARD); } } guint nemo_get_list_icon_size_for_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLEST: return NEMO_LIST_ICON_SIZE_SMALLEST; case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_LIST_ICON_SIZE_SMALLEST; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_LIST_ICON_SIZE_SMALLER; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_LIST_ICON_SIZE_SMALL; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_LIST_ICON_SIZE_STANDARD; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_LIST_ICON_SIZE_LARGE; case NEMO_ZOOM_LEVEL_LARGEST: return NEMO_LIST_ICON_SIZE_LARGER; case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_ICON_SIZE_STANDARD); } } gint nemo_get_icon_size_for_stock_size (GtkIconSize size) { gint w, h; if (gtk_icon_size_lookup (size, &w, &h)) { return MAX (w, h); } return NEMO_ICON_SIZE_STANDARD; } guint nemo_icon_get_emblem_size_for_icon_size (guint size) { if (size >= 96) return 48; if (size >= 64) return 32; if (size >= 48) return 24; if (size >= 24) return 16; if (size >= 16) return 12; return 0; /* no emblems for smaller sizes */ } GIcon * nemo_user_special_directory_get_gicon (GUserDirectory directory) { #define ICON_CASE(x) \ case G_USER_DIRECTORY_ ## x:\ return g_themed_icon_new (NEMO_ICON_FOLDER_ ## x); switch (directory) { ICON_CASE (DESKTOP); ICON_CASE (DOCUMENTS); ICON_CASE (DOWNLOAD); ICON_CASE (MUSIC); ICON_CASE (PICTURES); ICON_CASE (PUBLIC_SHARE); ICON_CASE (TEMPLATES); ICON_CASE (VIDEOS); case G_USER_N_DIRECTORIES: default: return g_themed_icon_new ("folder"); } #undef ICON_CASE } nemo-4.4.2/libnemo-private/nemo-icon-info.h000066400000000000000000000123601357442400300205460ustar00rootroot00000000000000#ifndef NEMO_ICON_INFO_H #define NEMO_ICON_INFO_H #include #include #include #include #include G_BEGIN_DECLS /* Names for Nemo's different zoom levels, from tiniest items to largest items */ typedef enum { NEMO_ZOOM_LEVEL_NULL = -1, NEMO_ZOOM_LEVEL_SMALLEST = 0, NEMO_ZOOM_LEVEL_SMALLER, NEMO_ZOOM_LEVEL_SMALL, NEMO_ZOOM_LEVEL_STANDARD, NEMO_ZOOM_LEVEL_LARGE, NEMO_ZOOM_LEVEL_LARGER, NEMO_ZOOM_LEVEL_LARGEST } NemoZoomLevel; #define NEMO_ZOOM_LEVEL_N_ENTRIES (NEMO_ZOOM_LEVEL_LARGEST + 1) /* Nominal icon sizes for each Nemo zoom level. * This scheme assumes that icons are designed to * fit in a square space, though each image needn't * be square. Since individual icons can be stretched, * each icon is not constrained to this nominal size. */ #define NEMO_COMPACT_FORCED_ICON_SIZE 16 #define NEMO_LIST_ICON_SIZE_SMALLEST 16 #define NEMO_LIST_ICON_SIZE_SMALLER 24 #define NEMO_LIST_ICON_SIZE_SMALL 32 #define NEMO_LIST_ICON_SIZE_STANDARD 48 #define NEMO_LIST_ICON_SIZE_LARGE 72 #define NEMO_LIST_ICON_SIZE_LARGER 96 #define NEMO_LIST_ICON_SIZE_LARGEST 192 #define NEMO_ICON_SIZE_SMALLEST 24 #define NEMO_ICON_SIZE_SMALLER 32 #define NEMO_ICON_SIZE_SMALL 48 #define NEMO_ICON_SIZE_STANDARD 64 #define NEMO_ICON_SIZE_LARGE 96 #define NEMO_ICON_SIZE_LARGER 128 #define NEMO_ICON_SIZE_LARGEST 256 #define NEMO_DESKTOP_ICON_SIZE_SMALLER 24 #define NEMO_DESKTOP_ICON_SIZE_SMALL 32 #define NEMO_DESKTOP_ICON_SIZE_STANDARD 48 #define NEMO_DESKTOP_ICON_SIZE_LARGE 64 #define NEMO_DESKTOP_ICON_SIZE_LARGER 96 #define NEMO_DESKTOP_TEXT_WIDTH_SMALLER 64 #define NEMO_DESKTOP_TEXT_WIDTH_SMALL 84 #define NEMO_DESKTOP_TEXT_WIDTH_STANDARD 110 #define NEMO_DESKTOP_TEXT_WIDTH_LARGE 150 #define NEMO_DESKTOP_TEXT_WIDTH_LARGER 200 #define NEMO_ICON_TEXT_WIDTH_SMALLEST 0 #define NEMO_ICON_TEXT_WIDTH_SMALLER 64 #define NEMO_ICON_TEXT_WIDTH_SMALL 84 #define NEMO_ICON_TEXT_WIDTH_STANDARD 110 #define NEMO_ICON_TEXT_WIDTH_LARGE 96 #define NEMO_ICON_TEXT_WIDTH_LARGER 128 #define NEMO_ICON_TEXT_WIDTH_LARGEST 256 /* Maximum size of an icon that the icon factory will ever produce */ #define NEMO_ICON_MAXIMUM_SIZE 320 typedef struct { gint ref_count; gboolean sole_owner; gint64 last_use_time; GdkPixbuf *pixbuf; char *icon_name; gint orig_scale; } NemoIconInfo; NemoIconInfo * nemo_icon_info_ref (NemoIconInfo *icon); void nemo_icon_info_unref (NemoIconInfo *icon); void nemo_icon_info_clear (NemoIconInfo **info); NemoIconInfo * nemo_icon_info_new_for_pixbuf (GdkPixbuf *pixbuf, int scale); NemoIconInfo * nemo_icon_info_lookup (GIcon *icon, int size, int scale); NemoIconInfo * nemo_icon_info_lookup_from_name (const char *name, int size, int scale); NemoIconInfo * nemo_icon_info_lookup_from_path (const char *path, int size, int scale); gboolean nemo_icon_info_is_fallback (NemoIconInfo *icon); GdkPixbuf * nemo_icon_info_get_pixbuf (NemoIconInfo *icon); GdkPixbuf * nemo_icon_info_get_pixbuf_nodefault (NemoIconInfo *icon); GdkPixbuf * nemo_icon_info_get_pixbuf_nodefault_at_size (NemoIconInfo *icon, gsize forced_size); GdkPixbuf * nemo_icon_info_get_pixbuf_at_size (NemoIconInfo *icon, gsize forced_size); GdkPixbuf * nemo_icon_info_get_desktop_pixbuf_at_size (NemoIconInfo *icon, gsize max_height, gsize max_width); const char * nemo_icon_info_get_used_name (NemoIconInfo *icon); void nemo_icon_info_clear_caches (void); /* Relationship between zoom levels and icons sizes. */ guint nemo_get_icon_size_for_zoom_level (NemoZoomLevel zoom_level); guint nemo_get_icon_text_width_for_zoom_level (NemoZoomLevel zoom_level); guint nemo_get_list_icon_size_for_zoom_level (NemoZoomLevel zoom_level); guint nemo_get_desktop_icon_size_for_zoom_level (NemoZoomLevel zoom_level); guint nemo_get_desktop_text_width_for_zoom_level (NemoZoomLevel zoom_level); gint nemo_get_icon_size_for_stock_size (GtkIconSize size); guint nemo_icon_get_emblem_size_for_icon_size (guint size); GIcon * nemo_user_special_directory_get_gicon (GUserDirectory directory); G_END_DECLS #endif /* NEMO_ICON_INFO_H */ nemo-4.4.2/libnemo-private/nemo-icon-names.h000066400000000000000000000051751357442400300207240ustar00rootroot00000000000000#ifndef NEMO_ICON_NAMES_H #define NEMO_ICON_NAMES_H /* Icons for places */ #define NEMO_ICON_COMPUTER "computer" #define NEMO_ICON_DESKTOP "user-desktop" #define NEMO_ICON_FILESYSTEM "drive-harddisk" #define NEMO_ICON_FOLDER "folder" #define NEMO_ICON_FOLDER_REMOTE "folder-remote" #define NEMO_ICON_HOME "user-home" #define NEMO_ICON_NETWORK "network-workgroup" #define NEMO_ICON_NETWORK_SERVER "network-server" #define NEMO_ICON_SEARCH "system-search" #define NEMO_ICON_TRASH "user-trash" #define NEMO_ICON_TRASH_FULL "user-trash-full" #define NEMO_ICON_DELETE "edit-delete-symbolic" #define NEMO_ICON_FOLDER_DESKTOP "user-desktop" #define NEMO_ICON_FOLDER_DOCUMENTS "folder-documents" #define NEMO_ICON_FOLDER_DOWNLOAD "folder-download" #define NEMO_ICON_FOLDER_MUSIC "folder-music" #define NEMO_ICON_FOLDER_PICTURES "folder-pictures" #define NEMO_ICON_FOLDER_PUBLIC_SHARE "folder-publicshare" #define NEMO_ICON_FOLDER_TEMPLATES "folder-templates" #define NEMO_ICON_FOLDER_VIDEOS "folder-videos" #define NEMO_ICON_FOLDER_SAVED_SEARCH "folder-saved-search" /* Other icons */ #define NEMO_ICON_TEMPLATE "text-x-generic-template" /* Icons not provided by fd.o naming spec or nemo itself */ #define NEMO_ICON_BURN "nemo-cd-burner" #define NEMO_ICON_SYMBOLIC_COMPUTER "computer-symbolic" #define NEMO_ICON_SYMBOLIC_DESKTOP "user-desktop-symbolic" #define NEMO_ICON_SYMBOLIC_FILESYSTEM "drive-harddisk-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER "folder-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_REMOTE "folder-remote-symbolic" #define NEMO_ICON_SYMBOLIC_HOME "user-home-symbolic" #define NEMO_ICON_SYMBOLIC_NETWORK "network-workgroup-symbolic" #define NEMO_ICON_SYMBOLIC_NETWORK_SERVER "network-server-symbolic" #define NEMO_ICON_SYMBOLIC_TRASH "user-trash-symbolic" #define NEMO_ICON_SYMBOLIC_TRASH_FULL "user-trash-full-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_DOCUMENTS "folder-documents-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_DOWNLOAD "folder-download-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_MUSIC "folder-music-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_PICTURES "folder-pictures-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_PUBLIC_SHARE "folder-publicshare-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES "folder-templates-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_VIDEOS "folder-videos-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_SAVED_SEARCH "folder-saved-search-symbolic" #define NEMO_ICON_SYMBOLIC_FOLDER_RECENT "document-open-recent-symbolic" #define NEMO_ICON_SYMBOLIC_MISSING_BOOKMARK "nemo-bookmark-not-found-symbolic" #endif /* NEMO_ICON_NAMES_H */ nemo-4.4.2/libnemo-private/nemo-icon-private.h000066400000000000000000000457161357442400300213000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gnome-icon-container-private.h Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Ettore Perazzoli */ #ifndef NEMO_ICON_CONTAINER_PRIVATE_H #define NEMO_ICON_CONTAINER_PRIVATE_H #include #include #include #include #include /* Private NemoIconContainer members. */ typedef struct { double start_x, start_y; EelCanvasItem *selection_rectangle; EelDRect prev_rect; guint timer_id; guint prev_x, prev_y; int last_adj_x; int last_adj_y; gboolean active; } NemoIconRubberbandInfo; typedef enum { DRAG_STATE_INITIAL, DRAG_STATE_MOVE_OR_COPY, DRAG_STATE_STRETCH } DragState; typedef struct { /* Pointer position in canvas coordinates. */ int pointer_x, pointer_y; /* Icon top, left, and size in canvas coordinates. */ int icon_x, icon_y; guint icon_size; } StretchState; typedef enum { AXIS_NONE, AXIS_HORIZONTAL, AXIS_VERTICAL } Axis; enum { LABEL_COLOR, LABEL_COLOR_HIGHLIGHT, LABEL_COLOR_ACTIVE, LABEL_COLOR_PRELIGHT, LABEL_INFO_COLOR, LABEL_INFO_COLOR_HIGHLIGHT, LABEL_INFO_COLOR_ACTIVE, LAST_LABEL_COLOR }; typedef struct { gint icon_pad_left; gint icon_pad_right; gint icon_pad_top; gint icon_pad_bottom; gint container_pad_left; gint container_pad_right; gint container_pad_top; gint container_pad_bottom; gint standard_icon_grid_width; gint text_beside_icon_grid_width; gint desktop_pad_horizontal; gint desktop_pad_vertical; gint snap_size_x; gint snap_size_y; gint max_text_width_standard; gint max_text_width_beside; gint max_text_width_beside_top_to_bottom; gint icon_vertical_adjust; } NemoViewLayoutConstants; typedef struct { NemoIconContainer *container; GtkBorder *borders; int **icon_grid; int *grid_memory; int num_rows; int num_columns; int icon_size; int real_snap_x; int real_snap_y; gboolean horizontal; } NemoCenteredPlacementGrid; typedef struct { NemoIconContainer *container; int **icon_grid; int *grid_memory; int num_rows; int num_columns; gboolean tight; } NemoPlacementGrid; struct NemoIconContainerDetails { /* List of icons. */ GList *icons; GList *new_icons; GHashTable *icon_set; /* Current icon for keyboard navigation. */ NemoIcon *keyboard_focus; NemoIcon *keyboard_rubberband_start; /* Rubberbanding status. */ NemoIconRubberbandInfo rubberband_info; NemoViewLayoutConstants *view_constants; /* Last highlighted drop target. */ NemoIcon *drop_target; /* Current icon with stretch handles, so we have only one. */ NemoIcon *stretch_icon; double stretch_initial_x, stretch_initial_y; /* The position we are scaling to on stretch */ double world_x; double world_y; guint stretch_initial_size; /* Timeout used to make a selected icon fully visible after a short * period of time. (The timeout is needed to make sure * double-clicking still works.) */ guint keyboard_icon_reveal_timer_id; NemoIcon *keyboard_icon_to_reveal; /* If a request is made to reveal an unpositioned icon we remember * it and reveal it once it gets positioned (in relayout). */ NemoIcon *pending_icon_to_reveal; /* If a request is made to rename an unpositioned icon we remember * it and start renaming it once it gets positioned (in relayout). */ NemoIcon *pending_icon_to_rename; /* Remembered information about the start of the current event. */ guint32 button_down_time; /* Drag state. Valid only if drag_button is non-zero. */ guint drag_button; NemoIcon *drag_icon; int drag_x, drag_y; DragState drag_state; gboolean drag_started; StretchState stretch_start; gboolean drag_allow_moves; gboolean icon_selected_on_button_down; guint double_click_button[2]; gboolean skip_rename_on_release; NemoIcon *double_click_icon[2]; /* Both clicks in a double click need to be on the same icon */ NemoIcon *range_selection_base_icon; /* DnD info. */ NemoIconDndInfo *dnd_info; /* Renaming Details */ GtkWidget *rename_widget; /* Editable text item */ char *original_text; /* Copy of editable text for later compare */ char *font; /* specific fonts used to draw labels */ gboolean renaming; /* Idle ID. */ guint idle_id; /* Idle handler for stretch code */ guint stretch_idle_id; /* Align idle id */ guint align_idle_id; /* Used to coalesce selection changed signals in some cases */ guint selection_changed_id; /* zoom level */ int zoom_level; /* font sizes used to draw labels */ int font_size_table[NEMO_ZOOM_LEVEL_LARGEST + 1]; /* State used so arrow keys don't wander if icons aren't lined up. */ int arrow_key_start_x; int arrow_key_start_y; GtkDirectionType arrow_key_direction; /* Mode settings. */ gboolean single_click_mode; gboolean auto_layout; gboolean stored_auto_layout; gboolean click_to_rename; /* Whether for the vertical layout, all columns are supposed to * have the same width. */ gboolean all_columns_same_width; /* Layout mode */ NemoIconLayoutMode layout_mode; /* Label position */ NemoIconLabelPosition label_position; /* Forced icon size, iff greater than 0 */ int forced_icon_size; /* Should the container keep icons aligned to a grid */ gboolean keep_aligned; /* Set to TRUE after first allocation has been done */ gboolean has_been_allocated; int size_allocation_count; guint size_allocation_count_id; int renaming_allocation_count; /* Is the container fixed or resizable */ gboolean is_fixed_size; /* Is the container for a desktop window */ gboolean is_desktop; /* Used by desktop grid container only */ gboolean horizontal; gint h_adjust; gint v_adjust; gboolean show_desktop_tooltips; gboolean show_icon_view_tooltips; /* Ignore the visible area the next time the scroll region is recomputed */ gboolean reset_scroll_region_trigger; gint tooltip_flags; /* Really a NemoFileTooltipFlags */ /* margins to follow, used for the desktop panel avoidance */ int left_margin; int right_margin; int top_margin; int bottom_margin; /* Whether we should use drop shadows for the icon labels or not */ gboolean use_drop_shadows; gboolean drop_shadows_requested; /* interactive search */ gboolean imcontext_changed; /* a11y items used by canvas items */ guint a11y_item_action_idle_handler; time_t layout_timestamp; GtkWidget *search_window; GtkWidget *search_entry; NemoCenteredPlacementGrid *dnd_grid; GQueue* a11y_item_action_queue; int selected_iter; guint search_entry_changed_id; guint typeselect_flush_timeout; gint current_dnd_x; gint current_dnd_y; gboolean insert_dnd_mode; eel_boolean_bit is_loading : 1; eel_boolean_bit needs_resort : 1; eel_boolean_bit store_layout_timestamps : 1; eel_boolean_bit store_layout_timestamps_when_finishing_new_icons : 1; GList *current_selection; gint current_selection_count; }; typedef struct { double width; double height; double x_offset; double y_offset; } NemoCanvasRects; #define GET_VIEW_CONSTANT(c,name) (NEMO_ICON_CONTAINER (c)->details->view_constants->name) #define SNAP_HORIZONTAL(func,x) ((func ((double)((x) - GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) / GET_VIEW_CONSTANT (container, snap_size_x)) * GET_VIEW_CONSTANT (container, snap_size_x)) + GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) #define SNAP_VERTICAL(func, y) ((func ((double)((y) - GET_VIEW_CONSTANT (container, desktop_pad_vertical)) / GET_VIEW_CONSTANT (container, snap_size_y)) * GET_VIEW_CONSTANT (container, snap_size_y)) + GET_VIEW_CONSTANT (container, desktop_pad_vertical)) #define SNAP_NEAREST_HORIZONTAL(x) SNAP_HORIZONTAL (floor, x + .5) #define SNAP_NEAREST_VERTICAL(y) SNAP_VERTICAL (floor, y + .5) #define SNAP_CEIL_HORIZONTAL(x) SNAP_HORIZONTAL (ceil, x) #define SNAP_CEIL_VERTICAL(y) SNAP_VERTICAL (ceil, y) /* Private functions shared by mutiple files. */ NemoIcon *nemo_icon_container_get_icon_by_uri (NemoIconContainer *container, const char *uri); void nemo_icon_container_select_list_unselect_others (NemoIconContainer *container, GList *icons); char * nemo_icon_container_get_icon_uri (NemoIconContainer *container, NemoIcon *icon); char * nemo_icon_container_get_icon_drop_target_uri (NemoIconContainer *container, NemoIcon *icon); void nemo_icon_container_update_icon (NemoIconContainer *container, NemoIcon *icon); gboolean nemo_icon_container_scroll (NemoIconContainer *container, int delta_x, int delta_y); void nemo_icon_container_update_scroll_region (NemoIconContainer *container); gint nemo_icon_container_get_canvas_height (NemoIconContainer *container, GtkAllocation allocation); gint nemo_icon_container_get_canvas_width (NemoIconContainer *container, GtkAllocation allocation); double nemo_icon_container_get_mirror_x_position (NemoIconContainer *container, NemoIcon *icon, double x); void nemo_icon_container_set_rtl_positions (NemoIconContainer *container); void nemo_icon_container_end_renaming_mode (NemoIconContainer *container, gboolean commit); NemoIcon *nemo_icon_container_get_icon_being_renamed (NemoIconContainer *container); void nemo_icon_container_icon_set_position (NemoIconContainer *container, NemoIcon *icon, gdouble x, gdouble y); void nemo_icon_container_icon_get_bounding_box (NemoIconContainer *container, NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage); void nemo_icon_container_move_icon (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position); void nemo_icon_container_icon_raise (NemoIconContainer *container, NemoIcon *icon); void nemo_icon_container_finish_adding_icon (NemoIconContainer *container, NemoIcon *icon); gboolean nemo_icon_container_icon_is_positioned (const NemoIcon *icon); void nemo_icon_container_sort_icons (NemoIconContainer *container, GList **icons); void nemo_icon_container_resort (NemoIconContainer *container); void nemo_icon_container_get_all_icon_bounds (NemoIconContainer *container, double *x1, double *y1, double *x2, double *y2, NemoIconCanvasItemBoundsUsage usage); void nemo_icon_container_store_layout_timestamps_now (NemoIconContainer *container); void nemo_icon_container_redo_layout (NemoIconContainer *container); NemoIconInfo *nemo_icon_container_get_icon_images (NemoIconContainer *container, NemoIconData *data, int size, gboolean for_drag_accept, gboolean *has_open_window); void nemo_icon_container_get_icon_text (NemoIconContainer *container, NemoIconData *data, char **editable_text, char **additional_text, gboolean *pinned, gboolean include_invisible); /* nemo-centered-placement-grid api * * used by nemo-icon-view-grid-container.c, nemo-icon-dnd.h */ NemoCenteredPlacementGrid *nemo_centered_placement_grid_new (NemoIconContainer *container, gboolean horizontal); void nemo_centered_placement_grid_free (NemoCenteredPlacementGrid *grid); void nemo_centered_placement_grid_nominal_to_icon_position (NemoCenteredPlacementGrid *grid, NemoIcon *icon, gint x_nominal, gint y_nominal, gint *x_adjusted, gint *y_adjusted); void nemo_centered_placement_grid_icon_position_to_nominal (NemoCenteredPlacementGrid *grid, NemoIcon *icon, gint x_adjusted, gint y_adjusted, gint *x_nominal, gint *y_nominal); void nemo_centered_placement_grid_mark_icon (NemoCenteredPlacementGrid *grid, NemoIcon *icon); void nemo_centered_placement_grid_unmark_icon (NemoCenteredPlacementGrid *grid, NemoIcon *icon); void nemo_centered_placement_grid_mark_position (NemoCenteredPlacementGrid *grid, gint x, gint y); void nemo_centered_placement_grid_unmark_position (NemoCenteredPlacementGrid *grid, gint x, gint y); void nemo_centered_placement_grid_pre_populate (NemoCenteredPlacementGrid *grid, GList *icons, gboolean ignore_lazy); void nemo_centered_placement_grid_get_next_position_rect (NemoCenteredPlacementGrid *grid, GdkRectangle *in_rect, GdkRectangle *out_rect, gboolean *is_free); void nemo_centered_placement_grid_get_current_position_rect (NemoCenteredPlacementGrid *grid, gint x, gint y, GdkRectangle *rect, gboolean *is_free); NemoIcon * nemo_centered_placement_grid_get_icon_at_position (NemoCenteredPlacementGrid *grid, gint x, gint y); GList * nemo_centered_placement_grid_clear_grid_for_selection (NemoCenteredPlacementGrid *grid, gint start_x, gint start_y, GList *drag_sel_list); /* nemo-placement-grid api * * used by nemo-icon-view-container.c */ NemoPlacementGrid *nemo_placement_grid_new (NemoIconContainer *container, gboolean tight); void nemo_placement_grid_free (NemoPlacementGrid *grid); gboolean nemo_placement_grid_position_is_free (NemoPlacementGrid *grid, EelIRect pos); void nemo_placement_grid_mark (NemoPlacementGrid *grid, EelIRect pos); void nemo_placement_grid_canvas_position_to_grid_position (NemoPlacementGrid *grid, EelIRect canvas_position, EelIRect *grid_position); void nemo_placement_grid_mark_icon (NemoPlacementGrid *grid, NemoIcon *icon); #endif /* NEMO_ICON_CONTAINER_PRIVATE_H */ nemo-4.4.2/libnemo-private/nemo-icon.h000066400000000000000000000043711357442400300176200ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gnome-icon-container-private.h Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Ettore Perazzoli */ #ifndef NEMO_ICON_H #define NEMO_ICON_H #include #include #include #define NEMO_ICON_CONTAINER_ICON_DATA(pointer) \ ((NemoIconData *) (pointer)) typedef struct NemoIconData NemoIconData; typedef void (* NemoIconCallback) (NemoIconData *icon_data, gpointer callback_data); /* An Icon. */ typedef struct { /* Object represented by this icon. */ NemoIconData *data; /* Canvas item for the icon. */ NemoIconCanvasItem *item; /* X/Y coordinates. */ double x, y; /* * In RTL mode x is RTL x position, we use saved_ltr_x for * keeping track of x value before it gets converted into * RTL value, this is used for saving the icon position * to the nemo metafile. */ double saved_ltr_x; /* Scale factor (stretches icon). */ double scale; /* Whether this item is selected. */ eel_boolean_bit is_selected : 1; /* Whether this item was selected before rubberbanding. */ eel_boolean_bit was_selected_before_rubberband : 1; /* Whether this item is visible in the view. */ eel_boolean_bit is_visible : 1; eel_boolean_bit has_lazy_position : 1; } NemoIcon; #endif /* NEMO_ICON_CONTAINER_PRIVATE_H */ nemo-4.4.2/libnemo-private/nemo-job-queue.c000066400000000000000000000152101357442400300205510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-job-queue.c - file operation queue 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include #include "nemo-job-queue.h" #include "nemo-global-preferences.h" struct _NemoJobQueuePriv { GList *queued_jobs; GList *running_jobs; gulong pref_changed_id; gboolean skip_queue; }; enum { NEW_JOB, LAST_SIGNAL }; typedef struct { GIOSchedulerJobFunc job_func; gpointer user_data; NemoProgressInfo *info; GCancellable *cancellable; } Job; static NemoJobQueue *singleton = NULL; static guint signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (NemoJobQueue, nemo_job_queue, G_TYPE_OBJECT); static void nemo_job_queue_finalize (GObject *obj) { NemoJobQueue *self = NEMO_JOB_QUEUE (obj); if (self->priv->queued_jobs != NULL) { g_list_free_full (self->priv->queued_jobs, g_object_unref); } if (self->priv->pref_changed_id != 0) { g_signal_handler_disconnect (nemo_preferences, self->priv->pref_changed_id); self->priv->pref_changed_id = 0; } G_OBJECT_CLASS (nemo_job_queue_parent_class)->finalize (obj); } static GObject * nemo_job_queue_constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *retval; if (singleton != NULL) { return g_object_ref (G_OBJECT (singleton)); } retval = G_OBJECT_CLASS (nemo_job_queue_parent_class)->constructor (type, n_props, props); singleton = NEMO_JOB_QUEUE (retval); g_object_add_weak_pointer (retval, (gpointer) &singleton); return retval; } static void pref_changed_cb (NemoJobQueue *self) { self->priv->skip_queue = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_NEVER_QUEUE_FILE_OPS); } static void nemo_job_queue_init (NemoJobQueue *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_JOB_QUEUE, NemoJobQueuePriv); self->priv->queued_jobs = NULL; self->priv->running_jobs = NULL; self->priv->pref_changed_id = g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_NEVER_QUEUE_FILE_OPS, G_CALLBACK (pref_changed_cb), self); pref_changed_cb (self); } static void nemo_job_queue_class_init (NemoJobQueueClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->constructor = nemo_job_queue_constructor; oclass->finalize = nemo_job_queue_finalize; signals[NEW_JOB] = g_signal_new ("new-job", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 0, NULL); g_type_class_add_private (klass, sizeof (NemoJobQueuePriv)); } static gint compare_info_func (gconstpointer a, gconstpointer b) { Job *job = (Job*) a; return (job->info == b) ? 0 : 1; } static gint compare_job_data_func (gconstpointer a, gconstpointer b) { Job *job = (Job*) a; return (job->job_func == b) ? 0 : 1; } static void job_finished_cb (NemoJobQueue *self, NemoProgressInfo *info) { GList *ptr; ptr = g_list_find_custom (self->priv->running_jobs, info, (GCompareFunc) compare_info_func); if (!ptr) ptr = g_list_find_custom (self->priv->queued_jobs, info, (GCompareFunc) compare_info_func); Job *job = ptr->data; self->priv->running_jobs = g_list_remove (self->priv->running_jobs, job); self->priv->queued_jobs = g_list_remove (self->priv->queued_jobs, job); g_slice_free (Job, job); nemo_job_queue_start_next_job (self); } static void start_job (NemoJobQueue *self, Job *job); NemoJobQueue * nemo_job_queue_get (void) { return g_object_new (NEMO_TYPE_JOB_QUEUE, NULL); } void nemo_job_queue_add_new_job (NemoJobQueue *self, GIOSchedulerJobFunc job_func, gpointer user_data, GCancellable *cancellable, NemoProgressInfo *info, gboolean start_immediately) { if (g_list_find_custom (self->priv->queued_jobs, user_data, (GCompareFunc) compare_job_data_func) != NULL) { g_warning ("Adding the same file job object to the job queue"); return; } Job *new_job = g_slice_new0 (Job); new_job->job_func = job_func; new_job->user_data = user_data; new_job->cancellable = cancellable; new_job->info = info; self->priv->queued_jobs = g_list_append (self->priv->queued_jobs, new_job); nemo_progress_info_queue (info); g_signal_connect_swapped (info, "finished", G_CALLBACK (job_finished_cb), self); if (self->priv->skip_queue || start_immediately) start_job (self, new_job); else nemo_job_queue_start_next_job (self); g_signal_emit (self, signals[NEW_JOB], 0, NULL); } static void start_job (NemoJobQueue *self, Job *job) { self->priv->queued_jobs = g_list_remove (self->priv->queued_jobs, job); g_io_scheduler_push_job (job->job_func, job->user_data, NULL, // destroy notify 0, job->cancellable); self->priv->running_jobs = g_list_append (self->priv->running_jobs, job); } void nemo_job_queue_start_next_job (NemoJobQueue *self) { if (g_list_length (self->priv->running_jobs) == 0 && g_list_length (self->priv->queued_jobs) > 0) start_job (self, self->priv->queued_jobs->data); } void nemo_job_queue_start_job_by_info (NemoJobQueue *self, NemoProgressInfo *info) { GList *target = g_list_find_custom (self->priv->queued_jobs, info, (GCompareFunc) compare_info_func); if (target) start_job (self, target->data); } GList * nemo_job_queue_get_all_jobs (NemoJobQueue *self) { return self->priv->queued_jobs; } nemo-4.4.2/libnemo-private/nemo-job-queue.h000066400000000000000000000050261357442400300205620ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-job-queue.h - file operation queue 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __NEMO_JOB_QUEUE_H__ #define __NEMO_JOB_QUEUE_H__ #include #include #define NEMO_TYPE_JOB_QUEUE nemo_job_queue_get_type() #define NEMO_JOB_QUEUE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_JOB_QUEUE, NemoJobQueue)) #define NEMO_JOB_QUEUE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_JOB_QUEUE, NemoJobQueueClass)) #define NEMO_IS_JOB_QUEUE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_JOB_QUEUE)) #define NEMO_IS_JOB_QUEUE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_JOB_QUEUE)) #define NEMO_JOB_QUEUE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_JOB_QUEUE, NemoJobQueueClass)) typedef struct _NemoJobQueue NemoJobQueue; typedef struct _NemoJobQueueClass NemoJobQueueClass; typedef struct _NemoJobQueuePriv NemoJobQueuePriv; struct _NemoJobQueue { GObject parent; /* private */ NemoJobQueuePriv *priv; }; struct _NemoJobQueueClass { GObjectClass parent_class; }; GType nemo_job_queue_get_type (void); NemoJobQueue *nemo_job_queue_get (void); void nemo_job_queue_add_new_job (NemoJobQueue *self, GIOSchedulerJobFunc job_func, gpointer user_data, GCancellable *cancellable, NemoProgressInfo *info, gboolean start_immediately); void nemo_job_queue_start_next_job (NemoJobQueue *self); void nemo_job_queue_start_job_by_info (NemoJobQueue *self, NemoProgressInfo *info); GList *nemo_job_queue_get_all_jobs (NemoJobQueue *self); G_END_DECLS #endif /* __NEMO_JOB_QUEUE_H__ */ nemo-4.4.2/libnemo-private/nemo-lib-self-check-functions.c000066400000000000000000000023171357442400300234370ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-lib-self-check-functions.c: Wrapper for all self check functions in Nemo proper. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #if ! defined (NEMO_OMIT_SELF_CHECK) #include "nemo-lib-self-check-functions.h" void nemo_run_lib_self_checks (void) { NEMO_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/libnemo-private/nemo-lib-self-check-functions.h000066400000000000000000000036011357442400300234410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-lib-self-check-functions.h: Wrapper and prototypes for all self-check functions in libnemo. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include void nemo_run_lib_self_checks (void); /* Putting the prototypes for these self-check functions in each header file for the files they are defined in would make compiling the self-check framework take way too long (since one file would have to include everything). So we put the list of functions here instead. Instead of just putting prototypes here, we put this macro that can be used to do operations on the whole list of functions. */ #define NEMO_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ macro (nemo_self_check_file_utilities) \ macro (nemo_self_check_file_operations) \ macro (nemo_self_check_directory) \ macro (nemo_self_check_file) \ macro (nemo_self_check_icon_container) \ /* Add new self-check functions to the list above this line. */ /* Generate prototypes for all the functions. */ NEMO_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_SELF_CHECK_FUNCTION_PROTOTYPE) nemo-4.4.2/libnemo-private/nemo-link.c000066400000000000000000000334051357442400300176200ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-link.c: .desktop link files. Copyright (C) 2001 Red Hat, 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 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 historicalied 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Jonathan Blandford Alexander Larsson */ #include #include "nemo-link.h" #include "nemo-directory-notify.h" #include "nemo-directory.h" #include "nemo-file-utilities.h" #include "nemo-file.h" #include "nemo-program-choosing.h" #include "nemo-icon-names.h" #include #include #include #include #include #define MAIN_GROUP "Desktop Entry" #define NEMO_LINK_GENERIC_TAG "Link" #define NEMO_LINK_TRASH_TAG "X-nemo-trash" #define NEMO_LINK_MOUNT_TAG "FSDevice" #define NEMO_LINK_HOME_TAG "X-nemo-home" static gboolean is_link_mime_type (const char *mime_type) { if (mime_type != NULL && g_ascii_strcasecmp (mime_type, "application/x-desktop") == 0) { return TRUE; } return FALSE; } static gboolean is_local_file_a_link (const char *uri) { gboolean link; GFile *file; GFileInfo *info; GError *error; error = NULL; link = FALSE; file = g_file_new_for_uri (uri); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, &error); if (info) { link = is_link_mime_type (g_file_info_get_content_type (info)); g_object_unref (info); } else { g_warning ("Error getting info: %s\n", error->message); g_error_free (error); } g_object_unref (file); return link; } static gboolean _g_key_file_load_from_gfile (GKeyFile *key_file, GFile *file, GKeyFileFlags flags, GError **error) { char *data; gsize len; gboolean res; if (!g_file_load_contents (file, NULL, &data, &len, NULL, error)) { return FALSE; } res = g_key_file_load_from_data (key_file, data, len, flags, error); g_free (data); return res; } static gboolean _g_key_file_save_to_gfile (GKeyFile *key_file, GFile *file, GError **error) { char *data; gsize len; data = g_key_file_to_data (key_file, &len, error); if (data == NULL) { return FALSE; } if (!g_file_replace_contents (file, data, len, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, error)) { g_free (data); return FALSE; } g_free (data); return TRUE; } static GKeyFile * _g_key_file_new_from_uri (const char *uri, GKeyFileFlags flags, GError **error) { GKeyFile *key_file; GFile *file; file = g_file_new_for_uri (uri); key_file = g_key_file_new (); if (!_g_key_file_load_from_gfile (key_file, file, flags, error)) { g_key_file_free (key_file); key_file = NULL; } g_object_unref (file); return key_file; } static char * slurp_key_string (const char *uri, const char *keyname, gboolean localize) { GKeyFile *key_file; char *result; key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL); if (key_file == NULL) { return NULL; } if (localize) { result = g_key_file_get_locale_string (key_file, MAIN_GROUP, keyname, NULL, NULL); } else { result = g_key_file_get_string (key_file, MAIN_GROUP, keyname, NULL); } g_key_file_free (key_file); return result; } gboolean nemo_link_local_create (const char *directory_uri, const char *base_name, const char *display_name, const char *image, const char *target_uri, const GdkPoint *point, int monitor, gboolean unique_filename) { char *real_directory_uri; char *uri, *contents; GFile *file; GList dummy_list; NemoFileChangesQueuePosition item; g_return_val_if_fail (directory_uri != NULL, FALSE); g_return_val_if_fail (base_name != NULL, FALSE); g_return_val_if_fail (display_name != NULL, FALSE); g_return_val_if_fail (target_uri != NULL, FALSE); if (eel_uri_is_trash (directory_uri) || eel_uri_is_search (directory_uri)) { return FALSE; } if (eel_uri_is_desktop (directory_uri)) { real_directory_uri = nemo_get_desktop_directory_uri (); } else { real_directory_uri = g_strdup (directory_uri); } if (unique_filename) { uri = nemo_ensure_unique_file_name (real_directory_uri, base_name, ".desktop"); if (uri == NULL) { g_free (real_directory_uri); return FALSE; } file = g_file_new_for_uri (uri); g_free (uri); } else { char *link_name; GFile *dir; link_name = g_strdup_printf ("%s.desktop", base_name); /* replace '/' with '-', just in case */ g_strdelimit (link_name, "/", '-'); dir = g_file_new_for_uri (directory_uri); file = g_file_get_child (dir, link_name); g_free (link_name); g_object_unref (dir); } g_free (real_directory_uri); contents = g_strdup_printf ("[Desktop Entry]\n" "Encoding=UTF-8\n" "Name=%s\n" "Type=Link\n" "URL=%s\n" "%s%s\n", display_name, target_uri, image != NULL ? "Icon=" : "", image != NULL ? image : ""); if (!g_file_replace_contents (file, contents, strlen (contents), NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, NULL)) { g_free (contents); g_object_unref (file); return FALSE; } g_free (contents); dummy_list.data = file; dummy_list.next = NULL; dummy_list.prev = NULL; nemo_directory_notify_files_added (&dummy_list); if (point != NULL) { item.location = file; item.set = TRUE; item.monitor = monitor; item.point.x = point->x; item.point.y = point->y; item.screen = 0; dummy_list.data = &item; dummy_list.next = NULL; dummy_list.prev = NULL; nemo_directory_schedule_position_set (&dummy_list); } g_object_unref (file); return TRUE; } static const char * get_language (void) { const char * const *langs_pointer; int i; langs_pointer = g_get_language_names (); for (i = 0; langs_pointer[i] != NULL; i++) { /* find first without encoding */ if (strchr (langs_pointer[i], '.') == NULL) { return langs_pointer[i]; } } return NULL; } static gboolean nemo_link_local_set_key (const char *uri, const char *key, const char *value, gboolean localize) { gboolean success; GKeyFile *key_file; GFile *file; file = g_file_new_for_uri (uri); key_file = g_key_file_new (); if (!_g_key_file_load_from_gfile (key_file, file, G_KEY_FILE_KEEP_COMMENTS, NULL)) { g_key_file_free (key_file); g_object_unref (file); return FALSE; } if (localize) { g_key_file_set_locale_string (key_file, MAIN_GROUP, key, get_language (), value); } else { g_key_file_set_string (key_file, MAIN_GROUP, key, value); } success = _g_key_file_save_to_gfile (key_file, file, NULL); g_key_file_free (key_file); g_object_unref (file); return success; } gboolean nemo_link_local_set_text (const char *uri, const char *text) { return nemo_link_local_set_key (uri, "Name", text, TRUE); } gboolean nemo_link_local_set_icon (const char *uri, const char *icon) { return nemo_link_local_set_key (uri, "Icon", icon, FALSE); } char * nemo_link_local_get_text (const char *path) { return slurp_key_string (path, "Name", TRUE); } static char * nemo_link_get_link_uri_from_desktop (GKeyFile *key_file, const char *desktop_file_uri) { GFile *file, *parent; char *type; char *retval; char *scheme; retval = NULL; type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); if (type == NULL) { return NULL; } if (strcmp (type, "URL") == 0) { /* Some old broken desktop files use this nonstandard feature, we need handle it though */ retval = g_key_file_get_string (key_file, MAIN_GROUP, "Exec", NULL); } else if ((strcmp (type, NEMO_LINK_GENERIC_TAG) == 0) || (strcmp (type, NEMO_LINK_MOUNT_TAG) == 0) || (strcmp (type, NEMO_LINK_TRASH_TAG) == 0) || (strcmp (type, NEMO_LINK_HOME_TAG) == 0)) { retval = g_key_file_get_string (key_file, MAIN_GROUP, "URL", NULL); } g_free (type); if (retval != NULL && desktop_file_uri != NULL) { /* Handle local file names. * Ideally, we'd be able to use * g_file_parse_name(), but it does not know how to resolve * relative file names, since the base directory is unknown. */ scheme = g_uri_parse_scheme (retval); if (scheme == NULL) { file = g_file_new_for_uri (desktop_file_uri); parent = g_file_get_parent (file); g_object_unref (file); if (parent != NULL) { file = g_file_resolve_relative_path (parent, retval); g_free (retval); retval = g_file_get_uri (file); g_object_unref (file); g_object_unref (parent); } } g_free (scheme); } return retval; } static char * nemo_link_get_link_name_from_desktop (GKeyFile *key_file) { return g_key_file_get_locale_string (key_file, MAIN_GROUP, "Name", NULL, NULL); } static GIcon * nemo_link_get_link_icon_from_desktop (GKeyFile *key_file) { char *icon_str, *p, *type = NULL; GFile *file; GIcon *icon; /* Look at the Icon: key */ icon_str = g_key_file_get_string (key_file, MAIN_GROUP, "Icon", NULL); /* if it's an absolute path, return a GFileIcon for that path */ if (icon_str != NULL && g_path_is_absolute (icon_str)) { file = g_file_new_for_path (icon_str); icon = g_file_icon_new (file); g_object_unref (file); goto out; } type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); if (icon_str == NULL) { if (g_strcmp0 (type, "Application") == 0) { icon_str = g_strdup ("application-x-executable"); } else if (g_strcmp0 (type, "FSDevice") == 0) { icon_str = g_strdup ("drive-harddisk"); } else if (g_strcmp0 (type, "Directory") == 0) { icon_str = g_strdup (NEMO_ICON_FOLDER); } else if (g_strcmp0 (type, "Service") == 0 || g_strcmp0 (type, "ServiceType") == 0) { icon_str = g_strdup ("folder-remote"); } else { icon_str = g_strdup ("text-x-preview"); } } else { /* Strip out any extension on non-filename icons. Old desktop files may have this */ p = strchr (icon_str, '.'); /* Only strip known icon extensions */ if ((p != NULL) && ((g_ascii_strcasecmp (p, ".png") == 0) || (g_ascii_strcasecmp (p, ".svn") == 0) || (g_ascii_strcasecmp (p, ".jpg") == 0) || (g_ascii_strcasecmp (p, ".xpm") == 0) || (g_ascii_strcasecmp (p, ".bmp") == 0) || (g_ascii_strcasecmp (p, ".jpeg") == 0))) { *p = 0; } } icon = g_themed_icon_new (icon_str); /* apply a link emblem if it's a link */ if (g_strcmp0 (type, "Link") == 0) { GIcon *emblemed, *emblem_icon; GEmblem *emblem; emblem_icon = g_themed_icon_new ("emblem-symbolic-link"); emblem = g_emblem_new (emblem_icon); emblemed = g_emblemed_icon_new (icon, emblem); g_object_unref (icon); g_object_unref (emblem_icon); g_object_unref (emblem); icon = emblemed; } out: g_free (icon_str); g_free (type); return icon; } char * nemo_link_local_get_link_uri (const char *uri) { GKeyFile *key_file; char *retval; if (!is_local_file_a_link (uri)) { return NULL; } key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL); if (key_file == NULL) { return NULL; } retval = nemo_link_get_link_uri_from_desktop (key_file, uri); g_key_file_free (key_file); return retval; } static gboolean string_array_contains (char **array, const char *str) { char **p; if (!array) return FALSE; for (p = array; *p; p++) if (g_ascii_strcasecmp (*p, str) == 0) { return TRUE; } return FALSE; } static const gchar * get_session (void) { const gchar * session; session = g_getenv ("XDG_CURRENT_DESKTOP"); if (session == NULL || session[0] == 0) { /* historic behavior */ session = "GNOME"; } return session; } void nemo_link_get_link_info_given_file_contents (const char *file_contents, int link_file_size, const char *file_uri, char **uri, char **name, GIcon **icon, gboolean *is_launcher, gboolean *is_foreign) { GKeyFile *key_file; char *type; char **only_show_in; char **not_show_in; const gchar *session; session = get_session (); key_file = g_key_file_new (); if (!g_key_file_load_from_data (key_file, file_contents, link_file_size, G_KEY_FILE_NONE, NULL)) { g_key_file_free (key_file); return; } *uri = nemo_link_get_link_uri_from_desktop (key_file, file_uri); *name = nemo_link_get_link_name_from_desktop (key_file); *icon = nemo_link_get_link_icon_from_desktop (key_file); *is_launcher = FALSE; type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); if (g_strcmp0 (type, "Application") == 0 && g_key_file_has_key (key_file, MAIN_GROUP, "Exec", NULL)) { *is_launcher = TRUE; } g_free (type); *is_foreign = FALSE; only_show_in = g_key_file_get_string_list (key_file, MAIN_GROUP, "OnlyShowIn", NULL, NULL); if (session && only_show_in && !(string_array_contains (only_show_in, session) || string_array_contains (only_show_in, "GNOME"))) { *is_foreign = TRUE; } g_strfreev (only_show_in); not_show_in = g_key_file_get_string_list (key_file, MAIN_GROUP, "NotShowIn", NULL, NULL); if (session && not_show_in && string_array_contains (not_show_in, session)) { *is_foreign = TRUE; } g_strfreev (not_show_in); g_key_file_free (key_file); } nemo-4.4.2/libnemo-private/nemo-link.h000066400000000000000000000041541357442400300176240ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-link.h: . Copyright (C) 2001 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Jonathan Blandford */ #ifndef NEMO_LINK_H #define NEMO_LINK_H #include gboolean nemo_link_local_create (const char *directory_uri, const char *base_name, const char *display_name, const char *image, const char *target_uri, const GdkPoint *point, int monitor, gboolean unique_filename); gboolean nemo_link_local_set_text (const char *uri, const char *text); gboolean nemo_link_local_set_icon (const char *uri, const char *icon); char * nemo_link_local_get_text (const char *uri); char * nemo_link_local_get_link_uri (const char *uri); void nemo_link_get_link_info_given_file_contents (const char *file_contents, int link_file_size, const char *file_uri, char **uri, char **name, GIcon **icon, gboolean *is_launcher, gboolean *is_foreign); #endif /* NEMO_LINK_H */ nemo-4.4.2/libnemo-private/nemo-merged-directory.c000066400000000000000000000504051357442400300221270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-merged-directory.c: Subclass of NemoDirectory to implement the virtual merged directory. Copyright (C) 1999, 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-merged-directory.h" #include "nemo-directory-private.h" #include "nemo-directory-notify.h" #include "nemo-file.h" #include #include struct NemoMergedDirectoryDetails { GList *directories; GList *directories_not_done_loading; GHashTable *callbacks; GHashTable *monitors; }; typedef struct { NemoMergedDirectory *merged; NemoDirectoryCallback callback; gpointer callback_data; NemoFileAttributes wait_for_attributes; gboolean wait_for_file_list; GList *non_ready_directories; GList *merged_file_list; } MergedCallback; typedef struct { NemoMergedDirectory *merged; gboolean monitor_hidden_files; NemoFileAttributes monitor_attributes; } MergedMonitor; enum { ADD_REAL_DIRECTORY, REMOVE_REAL_DIRECTORY, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (NemoMergedDirectory, nemo_merged_directory, NEMO_TYPE_DIRECTORY); static guint merged_callback_hash (gconstpointer merged_callback_as_pointer) { const MergedCallback *merged_callback; merged_callback = merged_callback_as_pointer; return GPOINTER_TO_UINT (merged_callback->callback) ^ GPOINTER_TO_UINT (merged_callback->callback_data); } static gboolean merged_callback_equal (gconstpointer merged_callback_as_pointer, gconstpointer merged_callback_as_pointer_2) { const MergedCallback *merged_callback, *merged_callback_2; merged_callback = merged_callback_as_pointer; merged_callback_2 = merged_callback_as_pointer_2; return merged_callback->callback == merged_callback_2->callback && merged_callback->callback_data == merged_callback_2->callback_data; } static void merged_callback_destroy (MergedCallback *merged_callback) { g_assert (merged_callback != NULL); g_assert (NEMO_IS_MERGED_DIRECTORY (merged_callback->merged)); g_list_free (merged_callback->non_ready_directories); nemo_file_list_free (merged_callback->merged_file_list); g_free (merged_callback); } static void merged_callback_check_done (MergedCallback *merged_callback) { /* Check if we are ready. */ if (merged_callback->non_ready_directories != NULL) { return; } /* Remove from the hash table before sending it. */ g_hash_table_remove (merged_callback->merged->details->callbacks, merged_callback); /* We are ready, so do the real callback. */ (* merged_callback->callback) (NEMO_DIRECTORY (merged_callback->merged), merged_callback->merged_file_list, merged_callback->callback_data); /* And we are done. */ merged_callback_destroy (merged_callback); } static void merged_callback_remove_directory (MergedCallback *merged_callback, NemoDirectory *directory) { merged_callback->non_ready_directories = g_list_remove (merged_callback->non_ready_directories, directory); merged_callback_check_done (merged_callback); } static void directory_ready_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { MergedCallback *merged_callback; g_assert (NEMO_IS_DIRECTORY (directory)); g_assert (callback_data != NULL); merged_callback = callback_data; g_assert (g_list_find (merged_callback->non_ready_directories, directory) != NULL); /* Update based on this call. */ merged_callback->merged_file_list = g_list_concat (merged_callback->merged_file_list, nemo_file_list_copy (files)); /* Check if we are ready. */ merged_callback_remove_directory (merged_callback, directory); } static void merged_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback callback, gpointer callback_data) { NemoMergedDirectory *merged; MergedCallback search_key, *merged_callback; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); /* Check to be sure we aren't overwriting. */ search_key.callback = callback; search_key.callback_data = callback_data; if (g_hash_table_lookup (merged->details->callbacks, &search_key) != NULL) { g_warning ("tried to add a new callback while an old one was pending"); return; } /* Create a merged_callback record. */ merged_callback = g_new0 (MergedCallback, 1); merged_callback->merged = merged; merged_callback->callback = callback; merged_callback->callback_data = callback_data; merged_callback->wait_for_attributes = file_attributes; merged_callback->wait_for_file_list = wait_for_file_list; for (node = merged->details->directories; node != NULL; node = node->next) { merged_callback->non_ready_directories = g_list_prepend (merged_callback->non_ready_directories, node->data); } /* Put it in the hash table. */ g_hash_table_insert (merged->details->callbacks, merged_callback, merged_callback); /* Handle the pathological case where there are no directories. */ if (merged->details->directories == NULL) { merged_callback_check_done (merged_callback); } /* Now tell all the directories about it. */ for (node = merged->details->directories; node != NULL; node = node->next) { nemo_directory_call_when_ready (node->data, merged_callback->wait_for_attributes, merged_callback->wait_for_file_list, directory_ready_callback, merged_callback); } } static void merged_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data) { NemoMergedDirectory *merged; MergedCallback search_key, *merged_callback; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); /* Find the entry in the table. */ search_key.callback = callback; search_key.callback_data = callback_data; merged_callback = g_hash_table_lookup (merged->details->callbacks, &search_key); if (merged_callback == NULL) { return; } /* Remove from the hash table before working with it. */ g_hash_table_remove (merged_callback->merged->details->callbacks, merged_callback); /* Tell all the directories to cancel the call. */ for (node = merged_callback->non_ready_directories; node != NULL; node = node->next) { nemo_directory_cancel_callback (node->data, directory_ready_callback, merged_callback); } merged_callback_destroy (merged_callback); } static void build_merged_callback_list (NemoDirectory *directory, GList *file_list, gpointer callback_data) { GList **merged_list; merged_list = callback_data; *merged_list = g_list_concat (*merged_list, nemo_file_list_copy (file_list)); } /* Create a monitor on each of the directories in the list. */ static void merged_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { NemoMergedDirectory *merged; MergedMonitor *monitor; GList *node; GList *merged_callback_list; merged = NEMO_MERGED_DIRECTORY (directory); /* Map the client to a unique value so this doesn't interfere * with direct monitoring of the directory by the same client. */ monitor = g_hash_table_lookup (merged->details->monitors, client); if (monitor != NULL) { g_assert (monitor->merged == merged); } else { monitor = g_new0 (MergedMonitor, 1); monitor->merged = merged; g_hash_table_insert (merged->details->monitors, (gpointer) client, monitor); } monitor->monitor_hidden_files = monitor_hidden_files; monitor->monitor_attributes = file_attributes; /* Call through to the real directory add calls. */ merged_callback_list = NULL; for (node = merged->details->directories; node != NULL; node = node->next) { nemo_directory_file_monitor_add (node->data, monitor, monitor_hidden_files, file_attributes, build_merged_callback_list, &merged_callback_list); } if (callback != NULL) { (* callback) (directory, merged_callback_list, callback_data); } nemo_file_list_free (merged_callback_list); } static void merged_monitor_destroy (NemoMergedDirectory *merged, MergedMonitor *monitor) { GList *node; /* Call through to the real directory remove calls. */ for (node = merged->details->directories; node != NULL; node = node->next) { nemo_directory_file_monitor_remove (node->data, monitor); } g_free (monitor); } /* Remove the monitor from each of the directories in the list. */ static void merged_monitor_remove (NemoDirectory *directory, gconstpointer client) { NemoMergedDirectory *merged; MergedMonitor *monitor; merged = NEMO_MERGED_DIRECTORY (directory); /* Map the client to the value used by the earlier add call. */ monitor = g_hash_table_lookup (merged->details->monitors, client); if (monitor == NULL) { return; } g_hash_table_remove (merged->details->monitors, client); merged_monitor_destroy (merged, monitor); } static void merged_force_reload (NemoDirectory *directory) { NemoMergedDirectory *merged; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); /* Call through to the real force_reload calls. */ for (node = merged->details->directories; node != NULL; node = node->next) { nemo_directory_force_reload (node->data); } } /* Return true if any directory in the list does. */ static gboolean merged_contains_file (NemoDirectory *directory, NemoFile *file) { NemoMergedDirectory *merged; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); for (node = merged->details->directories; node != NULL; node = node->next) { if (nemo_directory_contains_file (node->data, file)) { return TRUE; } } return FALSE; } /* Return true only if all directories in the list do. */ static gboolean merged_are_all_files_seen (NemoDirectory *directory) { NemoMergedDirectory *merged; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); for (node = merged->details->directories; node != NULL; node = node->next) { if (!nemo_directory_are_all_files_seen (node->data)) { return FALSE; } } return TRUE; } /* Return true if any directory in the list does. */ static gboolean merged_is_not_empty (NemoDirectory *directory) { NemoMergedDirectory *merged; GList *node; merged = NEMO_MERGED_DIRECTORY (directory); for (node = merged->details->directories; node != NULL; node = node->next) { if (nemo_directory_is_not_empty (node->data)) { return TRUE; } } return FALSE; } static GList * merged_get_file_list (NemoDirectory *directory) { GList *dirs_file_list, *merged_dir_file_list = NULL; GList *dir_list; GList *cur_node; dirs_file_list = NULL; dir_list = NEMO_MERGED_DIRECTORY (directory)->details->directories; for (cur_node = dir_list; cur_node != NULL; cur_node = cur_node->next) { NemoDirectory *cur_dir; cur_dir = NEMO_DIRECTORY (cur_node->data); dirs_file_list = g_list_concat (dirs_file_list, nemo_directory_get_file_list (cur_dir)); } merged_dir_file_list = NEMO_DIRECTORY_CLASS (nemo_merged_directory_parent_class)->get_file_list (directory); return g_list_concat (dirs_file_list, merged_dir_file_list); } static void forward_files_added_cover (NemoDirectory *real_directory, GList *files, gpointer callback_data) { nemo_directory_emit_files_added (NEMO_DIRECTORY (callback_data), files); } static void forward_files_changed_cover (NemoDirectory *real_directory, GList *files, gpointer callback_data) { nemo_directory_emit_files_changed (NEMO_DIRECTORY (callback_data), files); } static void done_loading_callback (NemoDirectory *real_directory, NemoMergedDirectory *merged) { merged->details->directories_not_done_loading = g_list_remove (merged->details->directories_not_done_loading, real_directory); if (merged->details->directories_not_done_loading == NULL) { nemo_directory_emit_done_loading (NEMO_DIRECTORY (merged)); } } static void monitor_add_directory (gpointer key, gpointer value, gpointer callback_data) { MergedMonitor *monitor; monitor = value; nemo_directory_file_monitor_add (NEMO_DIRECTORY (callback_data), monitor, monitor->monitor_hidden_files, monitor->monitor_attributes, forward_files_added_cover, monitor->merged); } static void merged_add_real_directory (NemoMergedDirectory *merged, NemoDirectory *real_directory) { g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged)); g_return_if_fail (NEMO_IS_DIRECTORY (real_directory)); g_return_if_fail (!NEMO_IS_MERGED_DIRECTORY (real_directory)); g_return_if_fail (g_list_find (merged->details->directories, real_directory) == NULL); /* Add to our list of directories. */ nemo_directory_ref (real_directory); merged->details->directories = g_list_prepend (merged->details->directories, real_directory); merged->details->directories_not_done_loading = g_list_prepend (merged->details->directories_not_done_loading, real_directory); g_signal_connect_object (real_directory, "done_loading", G_CALLBACK (done_loading_callback), merged, 0); /* FIXME bugzilla.gnome.org 45084: The done_loading part won't work for the case where * we have no directories in our list. */ /* Add the directory to any extant monitors. */ g_hash_table_foreach (merged->details->monitors, monitor_add_directory, real_directory); /* FIXME bugzilla.gnome.org 42541: Do we need to add the directory to callbacks too? */ g_signal_connect_object (real_directory, "files_added", G_CALLBACK (forward_files_added_cover), merged, 0); g_signal_connect_object (real_directory, "files_changed", G_CALLBACK (forward_files_changed_cover), merged, 0); } void nemo_merged_directory_add_real_directory (NemoMergedDirectory *merged, NemoDirectory *real_directory) { g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged)); g_return_if_fail (NEMO_IS_DIRECTORY (real_directory)); g_return_if_fail (!NEMO_IS_MERGED_DIRECTORY (real_directory)); /* Quietly do nothing if asked to add something that's already there. */ if (g_list_find (merged->details->directories, real_directory) != NULL) { return; } g_signal_emit (merged, signals[ADD_REAL_DIRECTORY], 0, real_directory); } GList * nemo_merged_directory_get_real_directories (NemoMergedDirectory *merged) { return g_list_copy (merged->details->directories); } static void merged_callback_remove_directory_cover (gpointer key, gpointer value, gpointer callback_data) { merged_callback_remove_directory (value, NEMO_DIRECTORY (callback_data)); } static void monitor_remove_directory (gpointer key, gpointer value, gpointer callback_data) { nemo_directory_file_monitor_remove (NEMO_DIRECTORY (callback_data), value); } static void real_directory_notify_files_removed (NemoDirectory *real_directory) { GList *files, *l; files = nemo_directory_get_file_list (real_directory); for (l = files; l; l = l->next) { NemoFile *file; char *uri; file = NEMO_FILE (l->data); uri = nemo_file_get_uri (file); nemo_file_unref (file); l->data = uri; } if (files) { nemo_directory_notify_files_removed_by_uri (files); } g_list_free_full (files, g_free); } static void merged_remove_real_directory (NemoMergedDirectory *merged, NemoDirectory *real_directory) { g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged)); g_return_if_fail (NEMO_IS_DIRECTORY (real_directory)); g_return_if_fail (g_list_find (merged->details->directories, real_directory) != NULL); /* Since the real directory will be going away, act as if files were removed */ real_directory_notify_files_removed (real_directory); /* Remove this directory from callbacks and monitors. */ eel_g_hash_table_safe_for_each (merged->details->callbacks, merged_callback_remove_directory_cover, real_directory); g_hash_table_foreach (merged->details->monitors, monitor_remove_directory, real_directory); /* Disconnect all the signals. */ g_signal_handlers_disconnect_matched (real_directory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, merged); /* Remove from our list of directories. */ merged->details->directories = g_list_remove (merged->details->directories, real_directory); merged->details->directories_not_done_loading = g_list_remove (merged->details->directories_not_done_loading, real_directory); nemo_directory_unref (real_directory); } void nemo_merged_directory_remove_real_directory (NemoMergedDirectory *merged, NemoDirectory *real_directory) { g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged)); /* Quietly do nothing if asked to remove something that's not there. */ if (g_list_find (merged->details->directories, real_directory) == NULL) { return; } g_signal_emit (merged, signals[REMOVE_REAL_DIRECTORY], 0, real_directory); } static void merged_monitor_destroy_cover (gpointer key, gpointer value, gpointer callback_data) { merged_monitor_destroy (callback_data, value); } static void merged_callback_destroy_cover (gpointer key, gpointer value, gpointer callback_data) { merged_callback_destroy (value); } static void merged_finalize (GObject *object) { NemoMergedDirectory *merged; merged = NEMO_MERGED_DIRECTORY (object); g_hash_table_foreach (merged->details->monitors, merged_monitor_destroy_cover, merged); g_hash_table_foreach (merged->details->callbacks, merged_callback_destroy_cover, NULL); g_hash_table_destroy (merged->details->callbacks); g_hash_table_destroy (merged->details->monitors); nemo_directory_list_free (merged->details->directories); g_list_free (merged->details->directories_not_done_loading); G_OBJECT_CLASS (nemo_merged_directory_parent_class)->finalize (object); } static void nemo_merged_directory_init (NemoMergedDirectory *merged) { merged->details = G_TYPE_INSTANCE_GET_PRIVATE (merged, NEMO_TYPE_MERGED_DIRECTORY, NemoMergedDirectoryDetails); merged->details->callbacks = g_hash_table_new (merged_callback_hash, merged_callback_equal); merged->details->monitors = g_hash_table_new (NULL, NULL); } static void nemo_merged_directory_class_init (NemoMergedDirectoryClass *class) { NemoDirectoryClass *directory_class; directory_class = NEMO_DIRECTORY_CLASS (class); G_OBJECT_CLASS (class)->finalize = merged_finalize; directory_class->contains_file = merged_contains_file; directory_class->call_when_ready = merged_call_when_ready; directory_class->cancel_callback = merged_cancel_callback; directory_class->file_monitor_add = merged_monitor_add; directory_class->file_monitor_remove = merged_monitor_remove; directory_class->force_reload = merged_force_reload; directory_class->are_all_files_seen = merged_are_all_files_seen; directory_class->is_not_empty = merged_is_not_empty; /* Override get_file_list so that we can return a list that includes * the files from each of the directories in NemoMergedDirectory->details->directories. */ directory_class->get_file_list = merged_get_file_list; class->add_real_directory = merged_add_real_directory; class->remove_real_directory = merged_remove_real_directory; g_type_class_add_private (class, sizeof (NemoMergedDirectoryDetails)); signals[ADD_REAL_DIRECTORY] = g_signal_new ("add_real_directory", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoMergedDirectoryClass, add_real_directory), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[REMOVE_REAL_DIRECTORY] = g_signal_new ("remove_real_directory", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoMergedDirectoryClass, remove_real_directory), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } nemo-4.4.2/libnemo-private/nemo-merged-directory.h000066400000000000000000000053601357442400300221340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-merged-directory.h: Subclass of NemoDirectory to implement a virtual directory consisting of the merged contents of some real directories. Copyright (C) 1999, 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_MERGED_DIRECTORY_H #define NEMO_MERGED_DIRECTORY_H #include #define NEMO_TYPE_MERGED_DIRECTORY nemo_merged_directory_get_type() #define NEMO_MERGED_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_MERGED_DIRECTORY, NemoMergedDirectory)) #define NEMO_MERGED_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_MERGED_DIRECTORY, NemoMergedDirectoryClass)) #define NEMO_IS_MERGED_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_MERGED_DIRECTORY)) #define NEMO_IS_MERGED_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_MERGED_DIRECTORY)) #define NEMO_MERGED_DIRECTORY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_MERGED_DIRECTORY, NemoMergedDirectoryClass)) typedef struct NemoMergedDirectoryDetails NemoMergedDirectoryDetails; typedef struct { NemoDirectory parent_slot; NemoMergedDirectoryDetails *details; } NemoMergedDirectory; typedef struct { NemoDirectoryClass parent_slot; void (* add_real_directory) (NemoMergedDirectory *merged_directory, NemoDirectory *real_directory); void (* remove_real_directory) (NemoMergedDirectory *merged_directory, NemoDirectory *real_directory); } NemoMergedDirectoryClass; GType nemo_merged_directory_get_type (void); void nemo_merged_directory_add_real_directory (NemoMergedDirectory *merged_directory, NemoDirectory *real_directory); void nemo_merged_directory_remove_real_directory (NemoMergedDirectory *merged_directory, NemoDirectory *real_directory); GList * nemo_merged_directory_get_real_directories (NemoMergedDirectory *merged_directory); #endif /* NEMO_MERGED_DIRECTORY_H */ nemo-4.4.2/libnemo-private/nemo-metadata.c000066400000000000000000000061161357442400300204420ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-*/ /* nemo-metadata.c - metadata utils * * Copyright (C) 2009 Red Hatl, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include "nemo-metadata.h" #include static char *used_metadata_names[] = { (char *)NEMO_METADATA_KEY_DEFAULT_VIEW, (char *)NEMO_METADATA_KEY_LOCATION_BACKGROUND_COLOR, (char *)NEMO_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, (char *)NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, (char *)NEMO_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, (char *)NEMO_METADATA_KEY_ICON_VIEW_SORT_BY, (char *)NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED, (char *)NEMO_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED, (char *)NEMO_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP, (char *)NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL, (char *)NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN, (char *)NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED, (char *)NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, (char *)NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, (char *)NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, (char *)NEMO_METADATA_KEY_WINDOW_GEOMETRY, (char *)NEMO_METADATA_KEY_WINDOW_SCROLL_POSITION, (char *)NEMO_METADATA_KEY_WINDOW_SHOW_HIDDEN_FILES, (char *)NEMO_METADATA_KEY_WINDOW_MAXIMIZED, (char *)NEMO_METADATA_KEY_WINDOW_STICKY, (char *)NEMO_METADATA_KEY_WINDOW_KEEP_ABOVE, (char *)NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR, (char *)NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE, (char *)NEMO_METADATA_KEY_SIDEBAR_BUTTONS, (char *)NEMO_METADATA_KEY_ANNOTATION, (char *)NEMO_METADATA_KEY_ICON_POSITION, (char *)NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP, (char *)NEMO_METADATA_KEY_ICON_SCALE, (char *)NEMO_METADATA_KEY_CUSTOM_ICON, (char *)NEMO_METADATA_KEY_CUSTOM_ICON_NAME, (char *)NEMO_METADATA_KEY_EMBLEMS, (char *)NEMO_METADATA_KEY_MONITOR, (char *)NEMO_METADATA_KEY_DESKTOP_GRID_HORIZONTAL, (char *)NEMO_METADATA_KEY_SHOW_THUMBNAILS, (char *)NEMO_METADATA_KEY_DESKTOP_GRID_ADJUST, (char *)NEMO_METADATA_KEY_PINNED, NULL }; guint nemo_metadata_get_id (const char *metadata) { static GHashTable *hash; int i; if (hash == NULL) { hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; used_metadata_names[i] != NULL; i++) g_hash_table_insert (hash, used_metadata_names[i], GINT_TO_POINTER (i + 1)); } return GPOINTER_TO_INT (g_hash_table_lookup (hash, metadata)); } nemo-4.4.2/libnemo-private/nemo-metadata.h000066400000000000000000000077271357442400300204600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-metadata.h: #defines and other metadata-related info Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: John Sullivan */ #ifndef NEMO_METADATA_H #define NEMO_METADATA_H /* Keys for getting/setting Nemo metadata. All metadata used in Nemo * should define its key here, so we can keep track of the whole set easily. * Any updates here needs to be added in nemo-metadata.c too. */ #include /* Per-file */ #define NEMO_METADATA_KEY_DEFAULT_VIEW "nemo-default-view" #define NEMO_METADATA_KEY_LOCATION_BACKGROUND_COLOR "folder-background-color" #define NEMO_METADATA_KEY_LOCATION_BACKGROUND_IMAGE "folder-background-image" #define NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL "nemo-icon-view-zoom-level" #define NEMO_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT "nemo-icon-view-auto-layout" #define NEMO_METADATA_KEY_ICON_VIEW_SORT_BY "nemo-icon-view-sort-by" #define NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED "nemo-icon-view-sort-reversed" #define NEMO_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED "nemo-icon-view-keep-aligned" #define NEMO_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP "nemo-icon-view-layout-timestamp" #define NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL "nemo-list-view-zoom-level" #define NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN "nemo-list-view-sort-column" #define NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED "nemo-list-view-sort-reversed" #define NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS "nemo-list-view-visible-columns" #define NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER "nemo-list-view-column-order" #define NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL "nemo-compact-view-zoom-level" #define NEMO_METADATA_KEY_WINDOW_GEOMETRY "nemo-window-geometry" #define NEMO_METADATA_KEY_WINDOW_SCROLL_POSITION "nemo-window-scroll-position" #define NEMO_METADATA_KEY_WINDOW_SHOW_HIDDEN_FILES "nemo-window-show-hidden-files" #define NEMO_METADATA_KEY_WINDOW_MAXIMIZED "nemo-window-maximized" #define NEMO_METADATA_KEY_WINDOW_STICKY "nemo-window-sticky" #define NEMO_METADATA_KEY_WINDOW_KEEP_ABOVE "nemo-window-keep-above" #define NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR "nemo-sidebar-background-color" #define NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE "nemo-sidebar-background-image" #define NEMO_METADATA_KEY_SIDEBAR_BUTTONS "nemo-sidebar-buttons" #define NEMO_METADATA_KEY_ANNOTATION "annotation" #define NEMO_METADATA_KEY_ICON_POSITION "nemo-icon-position" #define NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP "nemo-icon-position-timestamp" #define NEMO_METADATA_KEY_ICON_SCALE "icon-scale" #define NEMO_METADATA_KEY_CUSTOM_ICON "custom-icon" #define NEMO_METADATA_KEY_CUSTOM_ICON_NAME "custom-icon-name" #define NEMO_METADATA_KEY_EMBLEMS "emblems" #define NEMO_METADATA_KEY_MONITOR "monitor" #define NEMO_METADATA_KEY_DESKTOP_GRID_HORIZONTAL "desktop-horizontal" #define NEMO_METADATA_KEY_SHOW_THUMBNAILS "show-thumbnails" #define NEMO_METADATA_KEY_DESKTOP_GRID_ADJUST "desktop-grid-adjust" #define NEMO_METADATA_KEY_PINNED "pinned-to-top" guint nemo_metadata_get_id (const char *metadata); #endif /* NEMO_METADATA_H */ nemo-4.4.2/libnemo-private/nemo-mime-application-chooser.c000066400000000000000000000620661357442400300235600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-mime-application-chooser.c: an mime-application chooser * * Copyright (C) 2004 Novell, Inc. * Copyright (C) 2007, 2010 Red Hat, Inc. * * The Gnome 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. * * The Gnome Library is distributed in the hope that it will be useful, * but APPLICATIONOUT ANY WARRANTY; applicationout 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 application the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Dave Camp * Alexander Larsson * Cosimo Cecchi */ #include #include "nemo-mime-application-chooser.h" #include "nemo-file.h" #include "nemo-signaller.h" #include #include #include #include #include #include #include struct _NemoMimeApplicationChooserDetails { GList *files; char *uri; char *content_type; GtkWidget *label; GtkWidget *entry; GtkWidget *set_as_default_button; GtkWidget *open_with_widget; GtkWidget *add_button; GAppInfo *custom_info; GtkWidget *custom_entry; GtkWidget *dialog_ok; }; enum { PROP_CONTENT_TYPE = 1, PROP_URI, PROP_FILES, PROP_DIALOG_OK, NUM_PROPERTIES }; #define DEFAULT_APPS "Default Applications" #define ADDED_ASS "Added Associations" static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoMimeApplicationChooser, nemo_mime_application_chooser, GTK_TYPE_BOX); static void add_clicked_cb (GtkButton *button, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; GAppInfo *info; if (!chooser->details->custom_info) { info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget)); g_app_info_set_as_last_used_for_type (info, chooser->details->content_type, NULL); } else { info = chooser->details->custom_info; g_app_info_set_as_last_used_for_type (info, chooser->details->content_type, NULL); } if (info == NULL) return; gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget)); gtk_entry_set_text (GTK_ENTRY (chooser->details->custom_entry), ""); g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); } static void remove_clicked_cb (GtkMenuItem *item, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; GError *error; GAppInfo *info; info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget)); if (info) { error = NULL; if (!g_app_info_remove_supports_type (info, chooser->details->content_type, &error)) { eel_show_error_dialog (_("Could not forget association"), error->message, GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (chooser)))); g_error_free (error); } gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget)); g_object_unref (info); } g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); } static void populate_popup_cb (GtkAppChooserWidget *widget, GtkMenu *menu, GAppInfo *app, gpointer user_data) { GtkWidget *item; NemoMimeApplicationChooser *chooser = user_data; if (g_app_info_can_remove_supports_type (app)) { item = gtk_menu_item_new_with_label (_("Forget association")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); g_signal_connect (item, "activate", G_CALLBACK (remove_clicked_cb), chooser); } } static void reset_clicked_cb (GtkButton *button, gpointer user_data) { NemoMimeApplicationChooser *chooser; chooser = NEMO_MIME_APPLICATION_CHOOSER (user_data); g_app_info_reset_type_associations (chooser->details->content_type); gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget)); gtk_entry_set_text (GTK_ENTRY (chooser->details->custom_entry), ""); g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); } static void set_as_default_clicked_cb (GtkButton *button, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; GAppInfo *info; if (!chooser->details->custom_info) { info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget)); g_app_info_set_as_default_for_type (info, chooser->details->content_type, NULL); } else { info = chooser->details->custom_info; g_app_info_set_as_default_for_type (info, chooser->details->content_type, NULL); } gtk_app_chooser_refresh (GTK_APP_CHOOSER (chooser->details->open_with_widget)); gtk_entry_set_text (GTK_ENTRY (chooser->details->custom_entry), ""); g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); } static gint app_compare (gconstpointer a, gconstpointer b) { return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b)); } static gboolean app_info_can_add (GAppInfo *info, const gchar *content_type) { GList *recommended, *fallback; gboolean retval = FALSE; recommended = g_app_info_get_recommended_for_type (content_type); fallback = g_app_info_get_fallback_for_type (content_type); if (g_list_find_custom (recommended, info, app_compare)) { goto out; } if (g_list_find_custom (fallback, info, app_compare)) { goto out; } retval = TRUE; out: g_list_free_full (recommended, g_object_unref); g_list_free_full (fallback, g_object_unref); return retval; } static void application_selected_cb (GtkAppChooserWidget *widget, GAppInfo *info, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; GAppInfo *default_app; gtk_entry_set_text (GTK_ENTRY (chooser->details->custom_entry), ""); default_app = g_app_info_get_default_for_type (chooser->details->content_type, FALSE); gtk_widget_set_sensitive (chooser->details->set_as_default_button, (!default_app || !g_app_info_equal (info, default_app))); gtk_widget_set_sensitive (chooser->details->add_button, app_info_can_add (info, chooser->details->content_type)); if (chooser->details->dialog_ok) gtk_widget_set_sensitive (chooser->details->dialog_ok, TRUE); g_clear_object (&default_app); } static void application_activated_cb (GtkAppChooserWidget *widget, GAppInfo *info, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; if (chooser->details->dialog_ok) { gtk_window_activate_default (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); } } static gboolean validate_entry (GtkEntry *entry, const gchar *str) { gint argcp = 0; gchar **argvp = NULL; gboolean ret = FALSE; if (g_shell_parse_argv (str, &argcp, &argvp, NULL)) { if (argcp > 0) { gchar *path_exec = g_find_program_in_path (argvp[0]); if (path_exec) { ret = TRUE; } else { if (!g_file_test (str, G_FILE_TEST_IS_DIR) && g_file_test (str, G_FILE_TEST_IS_EXECUTABLE)) { ret = TRUE; } } g_free (path_exec); } g_strfreev (argvp); } if (ret) { gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "ok"); gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("Valid executable.")); } else { gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "stop"); gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("Not a valid executable. Spaces in the file path must be escaped with backslash (\\).")); } return ret; } static gchar * get_nice_name (const gchar *entry) { gchar *exec_path; gchar *ret = NULL; gint argcp = 0; gchar **argvp = NULL; if (g_shell_parse_argv (entry, &argcp, &argvp, NULL)) { if (argcp > 0) { exec_path = argvp[0]; GFile *file = g_file_new_for_path (exec_path); ret = g_file_get_basename (file); g_object_unref (file); } g_strfreev (argvp); } return ret; } static void custom_entry_changed_cb (GtkEditable *entry, gpointer user_data) { NemoMimeApplicationChooser *chooser = user_data; const gchar *entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); gboolean empty = g_strcmp0 (entry_text, "") == 0; if (!empty && validate_entry (GTK_ENTRY (entry), entry_text)) { GAppInfo *default_app; gchar *cl = g_strdup_printf ("%s", entry_text); GAppInfo *info = g_app_info_create_from_commandline (cl, get_nice_name (cl), G_APP_INFO_CREATE_NONE, NULL); default_app = g_app_info_get_default_for_type (chooser->details->content_type, FALSE); gtk_widget_set_sensitive (chooser->details->set_as_default_button, !g_app_info_equal (info, default_app)); gtk_widget_set_sensitive (chooser->details->add_button, app_info_can_add (info, chooser->details->content_type)); g_object_unref (default_app); if (chooser->details->custom_info != NULL) { g_object_unref (chooser->details->custom_info); chooser->details->custom_info = NULL; } chooser->details->custom_info = info; if (chooser->details->dialog_ok) gtk_widget_set_sensitive (chooser->details->dialog_ok, TRUE); } else { if (chooser->details->custom_info != NULL) { g_object_unref (chooser->details->custom_info); chooser->details->custom_info = NULL; } if (empty) { gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL); gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL); } gtk_widget_set_sensitive (chooser->details->set_as_default_button, FALSE); gtk_widget_set_sensitive (chooser->details->add_button, FALSE); if (chooser->details->dialog_ok) gtk_widget_set_sensitive (chooser->details->dialog_ok, FALSE); } } static void custom_app_set (NemoMimeApplicationChooser *chooser, GtkFileChooser *dialog) { gchar *unescaped = gtk_file_chooser_get_filename (dialog); gchar *escaped = eel_str_escape_spaces (unescaped); gtk_entry_set_text (GTK_ENTRY (chooser->details->custom_entry), escaped); gtk_widget_grab_focus (chooser->details->custom_entry); gtk_editable_set_position (GTK_EDITABLE (chooser->details->custom_entry), -1); g_free (unescaped); g_free (escaped); } static char * get_extension (const char *basename) { char *p; p = strrchr (basename, '.'); if (p && *(p + 1) != '\0') { return g_strdup (p + 1); } else { return NULL; } } static gchar * get_extension_from_file (NemoFile *nfile) { char *name; char *extension; name = nemo_file_get_name (nfile); extension = get_extension (name); g_free (name); return extension; } static void nemo_mime_application_chooser_apply_labels (NemoMimeApplicationChooser *chooser) { gchar *label, *extension = NULL, *description = NULL; if (chooser->details->files != NULL) { /* here we assume all files are of the same content type */ if (g_content_type_is_unknown (chooser->details->content_type)) { extension = get_extension_from_file (NEMO_FILE (chooser->details->files->data)); /* the %s here is a file extension */ description = g_strdup_printf (_("%s document"), extension); } else { description = g_content_type_get_description (chooser->details->content_type); } label = g_strdup_printf (_("Open all files of type \"%s\" with"), description); } else { GFile *file; gchar *basename, *emname; file = g_file_new_for_uri (chooser->details->uri); basename = g_file_get_basename (file); if (g_content_type_is_unknown (chooser->details->content_type)) { extension = get_extension (basename); /* the %s here is a file extension */ description = g_strdup_printf (_("%s document"), extension); } else { description = g_content_type_get_description (chooser->details->content_type); } /* first %s is filename, second %s is mime-type description */ emname = g_markup_printf_escaped("%s", basename); label = g_strdup_printf (_("Select an application in the list to open %s and other files of type \"%s\""), emname, description); g_free (emname); g_free (basename); g_object_unref (file); } gtk_label_set_markup (GTK_LABEL (chooser->details->label), label); g_free (label); g_free (extension); g_free (description); } static gboolean exec_filter_func (const GtkFileFilterInfo *info, gpointer data) { if (info->contains & GTK_FILE_FILTER_FILENAME) { if (g_file_test (info->filename, G_FILE_TEST_IS_EXECUTABLE)) return TRUE; } return FALSE; } static void on_file_chooser_button_clicked (GtkButton *button, NemoMimeApplicationChooser *chooser) { GtkWidget *dialog; GtkFileFilter *filter; gint res; dialog = gtk_file_chooser_dialog_new (_("Custom application"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ()); filter = gtk_file_filter_new (); gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, (GtkFileFilterFunc) exec_filter_func, NULL, NULL); gtk_file_filter_set_name (filter, _("Executables")); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); res = gtk_dialog_run (GTK_DIALOG (dialog)); if (res == GTK_RESPONSE_ACCEPT) { custom_app_set (chooser, GTK_FILE_CHOOSER (dialog)); } gtk_widget_destroy (dialog); } static void nemo_mime_application_chooser_build_ui (NemoMimeApplicationChooser *chooser) { GtkWidget *box, *button; GAppInfo *info; gtk_container_set_border_width (GTK_CONTAINER (chooser), 8); gtk_box_set_spacing (GTK_BOX (chooser), 0); gtk_box_set_homogeneous (GTK_BOX (chooser), FALSE); chooser->details->label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (chooser->details->label), 0.0, 0.5); gtk_label_set_line_wrap (GTK_LABEL (chooser->details->label), TRUE); gtk_label_set_line_wrap_mode (GTK_LABEL (chooser->details->label), PANGO_WRAP_WORD_CHAR); gtk_box_pack_start (GTK_BOX (chooser), chooser->details->label, FALSE, FALSE, 0); gtk_widget_show (chooser->details->label); chooser->details->open_with_widget = gtk_app_chooser_widget_new (chooser->details->content_type); gtk_app_chooser_widget_set_show_default (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget), TRUE); gtk_app_chooser_widget_set_show_fallback (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget), TRUE); gtk_box_pack_start (GTK_BOX (chooser), chooser->details->open_with_widget, TRUE, TRUE, 6); gtk_widget_show (chooser->details->open_with_widget); gtk_app_chooser_widget_set_show_other (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget), TRUE); gtk_app_chooser_widget_set_show_recommended (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget), TRUE); GtkWidget *custom_label = gtk_label_new (_("You can also type or select a custom executable file to use to open this file type. " "You can use this command just once, or set it as default for all files of this type.")); gtk_misc_set_alignment (GTK_MISC (custom_label), 0.0, 0.5); gtk_label_set_line_wrap (GTK_LABEL (custom_label), TRUE); gtk_label_set_line_wrap_mode (GTK_LABEL (custom_label), PANGO_WRAP_WORD_CHAR); gtk_box_pack_start (GTK_BOX (chooser), custom_label, FALSE, FALSE, 0); gtk_widget_show (GTK_WIDGET (custom_label)); GtkWidget *custom_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (chooser), custom_box, FALSE, FALSE, 6); GtkWidget *entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (custom_box), entry, TRUE, TRUE, 0); gtk_entry_set_placeholder_text (GTK_ENTRY (entry), _("Enter a custom command...")); gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); g_signal_connect (entry, "changed", G_CALLBACK (custom_entry_changed_cb), chooser); chooser->details->custom_entry = entry; button = gtk_button_new_from_icon_name ("document-open-symbolic", GTK_ICON_SIZE_BUTTON); g_signal_connect (button, "clicked", G_CALLBACK (on_file_chooser_button_clicked), chooser); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (custom_box), button, FALSE, FALSE, 6); gtk_widget_show_all (custom_box); box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); gtk_box_set_spacing (GTK_BOX (box), 6); gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_CENTER); gtk_box_pack_start (GTK_BOX (chooser), box, FALSE, FALSE, 6); gtk_widget_show (box); button = gtk_button_new_with_label (_("Add to list")); g_signal_connect (button, "clicked", G_CALLBACK (add_clicked_cb), chooser); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); chooser->details->add_button = button; button = gtk_button_new_with_label (_("Set as default")); g_signal_connect (button, "clicked", G_CALLBACK (set_as_default_clicked_cb), chooser); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); chooser->details->set_as_default_button = button; button = gtk_button_new_with_label (_("Reset to system defaults")); g_signal_connect (button, "clicked", G_CALLBACK (reset_clicked_cb), chooser); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); /* initialize sensitivity */ info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget)); if (info != NULL) { application_selected_cb (GTK_APP_CHOOSER_WIDGET (chooser->details->open_with_widget), info, chooser); g_object_unref (info); } g_signal_connect (chooser->details->open_with_widget, "application-selected", G_CALLBACK (application_selected_cb), chooser); g_signal_connect (chooser->details->open_with_widget, "populate-popup", G_CALLBACK (populate_popup_cb), chooser); g_signal_connect (chooser->details->open_with_widget, "application-activated", G_CALLBACK (application_activated_cb), chooser); gtk_widget_grab_focus (chooser->details->custom_entry); } static void nemo_mime_application_chooser_init (NemoMimeApplicationChooser *chooser) { chooser->details = G_TYPE_INSTANCE_GET_PRIVATE (chooser, NEMO_TYPE_MIME_APPLICATION_CHOOSER, NemoMimeApplicationChooserDetails); gtk_orientable_set_orientation (GTK_ORIENTABLE (chooser), GTK_ORIENTATION_VERTICAL); chooser->details->custom_info = NULL; } static void nemo_mime_application_chooser_constructed (GObject *object) { NemoMimeApplicationChooser *chooser = NEMO_MIME_APPLICATION_CHOOSER (object); if (G_OBJECT_CLASS (nemo_mime_application_chooser_parent_class)->constructed != NULL) G_OBJECT_CLASS (nemo_mime_application_chooser_parent_class)->constructed (object); gtk_widget_set_halign (GTK_WIDGET (object), GTK_ALIGN_CENTER); nemo_mime_application_chooser_build_ui (chooser); nemo_mime_application_chooser_apply_labels (chooser); } static void nemo_mime_application_chooser_finalize (GObject *object) { NemoMimeApplicationChooser *chooser; chooser = NEMO_MIME_APPLICATION_CHOOSER (object); g_free (chooser->details->uri); g_free (chooser->details->content_type); if (chooser->details->custom_info != NULL) g_object_unref (chooser->details->custom_info); G_OBJECT_CLASS (nemo_mime_application_chooser_parent_class)->finalize (object); } static void nemo_mime_application_chooser_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoMimeApplicationChooser *chooser = NEMO_MIME_APPLICATION_CHOOSER (object); switch (property_id) { case PROP_CONTENT_TYPE: g_value_set_string (value, chooser->details->content_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_mime_application_chooser_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoMimeApplicationChooser *chooser = NEMO_MIME_APPLICATION_CHOOSER (object); switch (property_id) { case PROP_CONTENT_TYPE: chooser->details->content_type = g_value_dup_string (value); break; case PROP_FILES: chooser->details->files = g_value_get_pointer (value); break; case PROP_URI: chooser->details->uri = g_value_dup_string (value); break; case PROP_DIALOG_OK: chooser->details->dialog_ok = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_mime_application_chooser_class_init (NemoMimeApplicationChooserClass *class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (class); gobject_class->set_property = nemo_mime_application_chooser_set_property; gobject_class->get_property = nemo_mime_application_chooser_get_property; gobject_class->finalize = nemo_mime_application_chooser_finalize; gobject_class->constructed = nemo_mime_application_chooser_constructed; properties[PROP_CONTENT_TYPE] = g_param_spec_string ("content-type", "Content type", "Content type for this widget", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_URI] = g_param_spec_string ("uri", "URI", "URI for this widget", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_FILES] = g_param_spec_pointer ("files", "Files", "Files for this widget", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_DIALOG_OK] = g_param_spec_object ("ok-button", "Dialog OK button", "Dialog OK button", GTK_TYPE_WIDGET, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); g_type_class_add_private (class, sizeof (NemoMimeApplicationChooserDetails)); } GtkWidget * nemo_mime_application_chooser_new (const char *uri, GList *files, const char *mime_type, GtkWidget *ok_button) { GtkWidget *chooser; chooser = g_object_new (NEMO_TYPE_MIME_APPLICATION_CHOOSER, "uri", uri, "files", files, "content-type", mime_type, "ok-button", ok_button, NULL); return chooser; } GAppInfo * nemo_mime_application_chooser_get_info (NemoMimeApplicationChooser *chooser) { if (chooser->details->custom_info == NULL) return gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (chooser->details->open_with_widget)); else return chooser->details->custom_info; } const gchar * nemo_mime_application_chooser_get_uri (NemoMimeApplicationChooser *chooser) { return chooser->details->uri; } nemo-4.4.2/libnemo-private/nemo-mime-application-chooser.h000066400000000000000000000051251357442400300235560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-mime-application-chooser.c: Manages applications for mime types Copyright (C) 2004 Novell, Inc. The Gnome 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. The Gnome Library is distributed in the hope that it will be useful, but APPLICATIONOUT ANY WARRANTY; applicationout 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 application the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Dave Camp */ #ifndef NEMO_MIME_APPLICATION_CHOOSER_H #define NEMO_MIME_APPLICATION_CHOOSER_H #include #define NEMO_TYPE_MIME_APPLICATION_CHOOSER (nemo_mime_application_chooser_get_type ()) #define NEMO_MIME_APPLICATION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_MIME_APPLICATION_CHOOSER, NemoMimeApplicationChooser)) #define NEMO_MIME_APPLICATION_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_MIME_APPLICATION_CHOOSER, NemoMimeApplicationChooserClass)) #define NEMO_IS_MIME_APPLICATION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_MIME_APPLICATION_CHOOSER) typedef struct _NemoMimeApplicationChooser NemoMimeApplicationChooser; typedef struct _NemoMimeApplicationChooserClass NemoMimeApplicationChooserClass; typedef struct _NemoMimeApplicationChooserDetails NemoMimeApplicationChooserDetails; struct _NemoMimeApplicationChooser { GtkBox parent; NemoMimeApplicationChooserDetails *details; }; struct _NemoMimeApplicationChooserClass { GtkBoxClass parent_class; }; GType nemo_mime_application_chooser_get_type (void); GtkWidget * nemo_mime_application_chooser_new (const char *uri, GList *files, const char *mime_type, GtkWidget *ok_button); GAppInfo *nemo_mime_application_chooser_get_info (NemoMimeApplicationChooser *chooser); const gchar *nemo_mime_application_chooser_get_uri (NemoMimeApplicationChooser *chooser); #endif /* NEMO_MIME_APPLICATION_CHOOSER_H */ nemo-4.4.2/libnemo-private/nemo-module.c000066400000000000000000000130431357442400300201440ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-module.h - Interface to nemo extensions * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #include #include "nemo-module.h" #include #include static GList *module_objects = NULL; G_DEFINE_TYPE (NemoModule, nemo_module, G_TYPE_TYPE_MODULE); static gboolean nemo_module_load (GTypeModule *gmodule) { NemoModule *module; module = NEMO_MODULE (gmodule); module->library = g_module_open (module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); if (!module->library) { g_warning ("%s", g_module_error ()); return FALSE; } if (!g_module_symbol (module->library, "nemo_module_initialize", (gpointer *)&module->initialize) || !g_module_symbol (module->library, "nemo_module_shutdown", (gpointer *)&module->shutdown) || !g_module_symbol (module->library, "nemo_module_list_types", (gpointer *)&module->list_types)) { g_warning ("%s", g_module_error ()); g_module_close (module->library); return FALSE; } module->initialize (gmodule); return TRUE; } static void nemo_module_unload (GTypeModule *gmodule) { NemoModule *module; module = NEMO_MODULE (gmodule); module->shutdown (); g_module_close (module->library); module->initialize = NULL; module->shutdown = NULL; module->list_types = NULL; } static void nemo_module_finalize (GObject *object) { NemoModule *module; module = NEMO_MODULE (object); g_free (module->path); G_OBJECT_CLASS (nemo_module_parent_class)->finalize (object); } static void nemo_module_init (NemoModule *module) { } static void nemo_module_class_init (NemoModuleClass *class) { G_OBJECT_CLASS (class)->finalize = nemo_module_finalize; G_TYPE_MODULE_CLASS (class)->load = nemo_module_load; G_TYPE_MODULE_CLASS (class)->unload = nemo_module_unload; } static void module_object_weak_notify (gpointer user_data, GObject *object) { module_objects = g_list_remove (module_objects, object); } static gboolean module_is_selected (GType type) { gchar **disabled_list = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS); gboolean ret = TRUE; guint i = 0; for (i = 0; i < g_strv_length (disabled_list); i++) { if (g_strcmp0 (disabled_list[i], g_type_name (type)) == 0) ret = FALSE; } g_strfreev (disabled_list); return ret; } static void add_module_objects (NemoModule *module) { const GType *types; int num_types; int i; module->list_types (&types, &num_types); for (i = 0; i < num_types; i++) { if (types[i] == 0) { /* Work around broken extensions */ break; } if (module_is_selected (types[i])) { nemo_module_add_type (types[i]); } } } static void nemo_module_load_file (const char *filename) { NemoModule *module = NULL; module = g_object_new (NEMO_TYPE_MODULE, NULL); module->path = g_strdup (filename); if (g_type_module_use (G_TYPE_MODULE (module))) { add_module_objects (module); g_type_module_unuse (G_TYPE_MODULE (module)); } else { g_object_unref (module); } } static void load_module_dir (const char *dirname) { GDir *dir; dir = g_dir_open (dirname, 0, NULL); if (dir) { const char *name; while ((name = g_dir_read_name (dir))) { if (g_str_has_suffix (name, "." G_MODULE_SUFFIX)) { char *filename; filename = g_build_filename (dirname, name, NULL); nemo_module_load_file (filename); g_free (filename); } } g_dir_close (dir); } } static void free_module_objects (void) { GList *l, *next; for (l = module_objects; l != NULL; l = next) { next = l->next; g_object_unref (l->data); } g_list_free (module_objects); } void nemo_module_setup (void) { static gboolean initialized = FALSE; if (!initialized) { initialized = TRUE; load_module_dir (NEMO_EXTENSIONDIR); eel_debug_call_at_shutdown (free_module_objects); } } GList * nemo_module_get_extensions_for_type (GType type) { GList *l; GList *ret = NULL; for (l = module_objects; l != NULL; l = l->next) { if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data), type)) { g_object_ref (l->data); ret = g_list_prepend (ret, l->data); } } return ret; } void nemo_module_extension_list_free (GList *extensions) { GList *l, *next; for (l = extensions; l != NULL; l = next) { next = l->next; g_object_unref (l->data); } g_list_free (extensions); } void nemo_module_add_type (GType type) { GObject *object; object = g_object_new (type, NULL); g_object_weak_ref (object, (GWeakNotify)module_object_weak_notify, NULL); module_objects = g_list_prepend (module_objects, object); } nemo-4.4.2/libnemo-private/nemo-module.h000066400000000000000000000045111357442400300201510ustar00rootroot00000000000000/* * nemo-module.h - Interface to nemo extensions * * Copyright (C) 2003 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author: Dave Camp * */ #ifndef NEMO_MODULE_H #define NEMO_MODULE_H #include #include G_BEGIN_DECLS #define NEMO_TYPE_MODULE (nemo_module_get_type ()) #define NEMO_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_MODULE, NemoModule)) #define NEMO_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_MODULE, NemoModule)) #define NEMO_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_MODULE)) #define NEMO_IS_MODULE_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_MODULE)) typedef struct _NemoModule NemoModule; typedef struct _NemoModuleClass NemoModuleClass; struct _NemoModule { GTypeModule parent; GModule *library; char *path; void (*initialize) (GTypeModule *module); void (*shutdown) (void); void (*list_types) (const GType **types, int *num_types); void (*get_modules_name_and_desc) (gchar ***strings); }; struct _NemoModuleClass { GTypeModuleClass parent; }; GType nemo_module_get_type (void); void nemo_module_setup (void); void nemo_module_refresh (void); GList *nemo_module_get_extensions_for_type (GType type); void nemo_module_extension_list_free (GList *list); /* Add a type to the module interface - allows nemo to add its own modules * without putting them in separate shared libraries */ void nemo_module_add_type (GType type); G_END_DECLS #endif nemo-4.4.2/libnemo-private/nemo-monitor.c000066400000000000000000000117731357442400300203560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-monitor.c: file and directory change monitoring for nemo Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Seth Nickell Darin Adler Alex Graveley */ #include #include "nemo-monitor.h" #include "nemo-file-changes-queue.h" #include "nemo-file-utilities.h" #include struct NemoMonitor { GFileMonitor *monitor; GVolumeMonitor *volume_monitor; GFile *location; }; gboolean nemo_monitor_active (void) { static gboolean tried_monitor = FALSE; static gboolean monitor_success; GFileMonitor *dir_monitor; GFile *file; if (tried_monitor == FALSE) { file = g_file_new_for_path (g_get_home_dir ()); dir_monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); monitor_success = (dir_monitor != NULL); if (dir_monitor) { g_object_unref (dir_monitor); } tried_monitor = TRUE; } return monitor_success; } static gboolean call_consume_changes_idle_id = 0; static gboolean call_consume_changes_idle_cb (gpointer not_used) { nemo_file_changes_consume_changes (TRUE); call_consume_changes_idle_id = 0; return FALSE; } static void schedule_call_consume_changes (void) { if (call_consume_changes_idle_id == 0) { call_consume_changes_idle_id = g_idle_add (call_consume_changes_idle_cb, NULL); } } static void mount_removed (GVolumeMonitor *volume_monitor, GMount *mount, gpointer user_data) { NemoMonitor *monitor = user_data; GFile *mount_location; mount_location = g_mount_get_root (mount); if (g_file_has_prefix (monitor->location, mount_location)) { nemo_file_changes_queue_file_removed (monitor->location); schedule_call_consume_changes (); } g_object_unref (mount_location); } static void dir_changed (GFileMonitor* monitor, GFile *child, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { char *uri, *to_uri; uri = g_file_get_uri (child); to_uri = NULL; if (other_file) { to_uri = g_file_get_uri (other_file); } switch (event_type) { case G_FILE_MONITOR_EVENT_MOVED: case G_FILE_MONITOR_EVENT_RENAMED: case G_FILE_MONITOR_EVENT_MOVED_IN: case G_FILE_MONITOR_EVENT_MOVED_OUT: default: case G_FILE_MONITOR_EVENT_CHANGED: /* ignore */ break; case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: nemo_file_changes_queue_file_changed (child); break; case G_FILE_MONITOR_EVENT_DELETED: nemo_file_changes_queue_file_removed (child); break; case G_FILE_MONITOR_EVENT_CREATED: nemo_file_changes_queue_file_added (child); break; case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: /* TODO: Do something */ break; case G_FILE_MONITOR_EVENT_UNMOUNTED: /* TODO: Do something */ break; } g_free (uri); g_free (to_uri); schedule_call_consume_changes (); } NemoMonitor * nemo_monitor_directory (GFile *location) { GFileMonitor *dir_monitor; NemoMonitor *ret; ret = g_new0 (NemoMonitor, 1); dir_monitor = g_file_monitor_directory (location, G_FILE_MONITOR_WATCH_MOUNTS, NULL, NULL); if (dir_monitor != NULL) { ret->monitor = dir_monitor; } else if (!g_file_is_native (location)) { ret->location = g_object_ref (location); ret->volume_monitor = g_volume_monitor_get (); } if (ret->monitor != NULL) { g_signal_connect (ret->monitor, "changed", G_CALLBACK (dir_changed), ret); } if (ret->volume_monitor != NULL) { g_signal_connect (ret->volume_monitor, "mount-removed", G_CALLBACK (mount_removed), ret); } /* We return a monitor even on failure, so we can avoid later trying again */ return ret; } void nemo_monitor_cancel (NemoMonitor *monitor) { if (monitor->monitor != NULL) { g_signal_handlers_disconnect_by_func (monitor->monitor, dir_changed, monitor); g_file_monitor_cancel (monitor->monitor); g_object_unref (monitor->monitor); } if (monitor->volume_monitor != NULL) { g_signal_handlers_disconnect_by_func (monitor->volume_monitor, mount_removed, monitor); g_object_unref (monitor->volume_monitor); } g_clear_object (&monitor->location); g_free (monitor); } nemo-4.4.2/libnemo-private/nemo-monitor.h000066400000000000000000000024531357442400300203560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-monitor.h: file and directory change monitoring for nemo Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Authors: Seth Nickell Darin Adler */ #ifndef NEMO_MONITOR_H #define NEMO_MONITOR_H #include #include typedef struct NemoMonitor NemoMonitor; gboolean nemo_monitor_active (void); NemoMonitor *nemo_monitor_directory (GFile *location); void nemo_monitor_cancel (NemoMonitor *monitor); #endif /* NEMO_MONITOR_H */ nemo-4.4.2/libnemo-private/nemo-placement-grid.c000066400000000000000000000137361357442400300215630ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Copyright (C) 1999, 2000 Free Software Foundation Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Ettore Perazzoli */ #include "math.h" #include #include "nemo-icon-private.h" NemoPlacementGrid * nemo_placement_grid_new (NemoIconContainer *container, gboolean tight) { NemoPlacementGrid *grid; int width, height; int num_columns; int num_rows; int i; GtkAllocation allocation; /* Get container dimensions */ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); width = nemo_icon_container_get_canvas_width (container, allocation); height = nemo_icon_container_get_canvas_height (container, allocation); num_columns = width / GET_VIEW_CONSTANT (container, snap_size_x); num_rows = height / GET_VIEW_CONSTANT (container, snap_size_y); if (num_columns == 0 || num_rows == 0) { return NULL; } grid = g_new0 (NemoPlacementGrid, 1); grid->container = container; grid->tight = tight; grid->num_columns = num_columns; grid->num_rows = num_rows; grid->grid_memory = g_new0 (int, (num_rows * num_columns)); grid->icon_grid = g_new0 (int *, num_columns); for (i = 0; i < num_columns; i++) { grid->icon_grid[i] = grid->grid_memory + (i * num_rows); } return grid; } void nemo_placement_grid_free (NemoPlacementGrid *grid) { g_free (grid->icon_grid); g_free (grid->grid_memory); g_free (grid); } gboolean nemo_placement_grid_position_is_free (NemoPlacementGrid *grid, EelIRect pos) { int x, y; g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns); g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows); g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns); g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows); for (x = pos.x0; x <= pos.x1; x++) { for (y = pos.y0; y <= pos.y1; y++) { if (grid->icon_grid[x][y] != 0) { return FALSE; } } } return TRUE; } void nemo_placement_grid_mark (NemoPlacementGrid *grid, EelIRect pos) { int x, y; g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns); g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows); g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns); g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows); for (x = pos.x0; x <= pos.x1; x++) { for (y = pos.y0; y <= pos.y1; y++) { grid->icon_grid[x][y] = 1; } } } void nemo_placement_grid_canvas_position_to_grid_position (NemoPlacementGrid *grid, EelIRect canvas_position, EelIRect *grid_position) { /* The first causes minimal moving around during a snap, but * can end up with partially overlapping icons. The second one won't * allow any overlapping, but can cause more movement to happen * during a snap. */ NemoIconContainer *container = grid->container; if (grid->tight) { grid_position->x0 = ceil ((double)(canvas_position.x0 - GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) / GET_VIEW_CONSTANT (container, snap_size_x)); grid_position->y0 = ceil ((double)(canvas_position.y0 - GET_VIEW_CONSTANT (container, desktop_pad_vertical)) / GET_VIEW_CONSTANT (container, snap_size_y)); grid_position->x1 = floor ((double)(canvas_position.x1 - GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) / GET_VIEW_CONSTANT (container, snap_size_x)); grid_position->y1 = floor ((double)(canvas_position.y1 - GET_VIEW_CONSTANT (container, desktop_pad_vertical)) / GET_VIEW_CONSTANT (container, snap_size_y)); } else { grid_position->x0 = floor ((double)(canvas_position.x0 - GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) / GET_VIEW_CONSTANT (container, snap_size_x)); grid_position->y0 = floor ((double)(canvas_position.y0 - GET_VIEW_CONSTANT (container, desktop_pad_vertical)) / GET_VIEW_CONSTANT (container, snap_size_y)); grid_position->x1 = floor ((double)(canvas_position.x1 - GET_VIEW_CONSTANT (container, desktop_pad_horizontal)) / GET_VIEW_CONSTANT (container, snap_size_x)); grid_position->y1 = floor ((double)(canvas_position.y1 - GET_VIEW_CONSTANT (container, desktop_pad_vertical)) / GET_VIEW_CONSTANT (container, snap_size_y)); } grid_position->x0 = CLAMP (grid_position->x0, 0, grid->num_columns - 1); grid_position->y0 = CLAMP (grid_position->y0, 0, grid->num_rows - 1); grid_position->x1 = CLAMP (grid_position->x1, grid_position->x0, grid->num_columns - 1); grid_position->y1 = CLAMP (grid_position->y1, grid_position->y0, grid->num_rows - 1); } void nemo_placement_grid_mark_icon (NemoPlacementGrid *grid, NemoIcon *icon) { EelIRect icon_pos; EelIRect grid_pos; nemo_icon_container_icon_get_bounding_box (grid->container, icon, &icon_pos.x0, &icon_pos.y0, &icon_pos.x1, &icon_pos.y1, BOUNDS_USAGE_FOR_LAYOUT); nemo_placement_grid_canvas_position_to_grid_position (grid, icon_pos, &grid_pos); nemo_placement_grid_mark (grid, grid_pos); } nemo-4.4.2/libnemo-private/nemo-places-tree-view.c000066400000000000000000000104021357442400300220270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-places-tree-view.h" G_DEFINE_TYPE (NemoPlacesTreeView, nemo_places_tree_view, GTK_TYPE_TREE_VIEW); static void nemo_places_tree_view_finalize (GObject *gobject); static gpointer parent_class; static void nemo_places_tree_view_init (NemoPlacesTreeView *tree_view) { gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)), "places-treeview"); } static void nemo_places_tree_view_class_init (NemoPlacesTreeViewClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = nemo_places_tree_view_finalize; gtk_widget_class_install_style_property (widget_class, g_param_spec_boxed ("disk-full-bg-color", "Unselected disk indicator background color", "Unselected disk indicator background color", GDK_TYPE_COLOR, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_boxed ("disk-full-fg-color", "Unselected disk indicator foreground color", "Unselected disk indicator foreground color", GDK_TYPE_COLOR, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("disk-full-bar-width", "Disk indicator bar width", "Disk indicator bar width", 0, G_MAXINT, 2, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("disk-full-bar-radius", "Disk indicator bar radius (usually half the width)", "Disk indicator bar radius (usually half the width)", 0, G_MAXINT, 1, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("disk-full-bottom-padding", "Extra padding under the disk indicator", "Extra padding under the disk indicator", 0, G_MAXINT, 1, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("disk-full-max-length", "Maximum length of the disk indicator", "Maximum length of the disk indicator", 0, G_MAXINT, 70, G_PARAM_READABLE)); } GtkWidget * nemo_places_tree_view_new (void) { return g_object_new (NEMO_TYPE_PLACES_TREE_VIEW, NULL); } static void nemo_places_tree_view_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } nemo-4.4.2/libnemo-private/nemo-places-tree-view.h000066400000000000000000000037201357442400300220410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- Copyright (C) 2007 Martin Wehner 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_PLACES_TREE_VIEW_H #define NEMO_PLACES_TREE_VIEW_H #include #define NEMO_TYPE_PLACES_TREE_VIEW nemo_places_tree_view_get_type() #define NEMO_PLACES_TREE_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PLACES_TREE_VIEW, NemoPlacesTreeView)) #define NEMO_PLACES_TREE_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PLACES_TREE_VIEW, NemoPlacesTreeViewClass)) #define NEMO_IS_PLACES_TREE_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PLACES_TREE_VIEW)) #define NEMO_IS_PLACES_TREE_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PLACES_TREE_VIEW)) #define NEMO_PLACES_TREE_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PLACES_TREE_VIEW, NemoPlacesTreeViewClass)) typedef struct _NemoPlacesTreeView NemoPlacesTreeView; typedef struct _NemoPlacesTreeViewClass NemoPlacesTreeViewClass; struct _NemoPlacesTreeView { GtkTreeView parent; }; struct _NemoPlacesTreeViewClass { GtkTreeViewClass parent_class; }; GType nemo_places_tree_view_get_type (void); GtkWidget *nemo_places_tree_view_new (void); #endif /* NEMO_PLACES_TREE_VIEW_H */ nemo-4.4.2/libnemo-private/nemo-program-choosing.c000066400000000000000000000267351357442400300221510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-program-choosing.c - functions for selecting and activating programs for opening/viewing particular files. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: John Sullivan */ #include #include "nemo-program-choosing.h" #include "nemo-global-preferences.h" #include "nemo-icon-info.h" #include "nemo-recent.h" #include "nemo-desktop-icon-file.h" #include #include #include #include #include #include #include #include #include void nemo_launch_application_for_mount (GAppInfo *app_info, GMount *mount, GtkWindow *parent_window) { GFile *root; NemoFile *file; GList *files; root = g_mount_get_root (mount); file = nemo_file_get (root); g_object_unref (root); files = g_list_append (NULL, file); nemo_launch_application (app_info, files, parent_window); g_list_free_full (files, (GDestroyNotify) nemo_file_unref); } /** * nemo_launch_application: * * Fork off a process to launch an application with a given file as a * parameter. Provide a parent window for error dialogs. * * @application: The application to be launched. * @uris: The files whose locations should be passed as a parameter to the application. * @parent_window: A window to use as the parent for any error dialogs. */ void nemo_launch_application (GAppInfo *application, GList *files, GtkWindow *parent_window) { GList *uris, *l; uris = NULL; for (l = files; l != NULL; l = l->next) { uris = g_list_prepend (uris, nemo_file_get_activation_uri (l->data)); } uris = g_list_reverse (uris); nemo_launch_application_by_uri (application, uris, parent_window); g_list_free_full (uris, g_free); } static void dummy_child_watch (GPid pid, gint status, gpointer user_data) { /* Nothing, this is just to ensure we don't double fork * and break pkexec: * https://bugzilla.gnome.org/show_bug.cgi?id=675789 */ } static void gather_pid_callback (GDesktopAppInfo *appinfo, GPid pid, gpointer data) { g_child_watch_add(pid, dummy_child_watch, NULL); } void nemo_launch_application_by_uri (GAppInfo *application, GList *uris, GtkWindow *parent_window) { char *uri; GList *locations, *l; GFile *location; NemoFile *file; gboolean result; GError *error; GdkDisplay *display; GdkAppLaunchContext *launch_context; NemoIconInfo *icon; int count; g_assert (uris != NULL); /* count the number of uris with local paths */ count = 0; locations = NULL; for (l = uris; l != NULL; l = l->next) { uri = l->data; location = g_file_new_for_uri (uri); if (g_file_is_native (location)) { count++; } locations = g_list_prepend (locations, location); } locations = g_list_reverse (locations); if (parent_window != NULL) { display = gtk_widget_get_display (GTK_WIDGET (parent_window)); } else { display = gdk_display_get_default (); } launch_context = gdk_display_get_app_launch_context (display); if (parent_window != NULL) { gdk_app_launch_context_set_screen (launch_context, gtk_window_get_screen (parent_window)); } file = nemo_file_get_by_uri (uris->data); icon = nemo_file_get_icon (file, 48, 0, gtk_widget_get_scale_factor (GTK_WIDGET (parent_window)), 0); nemo_file_unref (file); if (icon) { gdk_app_launch_context_set_icon_name (launch_context, nemo_icon_info_get_used_name (icon)); nemo_icon_info_unref (icon); } error = NULL; result = g_desktop_app_info_launch_uris_as_manager (G_DESKTOP_APP_INFO (application), uris, G_APP_LAUNCH_CONTEXT (launch_context), G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, gather_pid_callback, application, &error); g_object_unref (launch_context); if (result) { for (l = uris; l != NULL; l = l->next) { file = nemo_file_get_by_uri (l->data); nemo_recent_add_file (file, application); nemo_file_unref (file); } } g_list_free_full (locations, g_object_unref); } static void launch_application_from_command_internal (const gchar *full_command, GdkScreen *screen, gboolean use_terminal) { GAppInfo *app; GdkAppLaunchContext *ctx; GdkDisplay *display; if (use_terminal) { eel_gnome_open_terminal_on_screen (full_command, screen); } else { app = g_app_info_create_from_commandline (full_command, NULL, 0, NULL); if (app != NULL) { display = gdk_screen_get_display (screen); ctx = gdk_display_get_app_launch_context (display); gdk_app_launch_context_set_screen (ctx, screen); g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (ctx), NULL); g_object_unref (app); g_object_unref (ctx); } } } /** * nemo_launch_application_from_command: * * Fork off a process to launch an application with a given uri as * a parameter. * * @command_string: The application to be launched, with any desired * command-line options. * @...: Passed as parameters to the application after quoting each of them. */ void nemo_launch_application_from_command (GdkScreen *screen, const char *command_string, gboolean use_terminal, ...) { char *full_command, *tmp; char *quoted_parameter; char *parameter; va_list ap; full_command = g_strdup (command_string); va_start (ap, use_terminal); while ((parameter = va_arg (ap, char *)) != NULL) { quoted_parameter = g_shell_quote (parameter); tmp = g_strconcat (full_command, " ", quoted_parameter, NULL); g_free (quoted_parameter); g_free (full_command); full_command = tmp; } va_end (ap); launch_application_from_command_internal (full_command, screen, use_terminal); g_free (full_command); } /** * nemo_launch_application_from_command: * * Fork off a process to launch an application with a given uri as * a parameter. * * @command_string: The application to be launched, with any desired * command-line options. * @parameters: Passed as parameters to the application after quoting each of them. */ void nemo_launch_application_from_command_array (GdkScreen *screen, const char *command_string, gboolean use_terminal, const char * const * parameters) { char *full_command, *tmp; char *quoted_parameter; const char * const *p; full_command = g_strdup (command_string); if (parameters != NULL) { for (p = parameters; *p != NULL; p++) { quoted_parameter = g_shell_quote (*p); tmp = g_strconcat (full_command, " ", quoted_parameter, NULL); g_free (quoted_parameter); g_free (full_command); full_command = tmp; } } launch_application_from_command_internal (full_command, screen, use_terminal); g_free (full_command); } void nemo_launch_desktop_file (GdkScreen *screen, const char *desktop_file_uri, const GList *parameter_uris, GtkWindow *parent_window) { GError *error; char *message, *desktop_file_path; const GList *p; GList *files; int total, count; GFile *file, *desktop_file; GDesktopAppInfo *app_info; GdkAppLaunchContext *context; /* Don't allow command execution from remote locations * to partially mitigate the security * risk of executing arbitrary commands. */ desktop_file = g_file_new_for_uri (desktop_file_uri); desktop_file_path = g_file_get_path (desktop_file); if (!g_file_is_native (desktop_file)) { g_free (desktop_file_path); g_object_unref (desktop_file); eel_show_error_dialog (_("Sorry, but you cannot execute commands from " "a remote site."), _("This is disabled due to security considerations."), parent_window); return; } g_object_unref (desktop_file); app_info = g_desktop_app_info_new_from_filename (desktop_file_path); g_free (desktop_file_path); if (app_info == NULL) { eel_show_error_dialog (_("There was an error launching the application."), NULL, parent_window); return; } /* count the number of uris with local paths */ count = 0; total = g_list_length ((GList *) parameter_uris); files = NULL; for (p = parameter_uris; p != NULL; p = p->next) { file = g_file_new_for_uri ((const char *) p->data); if (g_file_is_native (file)) { count++; } files = g_list_prepend (files, file); } /* check if this app only supports local files */ if (g_app_info_supports_files (G_APP_INFO (app_info)) && !g_app_info_supports_uris (G_APP_INFO (app_info)) && parameter_uris != NULL) { if (count == 0) { /* all files are non-local */ eel_show_error_dialog (_("This drop target only supports local files."), _("To open non-local files copy them to a local folder and then" " drop them again."), parent_window); g_list_free_full (files, g_object_unref); g_object_unref (app_info); return; } else if (count != total) { /* some files are non-local */ eel_show_warning_dialog (_("This drop target only supports local files."), _("To open non-local files copy them to a local folder and then" " drop them again. The local files you dropped have already been opened."), parent_window); } } error = NULL; context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (parent_window))); /* TODO: Ideally we should accept a timestamp here instead of using GDK_CURRENT_TIME */ gdk_app_launch_context_set_timestamp (context, GDK_CURRENT_TIME); gdk_app_launch_context_set_screen (context, gtk_window_get_screen (parent_window)); g_desktop_app_info_launch_uris_as_manager (app_info, (GList *) parameter_uris, G_APP_LAUNCH_CONTEXT (context), G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, gather_pid_callback, app_info, &error); if (error != NULL) { message = g_strconcat (_("Details: "), error->message, NULL); eel_show_error_dialog (_("There was an error launching the application."), message, parent_window); g_error_free (error); g_free (message); } g_list_free_full (files, g_object_unref); g_object_unref (context); g_object_unref (app_info); } nemo-4.4.2/libnemo-private/nemo-program-choosing.h000066400000000000000000000053151357442400300221450ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-program-choosing.h - functions for selecting and activating programs for opening/viewing particular files. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: John Sullivan */ #ifndef NEMO_PROGRAM_CHOOSING_H #define NEMO_PROGRAM_CHOOSING_H #include #include #include typedef void (*NemoApplicationChoiceCallback) (GAppInfo *application, gpointer callback_data); void nemo_launch_application (GAppInfo *application, GList *files, GtkWindow *parent_window); void nemo_launch_application_by_uri (GAppInfo *application, GList *uris, GtkWindow *parent_window); void nemo_launch_application_for_mount (GAppInfo *app_info, GMount *mount, GtkWindow *parent_window); void nemo_launch_application_from_command (GdkScreen *screen, const char *command_string, gboolean use_terminal, ...) G_GNUC_NULL_TERMINATED; void nemo_launch_application_from_command_array (GdkScreen *screen, const char *command_string, gboolean use_terminal, const char * const * parameters); void nemo_launch_desktop_file (GdkScreen *screen, const char *desktop_file_uri, const GList *parameter_uris, GtkWindow *parent_window); #endif /* NEMO_PROGRAM_CHOOSING_H */ nemo-4.4.2/libnemo-private/nemo-progress-info-manager.c000066400000000000000000000074011357442400300230650ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Cosimo Cecchi */ #include #include "nemo-progress-info-manager.h" struct _NemoProgressInfoManagerPriv { GList *progress_infos; }; enum { NEW_PROGRESS_INFO, LAST_SIGNAL }; static NemoProgressInfoManager *singleton = NULL; static guint signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (NemoProgressInfoManager, nemo_progress_info_manager, G_TYPE_OBJECT); static void nemo_progress_info_manager_finalize (GObject *obj) { NemoProgressInfoManager *self = NEMO_PROGRESS_INFO_MANAGER (obj); if (self->priv->progress_infos != NULL) { g_list_free_full (self->priv->progress_infos, g_object_unref); } G_OBJECT_CLASS (nemo_progress_info_manager_parent_class)->finalize (obj); } static GObject * nemo_progress_info_manager_constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *retval; if (singleton != NULL) { return g_object_ref (G_OBJECT (singleton)); } retval = G_OBJECT_CLASS (nemo_progress_info_manager_parent_class)->constructor (type, n_props, props); singleton = NEMO_PROGRESS_INFO_MANAGER (retval); g_object_add_weak_pointer (retval, (gpointer) &singleton); return retval; } static void nemo_progress_info_manager_init (NemoProgressInfoManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_PROGRESS_INFO_MANAGER, NemoProgressInfoManagerPriv); } static void nemo_progress_info_manager_class_init (NemoProgressInfoManagerClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->constructor = nemo_progress_info_manager_constructor; oclass->finalize = nemo_progress_info_manager_finalize; signals[NEW_PROGRESS_INFO] = g_signal_new ("new-progress-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NEMO_TYPE_PROGRESS_INFO); g_type_class_add_private (klass, sizeof (NemoProgressInfoManagerPriv)); } static void progress_info_finished_cb (NemoProgressInfo *info, NemoProgressInfoManager *self) { self->priv->progress_infos = g_list_remove (self->priv->progress_infos, info); } NemoProgressInfoManager * nemo_progress_info_manager_new (void) { return g_object_new (NEMO_TYPE_PROGRESS_INFO_MANAGER, NULL); } void nemo_progress_info_manager_add_new_info (NemoProgressInfoManager *self, NemoProgressInfo *info) { if (g_list_find (self->priv->progress_infos, info) != NULL) { g_warning ("Adding two times the same progress info object to the manager"); return; } self->priv->progress_infos = g_list_prepend (self->priv->progress_infos, g_object_ref (info)); g_signal_connect (info, "finished", G_CALLBACK (progress_info_finished_cb), self); g_signal_emit (self, signals[NEW_PROGRESS_INFO], 0, info); } GList * nemo_progress_info_manager_get_all_infos (NemoProgressInfoManager *self) { return self->priv->progress_infos; } nemo-4.4.2/libnemo-private/nemo-progress-info-manager.h000066400000000000000000000051141357442400300230710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Cosimo Cecchi */ #ifndef __NEMO_PROGRESS_INFO_MANAGER_H__ #define __NEMO_PROGRESS_INFO_MANAGER_H__ #include #include #define NEMO_TYPE_PROGRESS_INFO_MANAGER nemo_progress_info_manager_get_type() #define NEMO_PROGRESS_INFO_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PROGRESS_INFO_MANAGER, NemoProgressInfoManager)) #define NEMO_PROGRESS_INFO_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PROGRESS_INFO_MANAGER, NemoProgressInfoManagerClass)) #define NEMO_IS_PROGRESS_INFO_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PROGRESS_INFO_MANAGER)) #define NEMO_IS_PROGRESS_INFO_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PROGRESS_INFO_MANAGER)) #define NEMO_PROGRESS_INFO_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PROGRESS_INFO_MANAGER, NemoProgressInfoManagerClass)) typedef struct _NemoProgressInfoManager NemoProgressInfoManager; typedef struct _NemoProgressInfoManagerClass NemoProgressInfoManagerClass; typedef struct _NemoProgressInfoManagerPriv NemoProgressInfoManagerPriv; struct _NemoProgressInfoManager { GObject parent; /* private */ NemoProgressInfoManagerPriv *priv; }; struct _NemoProgressInfoManagerClass { GObjectClass parent_class; }; GType nemo_progress_info_manager_get_type (void); NemoProgressInfoManager* nemo_progress_info_manager_new (void); void nemo_progress_info_manager_add_new_info (NemoProgressInfoManager *self, NemoProgressInfo *info); GList *nemo_progress_info_manager_get_all_infos (NemoProgressInfoManager *self); G_END_DECLS #endif /* __NEMO_PROGRESS_INFO_MANAGER_H__ */ nemo-4.4.2/libnemo-private/nemo-progress-info.c000066400000000000000000000310071357442400300214540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-progress-info.h: file operation progress info. Copyright (C) 2007 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include #include #include #include #include "nemo-progress-info.h" #include "nemo-progress-info-manager.h" enum { CHANGED, QUEUED, PROGRESS_CHANGED, STARTED, FINISHED, LAST_SIGNAL }; #define SIGNAL_DELAY_MSEC 100 static guint signals[LAST_SIGNAL] = { 0 }; struct _NemoProgressInfo { GObject parent_instance; GCancellable *cancellable; char *status; char *details; char *initial_details; double progress; gboolean activity_mode; gboolean started; gboolean finished; gboolean paused; gboolean queued; GSource *idle_source; gboolean source_is_now; gboolean start_at_idle; gboolean finish_at_idle; gboolean changed_at_idle; gboolean progress_at_idle; gboolean queue_at_idle; }; struct _NemoProgressInfoClass { GObjectClass parent_class; }; G_LOCK_DEFINE_STATIC(progress_info); G_DEFINE_TYPE (NemoProgressInfo, nemo_progress_info, G_TYPE_OBJECT) static void nemo_progress_info_finalize (GObject *object) { NemoProgressInfo *info; info = NEMO_PROGRESS_INFO (object); g_free (info->status); g_free (info->details); g_free (info->initial_details); g_object_unref (info->cancellable); if (G_OBJECT_CLASS (nemo_progress_info_parent_class)->finalize) { (*G_OBJECT_CLASS (nemo_progress_info_parent_class)->finalize) (object); } } static void nemo_progress_info_dispose (GObject *object) { NemoProgressInfo *info; info = NEMO_PROGRESS_INFO (object); G_LOCK (progress_info); /* Destroy source in dispose, because the callback could come here before the destroy, which should ressurect the object for a while */ if (info->idle_source) { g_source_destroy (info->idle_source); g_source_unref (info->idle_source); info->idle_source = NULL; } G_UNLOCK (progress_info); } static void nemo_progress_info_class_init (NemoProgressInfoClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = nemo_progress_info_finalize; gobject_class->dispose = nemo_progress_info_dispose; signals[CHANGED] = g_signal_new ("changed", NEMO_TYPE_PROGRESS_INFO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[QUEUED] = g_signal_new ("queued", NEMO_TYPE_PROGRESS_INFO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PROGRESS_CHANGED] = g_signal_new ("progress-changed", NEMO_TYPE_PROGRESS_INFO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[STARTED] = g_signal_new ("started", NEMO_TYPE_PROGRESS_INFO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FINISHED] = g_signal_new ("finished", NEMO_TYPE_PROGRESS_INFO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void nemo_progress_info_init (NemoProgressInfo *info) { NemoProgressInfoManager *manager; info->cancellable = g_cancellable_new (); manager = nemo_progress_info_manager_new (); nemo_progress_info_manager_add_new_info (manager, info); g_object_unref (manager); } NemoProgressInfo * nemo_progress_info_new (void) { NemoProgressInfo *info; info = g_object_new (NEMO_TYPE_PROGRESS_INFO, NULL); return info; } char * nemo_progress_info_get_status (NemoProgressInfo *info) { char *res; G_LOCK (progress_info); if (info->status) { res = g_strdup (info->status); } else { res = g_strdup (_("Preparing")); } G_UNLOCK (progress_info); return res; } char * nemo_progress_info_get_details (NemoProgressInfo *info) { char *res; G_LOCK (progress_info); if (info->details) { res = g_strdup (info->details); } else { res = g_strdup (_("Preparing")); } G_UNLOCK (progress_info); return res; } char * nemo_progress_info_get_initial_details (NemoProgressInfo *info) { char *res; G_LOCK (progress_info); if (info->initial_details) { res = g_strdup (info->initial_details); } else { res = g_strdup (_("Preparing")); } G_UNLOCK (progress_info); return res; } double nemo_progress_info_get_progress (NemoProgressInfo *info) { double res; G_LOCK (progress_info); if (info->activity_mode) { res = -1.0; } else { res = info->progress; } G_UNLOCK (progress_info); return res; } void nemo_progress_info_cancel (NemoProgressInfo *info) { G_LOCK (progress_info); g_cancellable_cancel (info->cancellable); G_UNLOCK (progress_info); } GCancellable * nemo_progress_info_get_cancellable (NemoProgressInfo *info) { GCancellable *c; G_LOCK (progress_info); c = g_object_ref (info->cancellable); G_UNLOCK (progress_info); return c; } gboolean nemo_progress_info_get_is_started (NemoProgressInfo *info) { gboolean res; G_LOCK (progress_info); res = info->started; G_UNLOCK (progress_info); return res; } gboolean nemo_progress_info_get_is_finished (NemoProgressInfo *info) { gboolean res; G_LOCK (progress_info); res = info->finished; G_UNLOCK (progress_info); return res; } gboolean nemo_progress_info_get_is_paused (NemoProgressInfo *info) { gboolean res; G_LOCK (progress_info); res = info->paused; G_UNLOCK (progress_info); return res; } static gboolean idle_callback (gpointer data) { NemoProgressInfo *info = data; gboolean start_at_idle; gboolean finish_at_idle; gboolean changed_at_idle; gboolean progress_at_idle; gboolean queue_at_idle; GSource *source; source = g_main_current_source (); G_LOCK (progress_info); /* Protect agains races where the source has been destroyed on another thread while it was being dispatched. Similar to what gdk_threads_add_idle does. */ if (g_source_is_destroyed (source)) { G_UNLOCK (progress_info); return FALSE; } /* We hadn't destroyed the source, so take a ref. * This might ressurect the object from dispose, but * that should be ok. */ g_object_ref (info); g_assert (source == info->idle_source); g_source_unref (source); info->idle_source = NULL; start_at_idle = info->start_at_idle; finish_at_idle = info->finish_at_idle; changed_at_idle = info->changed_at_idle; progress_at_idle = info->progress_at_idle; queue_at_idle = info->queue_at_idle; info->start_at_idle = FALSE; info->finish_at_idle = FALSE; info->changed_at_idle = FALSE; info->progress_at_idle = FALSE; info->queue_at_idle = FALSE; G_UNLOCK (progress_info); if (queue_at_idle) { g_signal_emit (info, signals[QUEUED], 0); } if (start_at_idle) { g_signal_emit (info, signals[STARTED], 0); } if (changed_at_idle) { g_signal_emit (info, signals[CHANGED], 0); } if (progress_at_idle) { g_signal_emit (info, signals[PROGRESS_CHANGED], 0); } if (finish_at_idle) { g_signal_emit (info, signals[FINISHED], 0); } g_object_unref (info); return FALSE; } /* Called with lock held */ static void queue_idle (NemoProgressInfo *info, gboolean now) { if (info->idle_source == NULL || (now && !info->source_is_now)) { if (info->idle_source) { g_source_destroy (info->idle_source); g_source_unref (info->idle_source); info->idle_source = NULL; } info->source_is_now = now; if (now) { info->idle_source = g_idle_source_new (); } else { info->idle_source = g_timeout_source_new (SIGNAL_DELAY_MSEC); } g_source_set_callback (info->idle_source, idle_callback, info, NULL); g_source_attach (info->idle_source, NULL); } } void nemo_progress_info_queue (NemoProgressInfo *info) { G_LOCK (progress_info); if (!info->queued) { info->queued = TRUE; info->queue_at_idle = TRUE; queue_idle (info, TRUE); } G_UNLOCK (progress_info); } void nemo_progress_info_pause (NemoProgressInfo *info) { G_LOCK (progress_info); if (!info->paused) { info->paused = TRUE; } G_UNLOCK (progress_info); } void nemo_progress_info_resume (NemoProgressInfo *info) { G_LOCK (progress_info); if (info->paused) { info->paused = FALSE; } G_UNLOCK (progress_info); } void nemo_progress_info_start (NemoProgressInfo *info) { G_LOCK (progress_info); if (!info->started) { info->started = TRUE; info->start_at_idle = TRUE; queue_idle (info, TRUE); } G_UNLOCK (progress_info); } void nemo_progress_info_finish (NemoProgressInfo *info) { G_LOCK (progress_info); if (!info->finished) { info->finished = TRUE; info->finish_at_idle = TRUE; queue_idle (info, TRUE); } G_UNLOCK (progress_info); } void nemo_progress_info_take_status (NemoProgressInfo *info, char *status) { G_LOCK (progress_info); if (g_strcmp0 (info->status, status) != 0) { g_free (info->status); info->status = status; info->changed_at_idle = TRUE; queue_idle (info, FALSE); } else { g_free (status); } G_UNLOCK (progress_info); } void nemo_progress_info_set_status (NemoProgressInfo *info, const char *status) { G_LOCK (progress_info); if (g_strcmp0 (info->status, status) != 0) { g_free (info->status); info->status = g_strdup (status); info->changed_at_idle = TRUE; queue_idle (info, FALSE); } G_UNLOCK (progress_info); } void nemo_progress_info_take_details (NemoProgressInfo *info, char *details) { G_LOCK (progress_info); if (g_strcmp0 (info->details, details) != 0) { g_free (info->details); info->details = details; info->changed_at_idle = TRUE; queue_idle (info, FALSE); } else { g_free (details); } G_UNLOCK (progress_info); } void nemo_progress_info_set_details (NemoProgressInfo *info, const char *details) { G_LOCK (progress_info); if (g_strcmp0 (info->details, details) != 0) { g_free (info->details); info->details = g_strdup (details); info->changed_at_idle = TRUE; queue_idle (info, FALSE); } G_UNLOCK (progress_info); } void nemo_progress_info_take_initial_details (NemoProgressInfo *info, char *initial_details) { G_LOCK (progress_info); if (g_strcmp0 (info->initial_details, initial_details) != 0) { g_free (info->initial_details); info->initial_details = initial_details; info->changed_at_idle = TRUE; queue_idle (info, FALSE); } else { g_free (initial_details); } G_UNLOCK (progress_info); } void nemo_progress_info_pulse_progress (NemoProgressInfo *info) { G_LOCK (progress_info); info->activity_mode = TRUE; info->progress = 0.0; info->progress_at_idle = TRUE; queue_idle (info, FALSE); G_UNLOCK (progress_info); } void nemo_progress_info_set_progress (NemoProgressInfo *info, double current, double total) { double current_percent; if (total <= 0) { current_percent = 1.0; } else { current_percent = current / total; if (current_percent < 0) { current_percent = 0; } if (current_percent > 1.0) { current_percent = 1.0; } } G_LOCK (progress_info); if (info->activity_mode || /* emit on switch from activity mode */ fabs (current_percent - info->progress) > 0.005 /* Emit on change of 0.5 percent */ ) { info->activity_mode = FALSE; info->progress = current_percent; info->progress_at_idle = TRUE; queue_idle (info, FALSE); } G_UNLOCK (progress_info); } nemo-4.4.2/libnemo-private/nemo-progress-info.h000066400000000000000000000101631357442400300214610ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-progress-info.h: file operation progress info. Copyright (C) 2007 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_PROGRESS_INFO_H #define NEMO_PROGRESS_INFO_H #include #include #define NEMO_TYPE_PROGRESS_INFO (nemo_progress_info_get_type ()) #define NEMO_PROGRESS_INFO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_PROGRESS_INFO, NemoProgressInfo)) #define NEMO_PROGRESS_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_PROGRESS_INFO, NemoProgressInfoClass)) #define NEMO_IS_PROGRESS_INFO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_PROGRESS_INFO)) #define NEMO_IS_PROGRESS_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_PROGRESS_INFO)) #define NEMO_PROGRESS_INFO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_PROGRESS_INFO, NemoProgressInfoClass)) typedef struct _NemoProgressInfo NemoProgressInfo; typedef struct _NemoProgressInfoClass NemoProgressInfoClass; GType nemo_progress_info_get_type (void) G_GNUC_CONST; /* Signals: "changed" - status or details changed "progress-changed" - the percentage progress changed (or we pulsed if in activity_mode "started" - emited on job start "finished" - emitted when job is done All signals are emitted from idles in main loop. All methods are threadsafe. */ NemoProgressInfo *nemo_progress_info_new (void); GList * nemo_get_all_progress_info (void); char * nemo_progress_info_get_status (NemoProgressInfo *info); char * nemo_progress_info_get_details (NemoProgressInfo *info); char * nemo_progress_info_get_initial_details (NemoProgressInfo *info); double nemo_progress_info_get_progress (NemoProgressInfo *info); GCancellable *nemo_progress_info_get_cancellable (NemoProgressInfo *info); void nemo_progress_info_cancel (NemoProgressInfo *info); gboolean nemo_progress_info_get_is_started (NemoProgressInfo *info); gboolean nemo_progress_info_get_is_finished (NemoProgressInfo *info); gboolean nemo_progress_info_get_is_paused (NemoProgressInfo *info); void nemo_progress_info_queue (NemoProgressInfo *info); void nemo_progress_info_start (NemoProgressInfo *info); void nemo_progress_info_finish (NemoProgressInfo *info); void nemo_progress_info_pause (NemoProgressInfo *info); void nemo_progress_info_resume (NemoProgressInfo *info); void nemo_progress_info_set_status (NemoProgressInfo *info, const char *status); void nemo_progress_info_take_status (NemoProgressInfo *info, char *status); void nemo_progress_info_set_details (NemoProgressInfo *info, const char *details); void nemo_progress_info_take_initial_details (NemoProgressInfo *info, char *initial_details); void nemo_progress_info_take_details (NemoProgressInfo *info, char *details); void nemo_progress_info_set_progress (NemoProgressInfo *info, double current, double total); void nemo_progress_info_pulse_progress (NemoProgressInfo *info); #endif /* NEMO_PROGRESS_INFO_H */ nemo-4.4.2/libnemo-private/nemo-query.c000066400000000000000000000214761357442400300200350ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Novell, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Anders Carlsson * */ #include #include #include "nemo-query.h" #include #include #include struct NemoQueryDetails { char *text; char *location_uri; GList *mime_types; gboolean show_hidden; }; G_DEFINE_TYPE (NemoQuery, nemo_query, G_TYPE_OBJECT); static void finalize (GObject *object) { NemoQuery *query; query = NEMO_QUERY (object); g_free (query->details->text); g_free (query->details->location_uri); G_OBJECT_CLASS (nemo_query_parent_class)->finalize (object); } static void nemo_query_class_init (NemoQueryClass *class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (class); gobject_class->finalize = finalize; g_type_class_add_private (class, sizeof (NemoQueryDetails)); } static void nemo_query_init (NemoQuery *query) { query->details = G_TYPE_INSTANCE_GET_PRIVATE (query, NEMO_TYPE_QUERY, NemoQueryDetails); } NemoQuery * nemo_query_new (void) { return g_object_new (NEMO_TYPE_QUERY, NULL); } char * nemo_query_get_text (NemoQuery *query) { g_return_val_if_fail (NEMO_IS_QUERY (query), NULL); return g_strdup (query->details->text); } void nemo_query_set_text (NemoQuery *query, const char *text) { g_return_if_fail (NEMO_IS_QUERY (query)); g_free (query->details->text); query->details->text = g_strstrip (g_strdup (text)); } char * nemo_query_get_location (NemoQuery *query) { g_return_val_if_fail (NEMO_IS_QUERY (query), NULL); return g_strdup (query->details->location_uri); } void nemo_query_set_location (NemoQuery *query, const char *uri) { g_return_if_fail (NEMO_IS_QUERY (query)); g_free (query->details->location_uri); query->details->location_uri = g_strdup (uri); } GList * nemo_query_get_mime_types (NemoQuery *query) { g_return_val_if_fail (NEMO_IS_QUERY (query), NULL); return eel_g_str_list_copy (query->details->mime_types); } void nemo_query_set_mime_types (NemoQuery *query, GList *mime_types) { g_return_if_fail (NEMO_IS_QUERY (query)); g_list_free_full (query->details->mime_types, g_free); query->details->mime_types = eel_g_str_list_copy (mime_types); } void nemo_query_add_mime_type (NemoQuery *query, const char *mime_type) { g_return_if_fail (NEMO_IS_QUERY (query)); query->details->mime_types = g_list_append (query->details->mime_types, g_strdup (mime_type)); } void nemo_query_set_show_hidden (NemoQuery *query, gboolean hidden) { g_return_if_fail (NEMO_IS_QUERY (query)); query->details->show_hidden = hidden; } gboolean nemo_query_get_show_hidden (NemoQuery *query) { g_return_val_if_fail (NEMO_IS_QUERY (query), FALSE); return query->details->show_hidden; } char * nemo_query_to_readable_string (NemoQuery *query) { g_return_val_if_fail (NEMO_IS_QUERY (query), NULL); GFile *file; gchar *location_title, *readable; if (!query || !query->details->text || query->details->text[0] == '\0') { return g_strdup (_("Search")); } file = g_file_new_for_uri (query->details->location_uri); location_title = nemo_compute_search_title_for_location (file); g_object_unref (file); readable = g_strdup_printf (_("Search for \"%s\" in \"%s\""), query->details->text, location_title); g_free (location_title); return readable; } static char * encode_home_uri (const char *uri) { char *home_uri; const char *encoded_uri; home_uri = nemo_get_home_directory_uri (); if (g_str_has_prefix (uri, home_uri)) { encoded_uri = uri + strlen (home_uri); if (*encoded_uri == '/') { encoded_uri++; } } else { encoded_uri = uri; } g_free (home_uri); return g_markup_escape_text (encoded_uri, -1); } static char * decode_home_uri (const char *uri) { char *home_uri; char *decoded_uri; if (g_str_has_prefix (uri, "file:")) { decoded_uri = g_strdup (uri); } else { home_uri = nemo_get_home_directory_uri (); decoded_uri = g_strconcat (home_uri, "/", uri, NULL); g_free (home_uri); } return decoded_uri; } typedef struct { NemoQuery *query; gboolean in_text; gboolean in_location; gboolean in_mimetypes; gboolean in_mimetype; gboolean error; } ParserInfo; static void start_element_cb (GMarkupParseContext *ctx, const char *element_name, const char **attribute_names, const char **attribute_values, gpointer user_data, GError **err) { ParserInfo *info; info = (ParserInfo *) user_data; if (strcmp (element_name, "text") == 0) info->in_text = TRUE; else if (strcmp (element_name, "location") == 0) info->in_location = TRUE; else if (strcmp (element_name, "mimetypes") == 0) info->in_mimetypes = TRUE; else if (strcmp (element_name, "mimetype") == 0) info->in_mimetype = TRUE; } static void end_element_cb (GMarkupParseContext *ctx, const char *element_name, gpointer user_data, GError **err) { ParserInfo *info; info = (ParserInfo *) user_data; if (strcmp (element_name, "text") == 0) info->in_text = FALSE; else if (strcmp (element_name, "location") == 0) info->in_location = FALSE; else if (strcmp (element_name, "mimetypes") == 0) info->in_mimetypes = FALSE; else if (strcmp (element_name, "mimetype") == 0) info->in_mimetype = FALSE; } static void text_cb (GMarkupParseContext *ctx, const char *text, gsize text_len, gpointer user_data, GError **err) { ParserInfo *info; char *t, *uri; info = (ParserInfo *) user_data; t = g_strndup (text, text_len); if (info->in_text) { nemo_query_set_text (info->query, t); } else if (info->in_location) { uri = decode_home_uri (t); nemo_query_set_location (info->query, uri); g_free (uri); } else if (info->in_mimetypes && info->in_mimetype) { nemo_query_add_mime_type (info->query, t); } g_free (t); } static void error_cb (GMarkupParseContext *ctx, GError *err, gpointer user_data) { ParserInfo *info; info = (ParserInfo *) user_data; info->error = TRUE; } static GMarkupParser parser = { start_element_cb, end_element_cb, text_cb, NULL, error_cb }; static NemoQuery * nemo_query_parse_xml (char *xml, gsize xml_len) { ParserInfo info = { NULL }; GMarkupParseContext *ctx; info.query = nemo_query_new (); info.in_text = FALSE; info.error = FALSE; ctx = g_markup_parse_context_new (&parser, 0, &info, NULL); g_markup_parse_context_parse (ctx, xml, xml_len, NULL); g_markup_parse_context_free (ctx); if (info.error) { g_object_unref (info.query); return NULL; } return info.query; } NemoQuery * nemo_query_load (char *file) { NemoQuery *query; char *xml; gsize xml_len; if (!g_file_test (file, G_FILE_TEST_EXISTS)) { return NULL; } g_file_get_contents (file, &xml, &xml_len, NULL); if (xml_len == 0) { return NULL; } query = nemo_query_parse_xml (xml, xml_len); g_free (xml); return query; } static char * nemo_query_to_xml (NemoQuery *query) { GString *xml; char *text; char *uri; char *mimetype; GList *l; xml = g_string_new (""); g_string_append (xml, "\n" "\n"); text = g_markup_escape_text (query->details->text, -1); g_string_append_printf (xml, " %s\n", text); g_free (text); if (query->details->location_uri) { uri = encode_home_uri (query->details->location_uri); g_string_append_printf (xml, " %s\n", uri); g_free (uri); } if (query->details->mime_types) { g_string_append (xml, " \n"); for (l = query->details->mime_types; l != NULL; l = l->next) { mimetype = g_markup_escape_text (l->data, -1); g_string_append_printf (xml, " %s\n", mimetype); g_free (mimetype); } g_string_append (xml, " \n"); } g_string_append (xml, "\n"); return g_string_free (xml, FALSE); } gboolean nemo_query_save (NemoQuery *query, char *file) { char *xml; GError *err = NULL; gboolean res; res = TRUE; xml = nemo_query_to_xml (query); g_file_set_contents (file, xml, strlen (xml), &err); g_free (xml); if (err != NULL) { res = FALSE; g_error_free (err); } return res; } nemo-4.4.2/libnemo-private/nemo-query.h000066400000000000000000000052471357442400300200400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Novell, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Anders Carlsson * */ #ifndef NEMO_QUERY_H #define NEMO_QUERY_H #include #define NEMO_TYPE_QUERY (nemo_query_get_type ()) #define NEMO_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_QUERY, NemoQuery)) #define NEMO_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_QUERY, NemoQueryClass)) #define NEMO_IS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_QUERY)) #define NEMO_IS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_QUERY)) #define NEMO_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_QUERY, NemoQueryClass)) typedef struct NemoQueryDetails NemoQueryDetails; typedef struct NemoQuery { GObject parent; NemoQueryDetails *details; } NemoQuery; typedef struct { GObjectClass parent_class; } NemoQueryClass; GType nemo_query_get_type (void); gboolean nemo_query_enabled (void); NemoQuery* nemo_query_new (void); char * nemo_query_get_text (NemoQuery *query); void nemo_query_set_text (NemoQuery *query, const char *text); char * nemo_query_get_location (NemoQuery *query); void nemo_query_set_location (NemoQuery *query, const char *uri); GList * nemo_query_get_mime_types (NemoQuery *query); void nemo_query_set_mime_types (NemoQuery *query, GList *mime_types); void nemo_query_add_mime_type (NemoQuery *query, const char *mime_type); void nemo_query_set_show_hidden (NemoQuery *query, gboolean hidden); gboolean nemo_query_get_show_hidden (NemoQuery *query); char * nemo_query_to_readable_string (NemoQuery *query); NemoQuery *nemo_query_load (char *file); gboolean nemo_query_save (NemoQuery *query, char *file); #endif /* NEMO_QUERY_H */ nemo-4.4.2/libnemo-private/nemo-recent.c000066400000000000000000000042151357442400300201400ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2002 James Willcox * * 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, Suite 500, * Boston, MA 02110-1335, USA. */ #include "nemo-recent.h" #include #define DEFAULT_APP_EXEC "gnome-open %u" static GtkRecentManager * nemo_recent_get_manager (void) { static GtkRecentManager *manager = NULL; if (manager == NULL) { manager = gtk_recent_manager_get_default (); } return manager; } void nemo_recent_add_file (NemoFile *file, GAppInfo *application) { GtkRecentData recent_data; char *uri; uri = nemo_file_get_activation_uri (file); if (uri == NULL) { uri = nemo_file_get_uri (file); } /* do not add trash:// etc */ if (eel_uri_is_trash (uri) || eel_uri_is_search (uri) || eel_uri_is_recent (uri) || eel_uri_is_desktop (uri)) { g_free (uri); return; } recent_data.display_name = NULL; recent_data.description = NULL; recent_data.mime_type = nemo_file_get_mime_type (file); recent_data.app_name = g_strdup (g_get_application_name ()); if (application != NULL) recent_data.app_exec = g_strdup (g_app_info_get_commandline (application)); else recent_data.app_exec = g_strdup (DEFAULT_APP_EXEC); recent_data.groups = NULL; recent_data.is_private = FALSE; gtk_recent_manager_add_full (nemo_recent_get_manager (), uri, &recent_data); g_free (recent_data.mime_type); g_free (recent_data.app_name); g_free (recent_data.app_exec); g_free (uri); } nemo-4.4.2/libnemo-private/nemo-recent.h000066400000000000000000000003361357442400300201450ustar00rootroot00000000000000 #ifndef __NEMO_RECENT_H__ #define __NEMO_RECENT_H__ #include #include #include void nemo_recent_add_file (NemoFile *file, GAppInfo *application); #endif nemo-4.4.2/libnemo-private/nemo-saved-search-file.c000066400000000000000000000026351357442400300221460ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-saved-search-file.h: Subclass of NemoVFSFile to implement the the case of a Saved Search file. Copyright (C) 2005 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include #include "nemo-saved-search-file.h" #include "nemo-file-private.h" G_DEFINE_TYPE(NemoSavedSearchFile, nemo_saved_search_file, NEMO_TYPE_VFS_FILE) static void nemo_saved_search_file_init (NemoSavedSearchFile *search_file) { } static void nemo_saved_search_file_class_init (NemoSavedSearchFileClass * klass) { NemoFileClass *file_class; file_class = NEMO_FILE_CLASS (klass); file_class->default_file_type = G_FILE_TYPE_DIRECTORY; } nemo-4.4.2/libnemo-private/nemo-saved-search-file.h000066400000000000000000000040471357442400300221520ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-saved-search-file.h: Subclass of NemoVFSFile to implement the the case of a Saved Search file. Copyright (C) 2005 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_SAVED_SEARCH_FILE_H #define NEMO_SAVED_SEARCH_FILE_H #include #define NEMO_TYPE_SAVED_SEARCH_FILE nemo_saved_search_file_get_type() #define NEMO_SAVED_SEARCH_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SAVED_SEARCH_FILE, NemoSavedSearchFile)) #define NEMO_SAVED_SEARCH_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SAVED_SEARCH_FILE, NemoSavedSearchFileClass)) #define NEMO_IS_SAVED_SEARCH_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SAVED_SEARCH_FILE)) #define NEMO_IS_SAVED_SEARCH_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SAVED_SEARCH_FILE)) #define NEMO_SAVED_SEARCH_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SAVED_SEARCH_FILE, NemoSavedSearchFileClass)) typedef struct NemoSavedSearchFileDetails NemoSavedSearchFileDetails; typedef struct { NemoFile parent_slot; } NemoSavedSearchFile; typedef struct { NemoFileClass parent_slot; } NemoSavedSearchFileClass; GType nemo_saved_search_file_get_type (void); #endif /* NEMO_SAVED_SEARCH_FILE_H */ nemo-4.4.2/libnemo-private/nemo-search-directory-file.c000066400000000000000000000147501357442400300230510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-search-directory-file.c: Subclass of NemoFile to help implement the searches Copyright (C) 2005 Novell, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Anders Carlsson */ #include #include "nemo-search-directory-file.h" #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-file-attributes.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include #include "nemo-search-directory.h" #include #include #include struct NemoSearchDirectoryFileDetails { NemoSearchDirectory *search_directory; }; G_DEFINE_TYPE(NemoSearchDirectoryFile, nemo_search_directory_file, NEMO_TYPE_FILE); static void search_directory_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes) { /* No need for monitoring, we always emit changed when files are added/removed, and no other metadata changes */ /* Update display name, in case this didn't happen yet */ nemo_search_directory_file_update_display_name (NEMO_SEARCH_DIRECTORY_FILE (file)); } static void search_directory_file_monitor_remove (NemoFile *file, gconstpointer client) { /* Do nothing here, we don't have any monitors */ } static void search_directory_file_call_when_ready (NemoFile *file, NemoFileAttributes file_attributes, NemoFileCallback callback, gpointer callback_data) { /* Update display name, in case this didn't happen yet */ nemo_search_directory_file_update_display_name (NEMO_SEARCH_DIRECTORY_FILE (file)); /* All data for directory-as-file is always uptodate */ (* callback) (file, callback_data); } static void search_directory_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data) { /* Do nothing here, we don't have any pending calls */ } static gboolean search_directory_file_check_if_ready (NemoFile *file, NemoFileAttributes attributes) { return TRUE; } static gboolean search_directory_file_get_item_count (NemoFile *file, guint *count, gboolean *count_unreadable) { GList *file_list; if (count) { file_list = nemo_directory_get_file_list (file->details->directory); *count = g_list_length (file_list); nemo_file_list_free (file_list); } return TRUE; } static NemoRequestStatus search_directory_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size) { NemoFile *dir_file; GList *file_list, *l; guint dirs, files; GFileType type; file_list = nemo_directory_get_file_list (file->details->directory); dirs = files = 0; for (l = file_list; l != NULL; l = l->next) { dir_file = NEMO_FILE (l->data); type = nemo_file_get_file_type (dir_file); if (type == G_FILE_TYPE_DIRECTORY) { dirs++; } else { files++; } } if (directory_count != NULL) { *directory_count = dirs; } if (file_count != NULL) { *file_count = files; } if (unreadable_directory_count != NULL) { *unreadable_directory_count = 0; } if (total_size != NULL) { /* FIXME: Maybe we want to calculate this? */ *total_size = 0; } if (hidden_count != NULL) { *hidden_count = 0; } nemo_file_list_free (file_list); return NEMO_REQUEST_DONE; } static char * search_directory_file_get_where_string (NemoFile *file) { return g_strdup (_("Search")); } void nemo_search_directory_file_update_display_name (NemoSearchDirectoryFile *search_file) { NemoFile *file; NemoSearchDirectory *search_dir; NemoQuery *query; char *display_name; gboolean changed; display_name = NULL; file = NEMO_FILE (search_file); if (file->details->directory) { search_dir = NEMO_SEARCH_DIRECTORY (file->details->directory); query = nemo_search_directory_get_query (search_dir); if (query != NULL) { display_name = nemo_query_to_readable_string (query); g_object_unref (query); } } if (display_name == NULL) { display_name = g_strdup (_("Search")); } changed = nemo_file_set_display_name (file, display_name, NULL, TRUE); if (changed) { nemo_file_emit_changed (file); } g_free (display_name); } static void nemo_search_directory_file_init (NemoSearchDirectoryFile *search_file) { NemoFile *file; file = NEMO_FILE (search_file); file->details->got_file_info = TRUE; file->details->mime_type = eel_ref_str_get_unique ("x-directory/normal"); file->details->type = G_FILE_TYPE_DIRECTORY; file->details->size = 0; file->details->file_info_is_up_to_date = TRUE; file->details->custom_icon = NULL; file->details->activation_uri = NULL; file->details->got_link_info = TRUE; file->details->link_info_is_up_to_date = TRUE; file->details->directory_count = 0; file->details->got_directory_count = TRUE; file->details->directory_count_is_up_to_date = TRUE; nemo_file_set_display_name (file, _("Search"), NULL, TRUE); } static void nemo_search_directory_file_class_init (NemoSearchDirectoryFileClass *klass) { NemoFileClass *file_class; file_class = NEMO_FILE_CLASS (klass); file_class->default_file_type = G_FILE_TYPE_DIRECTORY; file_class->monitor_add = search_directory_file_monitor_add; file_class->monitor_remove = search_directory_file_monitor_remove; file_class->call_when_ready = search_directory_file_call_when_ready; file_class->cancel_call_when_ready = search_directory_file_cancel_call_when_ready; file_class->check_if_ready = search_directory_file_check_if_ready; file_class->get_item_count = search_directory_file_get_item_count; file_class->get_deep_counts = search_directory_file_get_deep_counts; file_class->get_where_string = search_directory_file_get_where_string; } nemo-4.4.2/libnemo-private/nemo-search-directory-file.h000066400000000000000000000044341357442400300230540ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-search-directory-file.h: Subclass of NemoFile to implement the the case of the search directory Copyright (C) 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_SEARCH_DIRECTORY_FILE_H #define NEMO_SEARCH_DIRECTORY_FILE_H #include #define NEMO_TYPE_SEARCH_DIRECTORY_FILE nemo_search_directory_file_get_type() #define NEMO_SEARCH_DIRECTORY_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SEARCH_DIRECTORY_FILE, NemoSearchDirectoryFile)) #define NEMO_SEARCH_DIRECTORY_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SEARCH_DIRECTORY_FILE, NemoSearchDirectoryFileClass)) #define NEMO_IS_SEARCH_DIRECTORY_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SEARCH_DIRECTORY_FILE)) #define NEMO_IS_SEARCH_DIRECTORY_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SEARCH_DIRECTORY_FILE)) #define NEMO_SEARCH_DIRECTORY_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SEARCH_DIRECTORY_FILE, NemoSearchDirectoryFileClass)) typedef struct NemoSearchDirectoryFileDetails NemoSearchDirectoryFileDetails; typedef struct { NemoFile parent_slot; NemoSearchDirectoryFileDetails *details; } NemoSearchDirectoryFile; typedef struct { NemoFileClass parent_slot; } NemoSearchDirectoryFileClass; GType nemo_search_directory_file_get_type (void); void nemo_search_directory_file_update_display_name (NemoSearchDirectoryFile *search_file); #endif /* NEMO_SEARCH_DIRECTORY_FILE_H */ nemo-4.4.2/libnemo-private/nemo-search-directory.c000066400000000000000000000553231357442400300221350ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Copyright (C) 2005 Novell, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Anders Carlsson */ #include #include "nemo-search-directory.h" #include "nemo-search-directory-file.h" #include "nemo-directory-private.h" #include "nemo-file.h" #include "nemo-file-private.h" #include "nemo-file-utilities.h" #include "nemo-global-preferences.h" #include "nemo-search-engine.h" #include #include #include #include #include struct NemoSearchDirectoryDetails { NemoQuery *query; char *saved_search_uri; gboolean modified; NemoSearchEngine *engine; gboolean search_running; gboolean search_finished; GList *files; GHashTable *file_hash; GList *monitor_list; GList *callback_list; GList *pending_callback_list; }; typedef struct { gboolean monitor_hidden_files; NemoFileAttributes monitor_attributes; gconstpointer client; } SearchMonitor; typedef struct { NemoSearchDirectory *search_directory; NemoDirectoryCallback callback; gpointer callback_data; NemoFileAttributes wait_for_attributes; gboolean wait_for_file_list; GList *file_list; GHashTable *non_ready_hash; } SearchCallback; G_DEFINE_TYPE (NemoSearchDirectory, nemo_search_directory, NEMO_TYPE_DIRECTORY); static void search_engine_hits_added (NemoSearchEngine *engine, GList *hits, NemoSearchDirectory *search); static void search_engine_hits_subtracted (NemoSearchEngine *engine, GList *hits, NemoSearchDirectory *search); static void search_engine_finished (NemoSearchEngine *engine, NemoSearchDirectory *search); static void search_engine_error (NemoSearchEngine *engine, const char *error, NemoSearchDirectory *search); static void search_callback_file_ready_callback (NemoFile *file, gpointer data); static void file_changed (NemoFile *file, NemoSearchDirectory *search); static void ensure_search_engine (NemoSearchDirectory *search) { if (!search->details->engine) { search->details->engine = nemo_search_engine_new (); g_signal_connect (search->details->engine, "hits-added", G_CALLBACK (search_engine_hits_added), search); g_signal_connect (search->details->engine, "hits-subtracted", G_CALLBACK (search_engine_hits_subtracted), search); g_signal_connect (search->details->engine, "finished", G_CALLBACK (search_engine_finished), search); g_signal_connect (search->details->engine, "error", G_CALLBACK (search_engine_error), search); } } static void reset_file_list (NemoSearchDirectory *search) { GList *list, *monitor_list; NemoFile *file; SearchMonitor *monitor; /* Remove file connections */ for (list = search->details->files; list != NULL; list = list->next) { file = list->data; /* Disconnect change handler */ g_signal_handlers_disconnect_by_func (file, file_changed, search); /* Remove monitors */ for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next) { monitor = monitor_list->data; nemo_file_monitor_remove (file, monitor); } } nemo_file_list_free (search->details->files); search->details->files = NULL; } static void start_or_stop_search_engine (NemoSearchDirectory *search, gboolean adding) { if (adding && (search->details->monitor_list || search->details->pending_callback_list) && search->details->query && !search->details->search_running) { /* We need to start the search engine */ search->details->search_running = TRUE; search->details->search_finished = FALSE; ensure_search_engine (search); nemo_query_set_show_hidden (search->details->query, g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES)); nemo_search_engine_set_query (search->details->engine, search->details->query); reset_file_list (search); nemo_search_engine_start (search->details->engine); } else if (!adding && (!search->details->monitor_list || !search->details->pending_callback_list) && search->details->engine && search->details->search_running) { search->details->search_running = FALSE; nemo_search_engine_stop (search->details->engine); reset_file_list (search); } } static void file_changed (NemoFile *file, NemoSearchDirectory *search) { GList list; list.data = file; list.next = NULL; nemo_directory_emit_files_changed (NEMO_DIRECTORY (search), &list); } static void search_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { GList *list; SearchMonitor *monitor; NemoSearchDirectory *search; NemoFile *file; search = NEMO_SEARCH_DIRECTORY (directory); monitor = g_new0 (SearchMonitor, 1); monitor->monitor_hidden_files = monitor_hidden_files; monitor->monitor_attributes = file_attributes; monitor->client = client; search->details->monitor_list = g_list_prepend (search->details->monitor_list, monitor); if (callback != NULL) { (* callback) (directory, search->details->files, callback_data); } for (list = search->details->files; list != NULL; list = list->next) { file = list->data; /* Add monitors */ nemo_file_monitor_add (file, monitor, file_attributes); } start_or_stop_search_engine (search, TRUE); } static void search_monitor_remove_file_monitors (SearchMonitor *monitor, NemoSearchDirectory *search) { GList *list; NemoFile *file; for (list = search->details->files; list != NULL; list = list->next) { file = list->data; nemo_file_monitor_remove (file, monitor); } } static void search_monitor_destroy (SearchMonitor *monitor, NemoSearchDirectory *search) { search_monitor_remove_file_monitors (monitor, search); g_free (monitor); } static void search_monitor_remove (NemoDirectory *directory, gconstpointer client) { NemoSearchDirectory *search; SearchMonitor *monitor; GList *list; search = NEMO_SEARCH_DIRECTORY (directory); for (list = search->details->monitor_list; list != NULL; list = list->next) { monitor = list->data; if (monitor->client == client) { search->details->monitor_list = g_list_delete_link (search->details->monitor_list, list); search_monitor_destroy (monitor, search); break; } } start_or_stop_search_engine (search, FALSE); } static void cancel_call_when_ready (gpointer key, gpointer value, gpointer user_data) { SearchCallback *search_callback; NemoFile *file; file = key; search_callback = user_data; nemo_file_cancel_call_when_ready (file, search_callback_file_ready_callback, search_callback); } static void search_callback_destroy (SearchCallback *search_callback) { if (search_callback->non_ready_hash) { g_hash_table_foreach (search_callback->non_ready_hash, cancel_call_when_ready, search_callback); g_hash_table_destroy (search_callback->non_ready_hash); } nemo_file_list_free (search_callback->file_list); g_free (search_callback); } static void search_callback_invoke_and_destroy (SearchCallback *search_callback) { search_callback->callback (NEMO_DIRECTORY (search_callback->search_directory), search_callback->file_list, search_callback->callback_data); search_callback->search_directory->details->callback_list = g_list_remove (search_callback->search_directory->details->callback_list, search_callback); search_callback_destroy (search_callback); } static void search_callback_file_ready_callback (NemoFile *file, gpointer data) { SearchCallback *search_callback = data; g_hash_table_remove (search_callback->non_ready_hash, file); if (g_hash_table_size (search_callback->non_ready_hash) == 0) { search_callback_invoke_and_destroy (search_callback); } } static void search_callback_add_file_callbacks (SearchCallback *callback) { GList *file_list_copy, *list; NemoFile *file; file_list_copy = g_list_copy (callback->file_list); for (list = file_list_copy; list != NULL; list = list->next) { file = list->data; nemo_file_call_when_ready (file, callback->wait_for_attributes, search_callback_file_ready_callback, callback); } g_list_free (file_list_copy); } static SearchCallback * search_callback_find (NemoSearchDirectory *search, NemoDirectoryCallback callback, gpointer callback_data) { SearchCallback *search_callback; GList *list; for (list = search->details->callback_list; list != NULL; list = list->next) { search_callback = list->data; if (search_callback->callback == callback && search_callback->callback_data == callback_data) { return search_callback; } } return NULL; } static SearchCallback * search_callback_find_pending (NemoSearchDirectory *search, NemoDirectoryCallback callback, gpointer callback_data) { SearchCallback *search_callback; GList *list; for (list = search->details->pending_callback_list; list != NULL; list = list->next) { search_callback = list->data; if (search_callback->callback == callback && search_callback->callback_data == callback_data) { return search_callback; } } return NULL; } static GHashTable * file_list_to_hash_table (GList *file_list) { GList *list; GHashTable *table; if (!file_list) return NULL; table = g_hash_table_new (NULL, NULL); for (list = file_list; list != NULL; list = list->next) { g_hash_table_insert (table, list->data, list->data); } return table; } static void search_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback callback, gpointer callback_data) { NemoSearchDirectory *search; SearchCallback *search_callback; search = NEMO_SEARCH_DIRECTORY (directory); search_callback = search_callback_find (search, callback, callback_data); if (search_callback == NULL) { search_callback = search_callback_find_pending (search, callback, callback_data); } if (search_callback) { g_warning ("tried to add a new callback while an old one was pending"); return; } search_callback = g_new0 (SearchCallback, 1); search_callback->search_directory = search; search_callback->callback = callback; search_callback->callback_data = callback_data; search_callback->wait_for_attributes = file_attributes; search_callback->wait_for_file_list = wait_for_file_list; if (wait_for_file_list && !search->details->search_finished) { /* Add it to the pending callback list, which will be * processed when the directory has finished loading */ search->details->pending_callback_list = g_list_prepend (search->details->pending_callback_list, search_callback); /* We might need to start the search engine */ start_or_stop_search_engine (search, TRUE); } else { search_callback->file_list = nemo_file_list_copy (search->details->files); search_callback->non_ready_hash = file_list_to_hash_table (search->details->files); if (!search_callback->non_ready_hash) { /* If there are no ready files, we invoke the callback with an empty list. */ search_callback_invoke_and_destroy (search_callback); } else { search->details->callback_list = g_list_prepend (search->details->callback_list, search_callback); search_callback_add_file_callbacks (search_callback); } } } static void search_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data) { NemoSearchDirectory *search; SearchCallback *search_callback; search = NEMO_SEARCH_DIRECTORY (directory); search_callback = search_callback_find (search, callback, callback_data); if (search_callback) { search->details->callback_list = g_list_remove (search->details->callback_list, search_callback); search_callback_destroy (search_callback); return; } /* Check for a pending callback */ search_callback = search_callback_find_pending (search, callback, callback_data); if (search_callback) { search->details->pending_callback_list = g_list_remove (search->details->pending_callback_list, search_callback); search_callback_destroy (search_callback); /* We might need to stop the search engine now */ start_or_stop_search_engine (search, FALSE); } } static void search_engine_hits_added (NemoSearchEngine *engine, GList *hits, NemoSearchDirectory *search) { GList *hit_list; GList *file_list; NemoFile *file; char *uri; SearchMonitor *monitor; GList *monitor_list; file_list = NULL; for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) { uri = hit_list->data; if (g_str_has_suffix (uri, NEMO_SAVED_SEARCH_EXTENSION)) { /* Never return saved searches themselves as hits */ continue; } file = nemo_file_get_by_uri (uri); for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next) { monitor = monitor_list->data; /* Add monitors */ nemo_file_monitor_add (file, monitor, monitor->monitor_attributes); } g_signal_connect (file, "changed", G_CALLBACK (file_changed), search), file_list = g_list_prepend (file_list, file); } search->details->files = g_list_concat (search->details->files, file_list); nemo_directory_emit_files_added (NEMO_DIRECTORY (search), file_list); file = nemo_directory_get_corresponding_file (NEMO_DIRECTORY (search)); nemo_file_emit_changed (file); nemo_file_unref (file); } static void search_engine_hits_subtracted (NemoSearchEngine *engine, GList *hits, NemoSearchDirectory *search) { GList *hit_list; GList *monitor_list; SearchMonitor *monitor; GList *file_list; char *uri; NemoFile *file; file_list = NULL; for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) { uri = hit_list->data; file = nemo_file_get_by_uri (uri); for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next) { monitor = monitor_list->data; /* Remove monitors */ nemo_file_monitor_remove (file, monitor); } g_signal_handlers_disconnect_by_func (file, file_changed, search); search->details->files = g_list_remove (search->details->files, file); file_list = g_list_prepend (file_list, file); } nemo_directory_emit_files_changed (NEMO_DIRECTORY (search), file_list); nemo_file_list_free (file_list); file = nemo_directory_get_corresponding_file (NEMO_DIRECTORY (search)); nemo_file_emit_changed (file); nemo_file_unref (file); } static void search_callback_add_pending_file_callbacks (SearchCallback *callback) { callback->file_list = nemo_file_list_copy (callback->search_directory->details->files); callback->non_ready_hash = file_list_to_hash_table (callback->search_directory->details->files); search_callback_add_file_callbacks (callback); } static void search_engine_error (NemoSearchEngine *engine, const char *error_message, NemoSearchDirectory *search) { GError *error; error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, error_message); nemo_directory_emit_load_error (NEMO_DIRECTORY (search), error); g_error_free (error); } static void search_engine_finished (NemoSearchEngine *engine, NemoSearchDirectory *search) { search->details->search_finished = TRUE; nemo_directory_emit_done_loading (NEMO_DIRECTORY (search)); /* Add all file callbacks */ g_list_foreach (search->details->pending_callback_list, (GFunc)search_callback_add_pending_file_callbacks, NULL); search->details->callback_list = g_list_concat (search->details->callback_list, search->details->pending_callback_list); g_list_free (search->details->pending_callback_list); search->details->pending_callback_list = NULL; } static void search_force_reload (NemoDirectory *directory) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (directory); if (!search->details->query) { return; } search->details->search_finished = FALSE; if (!search->details->engine) { return; } /* Remove file monitors */ reset_file_list (search); if (search->details->search_running) { nemo_search_engine_stop (search->details->engine); nemo_query_set_show_hidden (search->details->query, g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES)); nemo_search_engine_set_query (search->details->engine, search->details->query); nemo_search_engine_start (search->details->engine); } } static gboolean search_are_all_files_seen (NemoDirectory *directory) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (directory); return (!search->details->query || search->details->search_finished); } static gboolean search_is_not_empty (NemoDirectory *directory) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (directory); return search->details->files != NULL; } static gboolean search_contains_file (NemoDirectory *directory, NemoFile *file) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (directory); /* FIXME: Maybe put the files in a hash */ return (g_list_find (search->details->files, file) != NULL); } static GList * search_get_file_list (NemoDirectory *directory) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (directory); return nemo_file_list_copy (search->details->files); } static gboolean search_is_editable (NemoDirectory *directory) { return FALSE; } static void search_dispose (GObject *object) { NemoSearchDirectory *search; GList *list; search = NEMO_SEARCH_DIRECTORY (object); /* Remove search monitors */ if (search->details->monitor_list) { for (list = search->details->monitor_list; list != NULL; list = list->next) { search_monitor_destroy ((SearchMonitor *)list->data, search); } g_list_free (search->details->monitor_list); search->details->monitor_list = NULL; } reset_file_list (search); if (search->details->callback_list) { /* Remove callbacks */ g_list_foreach (search->details->callback_list, (GFunc)search_callback_destroy, NULL); g_list_free (search->details->callback_list); search->details->callback_list = NULL; } if (search->details->pending_callback_list) { g_list_foreach (search->details->pending_callback_list, (GFunc)search_callback_destroy, NULL); g_list_free (search->details->pending_callback_list); search->details->pending_callback_list = NULL; } if (search->details->query) { g_object_unref (search->details->query); search->details->query = NULL; } if (search->details->engine) { if (search->details->search_running) { nemo_search_engine_stop (search->details->engine); } g_object_unref (search->details->engine); search->details->engine = NULL; } G_OBJECT_CLASS (nemo_search_directory_parent_class)->dispose (object); } static void search_finalize (GObject *object) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (object); g_free (search->details->saved_search_uri); g_free (search->details); G_OBJECT_CLASS (nemo_search_directory_parent_class)->finalize (object); } static void nemo_search_directory_init (NemoSearchDirectory *search) { search->details = g_new0 (NemoSearchDirectoryDetails, 1); } static void nemo_search_directory_class_init (NemoSearchDirectoryClass *class) { NemoDirectoryClass *directory_class; G_OBJECT_CLASS (class)->dispose = search_dispose; G_OBJECT_CLASS (class)->finalize = search_finalize; directory_class = NEMO_DIRECTORY_CLASS (class); directory_class->are_all_files_seen = search_are_all_files_seen; directory_class->is_not_empty = search_is_not_empty; directory_class->contains_file = search_contains_file; directory_class->force_reload = search_force_reload; directory_class->call_when_ready = search_call_when_ready; directory_class->cancel_callback = search_cancel_callback; directory_class->file_monitor_add = search_monitor_add; directory_class->file_monitor_remove = search_monitor_remove; directory_class->get_file_list = search_get_file_list; directory_class->is_editable = search_is_editable; } char * nemo_search_directory_generate_new_uri (void) { static int counter = 0; char *uri; uri = g_strdup_printf (EEL_SEARCH_URI"//%d/", counter++); return uri; } void nemo_search_directory_set_query (NemoSearchDirectory *search, NemoQuery *query) { NemoDirectory *dir; NemoFile *as_file; if (search->details->query != query) { search->details->modified = TRUE; } if (query) { g_object_ref (query); } if (search->details->query) { g_object_unref (search->details->query); } search->details->query = query; dir = NEMO_DIRECTORY (search); as_file = dir->details->as_file; if (as_file != NULL) { nemo_search_directory_file_update_display_name (NEMO_SEARCH_DIRECTORY_FILE (as_file)); } } NemoQuery * nemo_search_directory_get_query (NemoSearchDirectory *search) { if (search->details->query != NULL) { return g_object_ref (search->details->query); } return NULL; } NemoSearchDirectory * nemo_search_directory_new_from_saved_search (const char *uri) { NemoSearchDirectory *search; NemoQuery *query; char *file; search = NEMO_SEARCH_DIRECTORY (g_object_new (NEMO_TYPE_SEARCH_DIRECTORY, NULL)); search->details->saved_search_uri = g_strdup (uri); file = g_filename_from_uri (uri, NULL, NULL); if (file != NULL) { query = nemo_query_load (file); if (query != NULL) { nemo_search_directory_set_query (search, query); g_object_unref (query); } g_free (file); } else { g_warning ("Non-local saved searches not supported"); } search->details->modified = FALSE; return search; } gboolean nemo_search_directory_is_saved_search (NemoSearchDirectory *search) { return search->details->saved_search_uri != NULL; } gboolean nemo_search_directory_is_modified (NemoSearchDirectory *search) { return search->details->modified; } void nemo_search_directory_save_to_file (NemoSearchDirectory *search, const char *save_file_uri) { char *file; file = g_filename_from_uri (save_file_uri, NULL, NULL); if (file == NULL) { return; } if (search->details->query != NULL) { nemo_query_save (search->details->query, file); } g_free (file); } void nemo_search_directory_save_search (NemoSearchDirectory *search) { if (search->details->saved_search_uri == NULL) { return; } nemo_search_directory_save_to_file (search, search->details->saved_search_uri); search->details->modified = FALSE; } nemo-4.4.2/libnemo-private/nemo-search-directory.h000066400000000000000000000055421357442400300221400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-search-directory.h: Subclass of NemoDirectory to implement a virtual directory consisting of the search directory and the search icons Copyright (C) 2005 Novell, 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 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_SEARCH_DIRECTORY_H #define NEMO_SEARCH_DIRECTORY_H #include #include #define NEMO_TYPE_SEARCH_DIRECTORY nemo_search_directory_get_type() #define NEMO_SEARCH_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SEARCH_DIRECTORY, NemoSearchDirectory)) #define NEMO_SEARCH_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SEARCH_DIRECTORY, NemoSearchDirectoryClass)) #define NEMO_IS_SEARCH_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SEARCH_DIRECTORY)) #define NEMO_IS_SEARCH_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SEARCH_DIRECTORY)) #define NEMO_SEARCH_DIRECTORY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SEARCH_DIRECTORY, NemoSearchDirectoryClass)) typedef struct NemoSearchDirectoryDetails NemoSearchDirectoryDetails; typedef struct { NemoDirectory parent_slot; NemoSearchDirectoryDetails *details; } NemoSearchDirectory; typedef struct { NemoDirectoryClass parent_slot; } NemoSearchDirectoryClass; GType nemo_search_directory_get_type (void); char *nemo_search_directory_generate_new_uri (void); NemoSearchDirectory *nemo_search_directory_new_from_saved_search (const char *uri); gboolean nemo_search_directory_is_saved_search (NemoSearchDirectory *search); gboolean nemo_search_directory_is_modified (NemoSearchDirectory *search); void nemo_search_directory_save_search (NemoSearchDirectory *search); void nemo_search_directory_save_to_file (NemoSearchDirectory *search, const char *save_file_uri); NemoQuery *nemo_search_directory_get_query (NemoSearchDirectory *search); void nemo_search_directory_set_query (NemoSearchDirectory *search, NemoQuery *query); #endif /* NEMO_SEARCH_DIRECTORY_H */ nemo-4.4.2/libnemo-private/nemo-search-engine-simple.c000066400000000000000000000276771357442400300227000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Red Hat, Inc * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #include #include "nemo-search-engine-simple.h" #include #include #include #define BATCH_SIZE 500 typedef struct { NemoSearchEngineSimple *engine; GCancellable *cancellable; GList *mime_types; char **words; gboolean *word_strstr; gboolean words_and; GList *found_list; GQueue *directories; /* GFiles */ GHashTable *visited; gint n_processed_files; GList *uri_hits; gboolean show_hidden; } SearchThreadData; struct NemoSearchEngineSimpleDetails { NemoQuery *query; SearchThreadData *active_search; gboolean query_finished; }; G_DEFINE_TYPE (NemoSearchEngineSimple, nemo_search_engine_simple, NEMO_TYPE_SEARCH_ENGINE); static void finalize (GObject *object) { NemoSearchEngineSimple *simple; simple = NEMO_SEARCH_ENGINE_SIMPLE (object); if (simple->details->query) { g_object_unref (simple->details->query); simple->details->query = NULL; } G_OBJECT_CLASS (nemo_search_engine_simple_parent_class)->finalize (object); } /** * function modified taken from glib2 / gstrfuncs.c */ static gchar** strsplit_esc_n (const gchar *string, const gchar delimiter, const gchar escape, gint max_tokens, gint *n_tokens) { GSList *string_list = NULL, *slist; gchar **str_array; guint n = 0; const gchar *remainder, *s; g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (delimiter != '\0', NULL); if (max_tokens < 1) max_tokens = G_MAXINT; remainder = string; s = remainder; while (s && *s) { if (*s == delimiter) break; else if (*s == escape) { s++; if (*s == 0) break; } s++; } if (*s == 0) s = NULL; if (s) { while (--max_tokens && s) { gsize len; len = s - remainder; string_list = g_slist_prepend (string_list, g_strndup (remainder, len)); n++; remainder = s + 1; s = remainder; while (s && *s) { if (*s == delimiter) break; else if (*s == escape) { s++; if (*s == 0) break; } s++; } if (*s == 0) s = NULL; } } if (*string) { n++; string_list = g_slist_prepend (string_list, g_strdup (remainder)); } *n_tokens = n; str_array = g_new (gchar*, n + 1); str_array[n--] = NULL; for (slist = string_list; slist; slist = slist->next) str_array[n--] = slist->data; g_slist_free (string_list); return str_array; } static SearchThreadData * search_thread_data_new (NemoSearchEngineSimple *engine, NemoQuery *query) { SearchThreadData *data; char *text, *lower, *normalized, *uri; GFile *location; gint n=1, i; data = g_new0 (SearchThreadData, 1); data->show_hidden = nemo_query_get_show_hidden (query); data->engine = engine; data->directories = g_queue_new (); data->visited = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); uri = nemo_query_get_location (query); location = NULL; if (uri != NULL) { location = g_file_new_for_uri (uri); g_free (uri); } if (location == NULL) { location = g_file_new_for_path ("/"); } g_queue_push_tail (data->directories, location); text = nemo_query_get_text (query); normalized = g_utf8_normalize (text, -1, G_NORMALIZE_NFD); lower = g_utf8_strdown (normalized, -1); data->words = strsplit_esc_n (lower, ' ', '\\', -1, &n); g_free (text); g_free (lower); g_free (normalized); data->word_strstr = g_malloc(sizeof(gboolean)*n); data->words_and = TRUE; for (i = 0; data->words[i] != NULL; i++) { data->word_strstr[i]=TRUE; text = data->words[i]; while(*text!=0) { if(*text=='\\' || *text=='?' || *text=='*') { data->word_strstr[i]=FALSE; break; } text++; } if (!data->word_strstr[i]) data->words_and = FALSE; } data->mime_types = nemo_query_get_mime_types (query); data->cancellable = g_cancellable_new (); return data; } static void search_thread_data_free (SearchThreadData *data) { g_queue_foreach (data->directories, (GFunc)g_object_unref, NULL); g_queue_free (data->directories); g_hash_table_destroy (data->visited); g_object_unref (data->cancellable); g_strfreev (data->words); g_free (data->word_strstr); g_list_free_full (data->mime_types, g_free); g_list_free_full (data->uri_hits, g_free); g_free (data); } static gboolean search_thread_done_idle (gpointer user_data) { SearchThreadData *data; data = user_data; if (!g_cancellable_is_cancelled (data->cancellable)) { nemo_search_engine_finished (NEMO_SEARCH_ENGINE (data->engine)); data->engine->details->active_search = NULL; } search_thread_data_free (data); return FALSE; } typedef struct { GList *uris; SearchThreadData *thread_data; } SearchHits; static gboolean search_thread_add_hits_idle (gpointer user_data) { SearchHits *hits; hits = user_data; if (!g_cancellable_is_cancelled (hits->thread_data->cancellable)) { nemo_search_engine_hits_added (NEMO_SEARCH_ENGINE (hits->thread_data->engine), hits->uris); } g_list_free_full (hits->uris, g_free); g_free (hits); return FALSE; } static void send_batch (SearchThreadData *data) { SearchHits *hits; data->n_processed_files = 0; if (data->uri_hits) { hits = g_new (SearchHits, 1); hits->uris = data->uri_hits; hits->thread_data = data; g_idle_add (search_thread_add_hits_idle, hits); } data->uri_hits = NULL; } static gboolean strwildcardcmp(char *a, char *b) { if (*a == 0 && *b == 0) return TRUE; while(*a!=0 && *b!=0) { if(*a=='\\') { // escaped character a++; if (*a != *b) return FALSE; } else { if (*a=='*') { if(*(a+1)==0) return TRUE; if(*b==0) return FALSE; if (strwildcardcmp(a+1, b) || strwildcardcmp(a, b+1)) return TRUE; else return FALSE; } else if (*a!='?' && (*a != *b)) return FALSE; } a++; b++; } if ((*a == 0 && *b == 0) || (*a=='*' && *(a+1)==0)) return TRUE; return FALSE; } #define STD_ATTRIBUTES \ G_FILE_ATTRIBUTE_STANDARD_NAME "," \ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," \ G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," \ G_FILE_ATTRIBUTE_STANDARD_TYPE "," \ G_FILE_ATTRIBUTE_ID_FILE static void visit_directory (GFile *dir, SearchThreadData *data) { GFileEnumerator *enumerator; GFileInfo *info; GFile *child; const char *mime_type, *display_name; char *lower_name, *normalized; gboolean hit; int i; GList *l; const char *id; gboolean visited; enumerator = g_file_enumerate_children (dir, data->mime_types != NULL ? STD_ATTRIBUTES "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE : STD_ATTRIBUTES , 0, data->cancellable, NULL); if (enumerator == NULL) { return; } while ((info = g_file_enumerator_next_file (enumerator, data->cancellable, NULL)) != NULL) { if (g_file_info_get_is_hidden (info) && !data->show_hidden) { goto next; } display_name = g_file_info_get_display_name (info); if (display_name == NULL) { goto next; } normalized = g_utf8_normalize (display_name, -1, G_NORMALIZE_NFD); lower_name = g_utf8_strdown (normalized, -1); g_free (normalized); hit = data->words_and; for (i = 0; data->words[i] != NULL; i++) { if (data->word_strstr[i]) { if ((strstr (lower_name, data->words[i]) != NULL)^data->words_and) { hit = !data->words_and; break; } } else if (strwildcardcmp (data->words[i], lower_name)^data->words_and) { hit = !data->words_and; break; } } g_free (lower_name); if (hit && data->mime_types) { mime_type = g_file_info_get_content_type (info); hit = FALSE; for (l = data->mime_types; mime_type != NULL && l != NULL; l = l->next) { if (g_content_type_equals (mime_type, l->data)) { hit = TRUE; break; } } } child = g_file_get_child (dir, g_file_info_get_name (info)); if (hit) { data->uri_hits = g_list_prepend (data->uri_hits, g_file_get_uri (child)); } data->n_processed_files++; if (data->n_processed_files > BATCH_SIZE) { send_batch (data); } if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE); visited = FALSE; if (id) { if (g_hash_table_lookup_extended (data->visited, id, NULL, NULL)) { visited = TRUE; } else { g_hash_table_insert (data->visited, g_strdup (id), NULL); } } if (!visited) { g_queue_push_tail (data->directories, g_object_ref (child)); } } g_object_unref (child); next: g_object_unref (info); } g_object_unref (enumerator); } static gpointer search_thread_func (gpointer user_data) { SearchThreadData *data; GFile *dir; GFileInfo *info; const char *id; data = user_data; /* Insert id for toplevel directory into visited */ dir = g_queue_peek_head (data->directories); info = g_file_query_info (dir, G_FILE_ATTRIBUTE_ID_FILE, 0, data->cancellable, NULL); if (info) { id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE); if (id) { g_hash_table_insert (data->visited, g_strdup (id), NULL); } g_object_unref (info); } while (!g_cancellable_is_cancelled (data->cancellable) && (dir = g_queue_pop_head (data->directories)) != NULL) { visit_directory (dir, data); g_object_unref (dir); } send_batch (data); g_idle_add (search_thread_done_idle, data); return NULL; } static void nemo_search_engine_simple_start (NemoSearchEngine *engine) { NemoSearchEngineSimple *simple; SearchThreadData *data; GThread *thread; simple = NEMO_SEARCH_ENGINE_SIMPLE (engine); if (simple->details->active_search != NULL) { return; } if (simple->details->query == NULL) { return; } data = search_thread_data_new (simple, simple->details->query); thread = g_thread_new ("nemo-search-simple", search_thread_func, data); simple->details->active_search = data; g_thread_unref (thread); } static void nemo_search_engine_simple_stop (NemoSearchEngine *engine) { NemoSearchEngineSimple *simple; simple = NEMO_SEARCH_ENGINE_SIMPLE (engine); if (simple->details->active_search != NULL) { g_cancellable_cancel (simple->details->active_search->cancellable); simple->details->active_search = NULL; } } static void nemo_search_engine_simple_set_query (NemoSearchEngine *engine, NemoQuery *query) { NemoSearchEngineSimple *simple; simple = NEMO_SEARCH_ENGINE_SIMPLE (engine); if (query) { g_object_ref (query); } if (simple->details->query) { g_object_unref (simple->details->query); } simple->details->query = query; } static void nemo_search_engine_simple_class_init (NemoSearchEngineSimpleClass *class) { GObjectClass *gobject_class; NemoSearchEngineClass *engine_class; gobject_class = G_OBJECT_CLASS (class); gobject_class->finalize = finalize; engine_class = NEMO_SEARCH_ENGINE_CLASS (class); engine_class->set_query = nemo_search_engine_simple_set_query; engine_class->start = nemo_search_engine_simple_start; engine_class->stop = nemo_search_engine_simple_stop; g_type_class_add_private (class, sizeof (NemoSearchEngineSimpleDetails)); } static void nemo_search_engine_simple_init (NemoSearchEngineSimple *engine) { engine->details = G_TYPE_INSTANCE_GET_PRIVATE (engine, NEMO_TYPE_SEARCH_ENGINE_SIMPLE, NemoSearchEngineSimpleDetails); } NemoSearchEngine * nemo_search_engine_simple_new (void) { NemoSearchEngine *engine; engine = g_object_new (NEMO_TYPE_SEARCH_ENGINE_SIMPLE, NULL); return engine; } nemo-4.4.2/libnemo-private/nemo-search-engine-simple.h000066400000000000000000000042571357442400300226720ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Red Hat, Inc * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #ifndef NEMO_SEARCH_ENGINE_SIMPLE_H #define NEMO_SEARCH_ENGINE_SIMPLE_H #include #define NEMO_TYPE_SEARCH_ENGINE_SIMPLE (nemo_search_engine_simple_get_type ()) #define NEMO_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SEARCH_ENGINE_SIMPLE, NemoSearchEngineSimple)) #define NEMO_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SEARCH_ENGINE_SIMPLE, NemoSearchEngineSimpleClass)) #define NEMO_IS_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SEARCH_ENGINE_SIMPLE)) #define NEMO_IS_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SEARCH_ENGINE_SIMPLE)) #define NEMO_SEARCH_ENGINE_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SEARCH_ENGINE_SIMPLE, NemoSearchEngineSimpleClass)) typedef struct NemoSearchEngineSimpleDetails NemoSearchEngineSimpleDetails; typedef struct NemoSearchEngineSimple { NemoSearchEngine parent; NemoSearchEngineSimpleDetails *details; } NemoSearchEngineSimple; typedef struct { NemoSearchEngineClass parent_class; } NemoSearchEngineSimpleClass; GType nemo_search_engine_simple_get_type (void); NemoSearchEngine* nemo_search_engine_simple_new (void); #endif /* NEMO_SEARCH_ENGINE_SIMPLE_H */ nemo-4.4.2/libnemo-private/nemo-search-engine.c000066400000000000000000000103731357442400300213720ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Novell, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Anders Carlsson * */ #include #include "nemo-search-engine.h" #include "nemo-search-engine-simple.h" enum { HITS_ADDED, HITS_SUBTRACTED, FINISHED, ERROR, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_ABSTRACT_TYPE (NemoSearchEngine, nemo_search_engine, G_TYPE_OBJECT); static void nemo_search_engine_class_init (NemoSearchEngineClass *class) { signals[HITS_ADDED] = g_signal_new ("hits-added", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoSearchEngineClass, hits_added), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[HITS_SUBTRACTED] = g_signal_new ("hits-subtracted", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoSearchEngineClass, hits_subtracted), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[FINISHED] = g_signal_new ("finished", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoSearchEngineClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[ERROR] = g_signal_new ("error", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoSearchEngineClass, error), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } static void nemo_search_engine_init (NemoSearchEngine *engine) { } NemoSearchEngine * nemo_search_engine_new (void) { NemoSearchEngine *engine; engine = nemo_search_engine_simple_new (); return engine; } void nemo_search_engine_set_query (NemoSearchEngine *engine, NemoQuery *query) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_return_if_fail (NEMO_SEARCH_ENGINE_GET_CLASS (engine)->set_query != NULL); NEMO_SEARCH_ENGINE_GET_CLASS (engine)->set_query (engine, query); } void nemo_search_engine_start (NemoSearchEngine *engine) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_return_if_fail (NEMO_SEARCH_ENGINE_GET_CLASS (engine)->start != NULL); NEMO_SEARCH_ENGINE_GET_CLASS (engine)->start (engine); } void nemo_search_engine_stop (NemoSearchEngine *engine) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_return_if_fail (NEMO_SEARCH_ENGINE_GET_CLASS (engine)->stop != NULL); NEMO_SEARCH_ENGINE_GET_CLASS (engine)->stop (engine); } void nemo_search_engine_hits_added (NemoSearchEngine *engine, GList *hits) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_signal_emit (engine, signals[HITS_ADDED], 0, hits); } void nemo_search_engine_hits_subtracted (NemoSearchEngine *engine, GList *hits) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_signal_emit (engine, signals[HITS_SUBTRACTED], 0, hits); } void nemo_search_engine_finished (NemoSearchEngine *engine) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_signal_emit (engine, signals[FINISHED], 0); } void nemo_search_engine_error (NemoSearchEngine *engine, const char *error_message) { g_return_if_fail (NEMO_IS_SEARCH_ENGINE (engine)); g_signal_emit (engine, signals[ERROR], 0, error_message); } nemo-4.4.2/libnemo-private/nemo-search-engine.h000066400000000000000000000060061357442400300213750ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Novell, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Anders Carlsson * */ #ifndef NEMO_SEARCH_ENGINE_H #define NEMO_SEARCH_ENGINE_H #include #include #define NEMO_TYPE_SEARCH_ENGINE (nemo_search_engine_get_type ()) #define NEMO_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SEARCH_ENGINE, NemoSearchEngine)) #define NEMO_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SEARCH_ENGINE, NemoSearchEngineClass)) #define NEMO_IS_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SEARCH_ENGINE)) #define NEMO_IS_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SEARCH_ENGINE)) #define NEMO_SEARCH_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SEARCH_ENGINE, NemoSearchEngineClass)) typedef struct NemoSearchEngineDetails NemoSearchEngineDetails; typedef struct NemoSearchEngine { GObject parent; NemoSearchEngineDetails *details; } NemoSearchEngine; typedef struct { GObjectClass parent_class; /* VTable */ void (*set_query) (NemoSearchEngine *engine, NemoQuery *query); void (*start) (NemoSearchEngine *engine); void (*stop) (NemoSearchEngine *engine); /* Signals */ void (*hits_added) (NemoSearchEngine *engine, GList *hits); void (*hits_subtracted) (NemoSearchEngine *engine, GList *hits); void (*finished) (NemoSearchEngine *engine); void (*error) (NemoSearchEngine *engine, const char *error_message); } NemoSearchEngineClass; GType nemo_search_engine_get_type (void); gboolean nemo_search_engine_enabled (void); NemoSearchEngine* nemo_search_engine_new (void); void nemo_search_engine_set_query (NemoSearchEngine *engine, NemoQuery *query); void nemo_search_engine_start (NemoSearchEngine *engine); void nemo_search_engine_stop (NemoSearchEngine *engine); void nemo_search_engine_hits_added (NemoSearchEngine *engine, GList *hits); void nemo_search_engine_hits_subtracted (NemoSearchEngine *engine, GList *hits); void nemo_search_engine_finished (NemoSearchEngine *engine); void nemo_search_engine_error (NemoSearchEngine *engine, const char *error_message); #endif /* NEMO_SEARCH_ENGINE_H */ nemo-4.4.2/libnemo-private/nemo-selection-canvas-item.c000066400000000000000000000405161357442400300230560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Canvas item for floating selection. * * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Federico Mena * Cosimo Cecchi */ #include #include "nemo-selection-canvas-item.h" #include enum { PROP_X1 = 1, PROP_Y1, PROP_X2, PROP_Y2, PROP_FILL_COLOR_RGBA, PROP_OUTLINE_COLOR_RGBA, PROP_OUTLINE_STIPPLING, PROP_WIDTH_PIXELS, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL }; typedef struct { /*< public >*/ int x0, y0, x1, y1; } Rect; struct _NemoSelectionCanvasItemDetails { Rect last_update_rect; Rect last_outline_update_rect; int last_outline_update_width; double x1, y1, x2, y2; /* Corners of item */ double width; /* Outline width */ GdkRGBA fill_color; GdkRGBA outline_color; gboolean outline_stippling; /* Configuration flags */ unsigned int fill_set : 1; /* Is fill color set? */ unsigned int outline_set : 1; /* Is outline color set? */ double fade_out_fill_alpha; double fade_out_outline_alpha; double fade_out_fill_delta; double fade_out_outline_delta; guint fade_out_handler_id; }; G_DEFINE_TYPE (NemoSelectionCanvasItem, nemo_selection_canvas_item, EEL_TYPE_CANVAS_ITEM); #define DASH_ON 0.8 #define DASH_OFF 1.7 static void nemo_selection_canvas_item_draw (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region) { NemoSelectionCanvasItem *self; double x1, y1, x2, y2; int cx1, cy1, cx2, cy2; double i2w_dx, i2w_dy; self = NEMO_SELECTION_CANVAS_ITEM (item); /* Get canvas pixel coordinates */ i2w_dx = 0.0; i2w_dy = 0.0; eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy); x1 = self->priv->x1 + i2w_dx; y1 = self->priv->y1 + i2w_dy; x2 = self->priv->x2 + i2w_dx; y2 = self->priv->y2 + i2w_dy; eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); if (cx2 <= cx1 || cy2 <= cy1 ) { return; } cairo_save (cr); if (self->priv->fill_set) { GdkRGBA actual_fill; actual_fill = self->priv->fill_color; if (self->priv->fade_out_handler_id != 0) { actual_fill.alpha = self->priv->fade_out_fill_alpha; } gdk_cairo_set_source_rgba (cr, &actual_fill); cairo_rectangle (cr, cx1, cy1, cx2 - cx1 + 1, cy2 - cy1 + 1); cairo_fill (cr); } if (self->priv->outline_set) { GdkRGBA actual_outline; actual_outline = self->priv->outline_color; if (self->priv->fade_out_handler_id != 0) { actual_outline.alpha = self->priv->fade_out_outline_alpha; } gdk_cairo_set_source_rgba (cr, &actual_outline); cairo_set_line_width (cr, (int) self->priv->width); if (self->priv->outline_stippling) { double dash[2] = { DASH_ON, DASH_OFF }; cairo_set_dash (cr, dash, G_N_ELEMENTS (dash), 0); } cairo_rectangle (cr, cx1 + 0.5, cy1 + 0.5, cx2 - cx1, cy2 - cy1); cairo_stroke (cr); } cairo_restore (cr); } static double nemo_selection_canvas_item_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) { NemoSelectionCanvasItem *self; double x1, y1, x2, y2; double hwidth; double dx, dy; double tmp; self = NEMO_SELECTION_CANVAS_ITEM (item); *actual_item = item; /* Find the bounds for the rectangle plus its outline width */ x1 = self->priv->x1; y1 = self->priv->y1; x2 = self->priv->x2; y2 = self->priv->y2; if (self->priv->outline_set) { hwidth = (self->priv->width / item->canvas->pixels_per_unit) / 2.0; x1 -= hwidth; y1 -= hwidth; x2 += hwidth; y2 += hwidth; } else hwidth = 0.0; /* Is point inside rectangle (which can be hollow if it has no fill set)? */ if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { if (self->priv->fill_set || !self->priv->outline_set) return 0.0; dx = x - x1; tmp = x2 - x; if (tmp < dx) dx = tmp; dy = y - y1; tmp = y2 - y; if (tmp < dy) dy = tmp; if (dy < dx) dx = dy; dx -= 2.0 * hwidth; if (dx < 0.0) return 0.0; else return dx; } /* Point is outside rectangle */ if (x < x1) dx = x1 - x; else if (x > x2) dx = x - x2; else dx = 0.0; if (y < y1) dy = y1 - y; else if (y > y2) dy = y - y2; else dy = 0.0; return sqrt (dx * dx + dy * dy); } static void request_redraw_borders (EelCanvas *canvas, Rect *update_rect, int width) { eel_canvas_request_redraw (canvas, update_rect->x0, update_rect->y0, update_rect->x1, update_rect->y0 + width); eel_canvas_request_redraw (canvas, update_rect->x0, update_rect->y1-width, update_rect->x1, update_rect->y1); eel_canvas_request_redraw (canvas, update_rect->x0, update_rect->y0, update_rect->x0+width, update_rect->y1); eel_canvas_request_redraw (canvas, update_rect->x1-width, update_rect->y0, update_rect->x1, update_rect->y1); } static Rect make_rect (int x0, int y0, int x1, int y1); static int rect_empty (const Rect *src) { return (src->x1 <= src->x0 || src->y1 <= src->y0); } static gboolean rects_intersect (Rect r1, Rect r2) { if (r1.x0 >= r2.x1) { return FALSE; } if (r2.x0 >= r1.x1) { return FALSE; } if (r1.y0 >= r2.y1) { return FALSE; } if (r2.y0 >= r1.y1) { return FALSE; } return TRUE; } static void diff_rects_guts (Rect ra, Rect rb, int *count, Rect result[4]) { if (ra.x0 < rb.x0) { result[(*count)++] = make_rect (ra.x0, ra.y0, rb.x0, ra.y1); } if (ra.y0 < rb.y0) { result[(*count)++] = make_rect (ra.x0, ra.y0, ra.x1, rb.y0); } if (ra.x1 < rb.x1) { result[(*count)++] = make_rect (ra.x1, rb.y0, rb.x1, rb.y1); } if (ra.y1 < rb.y1) { result[(*count)++] = make_rect (rb.x0, ra.y1, rb.x1, rb.y1); } } static void diff_rects (Rect r1, Rect r2, int *count, Rect result[4]) { g_assert (count != NULL); g_assert (result != NULL); *count = 0; if (rects_intersect (r1, r2)) { diff_rects_guts (r1, r2, count, result); diff_rects_guts (r2, r1, count, result); } else { if (!rect_empty (&r1)) { result[(*count)++] = r1; } if (!rect_empty (&r2)) { result[(*count)++] = r2; } } } static Rect make_rect (int x0, int y0, int x1, int y1) { Rect r; r.x0 = x0; r.y0 = y0; r.x1 = x1; r.y1 = y1; return r; } static void nemo_selection_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags) { NemoSelectionCanvasItem *self; NemoSelectionCanvasItemDetails *priv; double x1, y1, x2, y2; int cx1, cy1, cx2, cy2; int repaint_rects_count, i; int width_pixels; int width_lt, width_rb; Rect update_rect, repaint_rects[4]; if (EEL_CANVAS_ITEM_CLASS (nemo_selection_canvas_item_parent_class)->update) (* EEL_CANVAS_ITEM_CLASS (nemo_selection_canvas_item_parent_class)->update) (item, i2w_dx, i2w_dy, flags); self = NEMO_SELECTION_CANVAS_ITEM (item); priv = self->priv; x1 = priv->x1 + i2w_dx; y1 = priv->y1 + i2w_dy; x2 = priv->x2 + i2w_dx; y2 = priv->y2 + i2w_dy; eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); update_rect = make_rect (cx1, cy1, cx2+1, cy2+1); diff_rects (update_rect, priv->last_update_rect, &repaint_rects_count, repaint_rects); for (i = 0; i < repaint_rects_count; i++) { eel_canvas_request_redraw (item->canvas, repaint_rects[i].x0, repaint_rects[i].y0, repaint_rects[i].x1, repaint_rects[i].y1); } priv->last_update_rect = update_rect; if (priv->outline_set) { /* Outline and bounding box */ width_pixels = (int) priv->width; width_lt = width_pixels / 2; width_rb = (width_pixels + 1) / 2; cx1 -= width_lt; cy1 -= width_lt; cx2 += width_rb; cy2 += width_rb; update_rect = make_rect (cx1, cy1, cx2, cy2); request_redraw_borders (item->canvas, &update_rect, (width_lt + width_rb)); request_redraw_borders (item->canvas, &priv->last_outline_update_rect, priv->last_outline_update_width); priv->last_outline_update_rect = update_rect; priv->last_outline_update_width = width_lt + width_rb; item->x1 = cx1; item->y1 = cy1; item->x2 = cx2+1; item->y2 = cy2+1; } else { item->x1 = cx1; item->y1 = cy1; item->x2 = cx2+1; item->y2 = cy2+1; } } static void nemo_selection_canvas_item_translate (EelCanvasItem *item, double dx, double dy) { NemoSelectionCanvasItem *self; self = NEMO_SELECTION_CANVAS_ITEM (item); self->priv->x1 += dx; self->priv->y1 += dy; self->priv->x2 += dx; self->priv->y2 += dy; } static void nemo_selection_canvas_item_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { NemoSelectionCanvasItem *self; double hwidth; self = NEMO_SELECTION_CANVAS_ITEM (item); hwidth = (self->priv->width / item->canvas->pixels_per_unit) / 2.0; *x1 = self->priv->x1 - hwidth; *y1 = self->priv->y1 - hwidth; *x2 = self->priv->x2 + hwidth; *y2 = self->priv->y2 + hwidth; } #define FADE_OUT_STEPS 5 #define FADE_OUT_SPEED 30 static gboolean fade_and_request_redraw (gpointer user_data) { NemoSelectionCanvasItem *self = user_data; if (self->priv->fade_out_fill_alpha <= 0 || self->priv->fade_out_outline_alpha <= 0) { self->priv->fade_out_handler_id = 0; eel_canvas_item_destroy (EEL_CANVAS_ITEM (self)); return FALSE; } self->priv->fade_out_fill_alpha -= self->priv->fade_out_fill_delta; self->priv->fade_out_outline_alpha -= self->priv->fade_out_outline_delta; eel_canvas_item_request_redraw (EEL_CANVAS_ITEM (self)); return TRUE; } void nemo_selection_canvas_item_fade_out (NemoSelectionCanvasItem *self, guint transition_time) { self->priv->fade_out_fill_alpha = self->priv->fill_color.alpha; self->priv->fade_out_outline_alpha = self->priv->outline_color.alpha; self->priv->fade_out_fill_delta = self->priv->fade_out_fill_alpha / FADE_OUT_STEPS; self->priv->fade_out_outline_delta = self->priv->fade_out_outline_alpha / FADE_OUT_STEPS; self->priv->fade_out_handler_id = g_timeout_add ((guint) (transition_time / FADE_OUT_STEPS), fade_and_request_redraw, self); } static void nemo_selection_canvas_item_dispose (GObject *obj) { NemoSelectionCanvasItem *self = NEMO_SELECTION_CANVAS_ITEM (obj); if (self->priv->fade_out_handler_id != 0) { g_source_remove (self->priv->fade_out_handler_id); self->priv->fade_out_handler_id = 0; } G_OBJECT_CLASS (nemo_selection_canvas_item_parent_class)->dispose (obj); } static void do_set_fill (NemoSelectionCanvasItem *self, gboolean fill_set) { if (self->priv->fill_set != fill_set) { self->priv->fill_set = fill_set; eel_canvas_item_request_update (EEL_CANVAS_ITEM (self)); } } static void do_set_outline (NemoSelectionCanvasItem *self, gboolean outline_set) { if (self->priv->outline_set != outline_set) { self->priv->outline_set = outline_set; eel_canvas_item_request_update (EEL_CANVAS_ITEM (self)); } } static void nemo_selection_canvas_item_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { EelCanvasItem *item; NemoSelectionCanvasItem *self; self = NEMO_SELECTION_CANVAS_ITEM (object); item = EEL_CANVAS_ITEM (object); switch (param_id) { case PROP_X1: self->priv->x1 = g_value_get_double (value); eel_canvas_item_request_update (item); break; case PROP_Y1: self->priv->y1 = g_value_get_double (value); eel_canvas_item_request_update (item); break; case PROP_X2: self->priv->x2 = g_value_get_double (value); eel_canvas_item_request_update (item); break; case PROP_Y2: self->priv->y2 = g_value_get_double (value); eel_canvas_item_request_update (item); break; case PROP_FILL_COLOR_RGBA: { GdkRGBA *color; color = g_value_get_boxed (value); do_set_fill (self, color != NULL); if (color != NULL) { self->priv->fill_color = *color; } eel_canvas_item_request_redraw (item); break; } case PROP_OUTLINE_COLOR_RGBA: { GdkRGBA *color; color = g_value_get_boxed (value); do_set_outline (self, color != NULL); if (color != NULL) { self->priv->outline_color = *color; } eel_canvas_item_request_redraw (item); break; } case PROP_OUTLINE_STIPPLING: self->priv->outline_stippling = g_value_get_boolean (value); eel_canvas_item_request_redraw (item); break; case PROP_WIDTH_PIXELS: self->priv->width = g_value_get_uint (value); eel_canvas_item_request_update (item); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_selection_canvas_item_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { NemoSelectionCanvasItem *self; self = NEMO_SELECTION_CANVAS_ITEM (object); switch (param_id) { case PROP_X1: g_value_set_double (value, self->priv->x1); break; case PROP_Y1: g_value_set_double (value, self->priv->y1); break; case PROP_X2: g_value_set_double (value, self->priv->x2); break; case PROP_Y2: g_value_set_double (value, self->priv->y2); break; case PROP_FILL_COLOR_RGBA: g_value_set_boxed (value, &self->priv->fill_color); break; case PROP_OUTLINE_COLOR_RGBA: g_value_set_boxed (value, &self->priv->outline_color); break; case PROP_OUTLINE_STIPPLING: g_value_set_boolean (value, self->priv->outline_stippling); break; case PROP_WIDTH_PIXELS: g_value_set_uint (value, self->priv->width); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void nemo_selection_canvas_item_class_init (NemoSelectionCanvasItemClass *klass) { EelCanvasItemClass *item_class; GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); item_class = EEL_CANVAS_ITEM_CLASS (klass); gobject_class->set_property = nemo_selection_canvas_item_set_property; gobject_class->get_property = nemo_selection_canvas_item_get_property; gobject_class->dispose = nemo_selection_canvas_item_dispose; item_class->draw = nemo_selection_canvas_item_draw; item_class->point = nemo_selection_canvas_item_point; item_class->update = nemo_selection_canvas_item_update; item_class->bounds = nemo_selection_canvas_item_bounds; item_class->translate = nemo_selection_canvas_item_translate; properties[PROP_X1] = g_param_spec_double ("x1", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE); properties[PROP_Y1] = g_param_spec_double ("y1", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE); properties[PROP_X2] = g_param_spec_double ("x2", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE); properties[PROP_Y2] = g_param_spec_double ("y2", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE); properties[PROP_FILL_COLOR_RGBA] = g_param_spec_boxed ("fill-color-rgba", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE); properties[PROP_OUTLINE_COLOR_RGBA] = g_param_spec_boxed ("outline-color-rgba", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE); properties[PROP_OUTLINE_STIPPLING] = g_param_spec_boolean ("outline-stippling", NULL, NULL, FALSE, G_PARAM_READWRITE); properties[PROP_WIDTH_PIXELS] = g_param_spec_uint ("width-pixels", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE); g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); g_type_class_add_private (klass, sizeof (NemoSelectionCanvasItemDetails)); } static void nemo_selection_canvas_item_init (NemoSelectionCanvasItem *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_SELECTION_CANVAS_ITEM, NemoSelectionCanvasItemDetails); } nemo-4.4.2/libnemo-private/nemo-selection-canvas-item.h000066400000000000000000000051221357442400300230550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Canvas item for floating selection. * * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Federico Mena * Cosimo Cecchi */ #ifndef __NEMO_SELECTION_CANVAS_ITEM_H__ #define __NEMO_SELECTION_CANVAS_ITEM_H__ #include G_BEGIN_DECLS #define NEMO_TYPE_SELECTION_CANVAS_ITEM nemo_selection_canvas_item_get_type() #define NEMO_SELECTION_CANVAS_ITEM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SELECTION_CANVAS_ITEM, NemoSelectionCanvasItem)) #define NEMO_SELECTION_CANVAS_ITEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SELECTION_CANVAS_ITEM, NemoSelectionCanvasItemClass)) #define NEMO_IS_SELECTION_CANVAS_ITEM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SELECTION_CANVAS_ITEM)) #define NEMO_IS_SELECTION_CANVAS_ITEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SELECTION_CANVAS_ITEM)) #define NEMO_SELECTION_CANVAS_ITEM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SELECTION_CANVAS_ITEM, NemoSelectionCanvasItemClass)) typedef struct _NemoSelectionCanvasItem NemoSelectionCanvasItem; typedef struct _NemoSelectionCanvasItemClass NemoSelectionCanvasItemClass; typedef struct _NemoSelectionCanvasItemDetails NemoSelectionCanvasItemDetails; struct _NemoSelectionCanvasItem { EelCanvasItem item; NemoSelectionCanvasItemDetails *priv; gpointer user_data; }; struct _NemoSelectionCanvasItemClass { EelCanvasItemClass parent_class; }; /* GObject */ GType nemo_selection_canvas_item_get_type (void); void nemo_selection_canvas_item_fade_out (NemoSelectionCanvasItem *self, guint transition_time); G_END_DECLS #endif /* __NEMO_SELECTION_CANVAS_ITEM_H__ */ nemo-4.4.2/libnemo-private/nemo-separator-action.c000066400000000000000000000043501357442400300221330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-separator-action.h" G_DEFINE_TYPE (NemoSeparatorAction, nemo_separator_action, GTK_TYPE_ACTION); static GtkWidget *create_menu_item (GtkAction *action); static GtkWidget *create_tool_item (GtkAction *action); static gpointer parent_class; static void nemo_separator_action_init (NemoSeparatorAction *action) { } static void nemo_separator_action_class_init (NemoSeparatorActionClass *klass) { GtkActionClass *action_class = GTK_ACTION_CLASS (klass); parent_class = g_type_class_peek_parent (klass); action_class->create_menu_item = create_menu_item; action_class->create_tool_item = create_tool_item; action_class->menu_item_type = GTK_TYPE_SEPARATOR_MENU_ITEM; action_class->toolbar_item_type = GTK_TYPE_SEPARATOR_TOOL_ITEM; } GtkAction * nemo_separator_action_new (const gchar *name) { return g_object_new (NEMO_TYPE_SEPARATOR_ACTION, "name", name, NULL); } static GtkWidget * create_menu_item (GtkAction *action) { GType menu_item_type; GtkWidget *ret; menu_item_type = GTK_ACTION_GET_CLASS (action)->menu_item_type; ret = g_object_new (menu_item_type, NULL); gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (ret), FALSE); return ret; } static GtkWidget * create_tool_item (GtkAction *action) { g_warning ("NemoSeparatorAction: Toolbar items unsupported at this time."); return NULL; } nemo-4.4.2/libnemo-private/nemo-separator-action.h000066400000000000000000000037311357442400300221420ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_SEPARATOR_ACTION_H #define NEMO_SEPARATOR_ACTION_H #include #define NEMO_TYPE_SEPARATOR_ACTION nemo_separator_action_get_type() #define NEMO_SEPARATOR_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SEPARATOR_ACTION, NemoSeparatorAction)) #define NEMO_SEPARATOR_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SEPARATOR_ACTION, NemoSeparatorActionClass)) #define NEMO_IS_SEPARATOR_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SEPARATOR_ACTION)) #define NEMO_IS_SEPARATOR_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SEPARATOR_ACTION)) #define NEMO_SEPARATOR_ACTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SEPARATOR_ACTION, NemoSeparatorActionClass)) typedef struct _NemoSeparatorAction NemoSeparatorAction; typedef struct _NemoSeparatorActionClass NemoSeparatorActionClass; struct _NemoSeparatorAction { GtkAction parent; }; struct _NemoSeparatorActionClass { GtkActionClass parent_class; }; GType nemo_separator_action_get_type (void); GtkAction *nemo_separator_action_new (const gchar *name); #endif /* NEMO_SEPARATOR_ACTION_H */ nemo-4.4.2/libnemo-private/nemo-signaller.c000066400000000000000000000054711357442400300206450ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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, Suite 500, Boston, MA 02110-1335 USA * * Author: John Sullivan */ /* nemo-signaller.h: Class to manage nemo-wide signals that don't * correspond to any particular object. */ #include #include "nemo-signaller.h" #include typedef GObject NemoSignaller; typedef GObjectClass NemoSignallerClass; enum { HISTORY_LIST_CHANGED, POPUP_MENU_CHANGED, USER_DIRS_CHANGED, MIME_DATA_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static GType nemo_signaller_get_type (void); G_DEFINE_TYPE (NemoSignaller, nemo_signaller, G_TYPE_OBJECT); GObject * nemo_signaller_get_current (void) { static GObject *global_signaller = NULL; if (global_signaller == NULL) { global_signaller = g_object_new (nemo_signaller_get_type (), NULL); } return global_signaller; } static void nemo_signaller_init (NemoSignaller *signaller) { } static void nemo_signaller_class_init (NemoSignallerClass *class) { signals[HISTORY_LIST_CHANGED] = g_signal_new ("history_list_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[POPUP_MENU_CHANGED] = g_signal_new ("popup_menu_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[USER_DIRS_CHANGED] = g_signal_new ("user_dirs_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[MIME_DATA_CHANGED] = g_signal_new ("mime_data_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } nemo-4.4.2/libnemo-private/nemo-signaller.h000066400000000000000000000031771357442400300206530ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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, Suite 500, Boston, MA 02110-1335 USA * * Author: John Sullivan */ /* nemo-signaller.h: Class to manage nemo-wide signals that don't * correspond to any particular object. */ #ifndef NEMO_SIGNALLER_H #define NEMO_SIGNALLER_H #include /* NemoSignaller is a class that manages signals between disconnected Nemo code. Nemo objects connect to these signals so that other objects can cause them to be emitted later, without the connecting and emit-causing objects needing to know about each other. It seems a shame to have to invent a subclass and a special object just for this purpose. Perhaps there's a better way to do this kind of thing. */ /* Get the one and only NemoSignaller to connect with or emit signals for */ GObject *nemo_signaller_get_current (void); #endif /* NEMO_SIGNALLER_H */ nemo-4.4.2/libnemo-private/nemo-statx.c000066400000000000000000000102271357442400300200230ustar00rootroot00000000000000/* statx.c -- part of Nemo file creation date extension * * * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #define _GNU_SOURCE #define _ATFILE_SOURCE #include #include #include // for AT_FDCWD, AT_NO_AUTOMOUNT #include // for statx, STATX_BTIME, statx_timestamp #include // for memset #include // for __NR_statx #include // for syscall, ssize_t #include #include #if NATIVE_STATX /* native statx call */ static __attribute__((unused)) ssize_t statx (int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) { return syscall (__NR_statx, dfd, filename, flags, mask, buffer); } #else /* statx wrapper/compatibility */ /* this code works ony with x86 and x86_64 */ #if __x86_64__ #define __NR_statx 332 #else #define __NR_statx 383 #endif #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ struct statx_timestamp { __s64 tv_sec; __u32 tv_nsec; __s32 __reserved; }; struct statx { /* 0x00 */ __u32 stx_mask; /* What results were written [uncond] */ __u32 stx_blksize; /* Preferred general I/O size [uncond] */ __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ /* 0x10 */ __u32 stx_nlink; /* Number of hard links */ __u32 stx_uid; /* User ID of owner */ __u32 stx_gid; /* Group ID of owner */ __u16 stx_mode; /* File mode */ __u16 __spare0[1]; /* 0x20 */ __u64 stx_ino; /* Inode number */ __u64 stx_size; /* File size */ __u64 stx_blocks; /* Number of 512-byte blocks allocated */ __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ /* 0x40 */ struct statx_timestamp stx_atime; /* Last access time */ struct statx_timestamp stx_btime; /* File creation time */ struct statx_timestamp stx_ctime; /* Last attribute change time */ struct statx_timestamp stx_mtime; /* Last data modification time */ /* 0x80 */ __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ __u32 stx_rdev_minor; __u32 stx_dev_major; /* ID of device containing file [uncond] */ __u32 stx_dev_minor; /* 0x90 */ __u64 __spare2[14]; /* Spare space for future expansion */ /* 0x100 */ }; #define statx(a,b,c,d,e) syscall(__NR_statx,(a),(b),(c),(d),(e)) #endif // NATIVE_STATX time_t get_file_btime (const char *path) { static int not_implemented = 0; int flags = AT_NO_AUTOMOUNT; unsigned int mask = STATX_BTIME; struct statx stxbuf; long ret = 0; time_t btime; btime = 0; if (not_implemented) { return btime; } memset (&stxbuf, 0xbf, sizeof(stxbuf)); errno = 0; ret = statx (AT_FDCWD, path, flags, mask, &stxbuf); if (ret < 0) { if (errno == ENOSYS) { printf("nemo-creation-date: kernel needs to be (>= 4.15) - file creation dates not available\n"); not_implemented = 1; } return btime; } btime = (&stxbuf)->stx_btime.tv_sec; return btime; }nemo-4.4.2/libnemo-private/nemo-statx.h000066400000000000000000000016041357442400300200270ustar00rootroot00000000000000/* statx.h -- part of Nemo file creation date extension * * * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef NEMO_STATX_H #define NEMO_STATX_H #include time_t get_file_btime (const char *path); #endif nemo-4.4.2/libnemo-private/nemo-thumbnails.c000066400000000000000000000531741357442400300210360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-thumbnail-cache.h: Thumbnail code for icon factory. Copyright (C) 2000, 2001 Eazel, Inc. Copyright (C) 2002, 2003 Red Hat, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Andy Hertzfeld */ #include #include "nemo-thumbnails.h" #define GNOME_DESKTOP_USE_UNSTABLE_API #include "nemo-directory-notify.h" #include "nemo-global-preferences.h" #include "nemo-file-utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_THUMBNAILS #include #include "nemo-file-private.h" /* Should never be a reasonable actual mtime */ #define INVALID_MTIME 0 /* Cool-off period between last file modification time and thumbnail creation */ #define THUMBNAIL_CREATION_DELAY_SECS 3 #define NEMO_THUMBNAIL_FRAME_LEFT 3 #define NEMO_THUMBNAIL_FRAME_TOP 3 #define NEMO_THUMBNAIL_FRAME_RIGHT 3 #define NEMO_THUMBNAIL_FRAME_BOTTOM 3 /* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */ typedef struct { char *image_uri; char *mime_type; time_t original_file_mtime; gint throttle_count; } NemoThumbnailInfo; /* * Thumbnail thread state. */ /* The id of the idle handler used to start the thumbnail thread, or 0 if no idle handler is currently registered. */ static guint thumbnail_thread_starter_id = 0; /* Our mutex used when accessing data shared between the main thread and the thumbnail thread, i.e. the thumbnail_thread_is_running flag and the thumbnails_to_make list. */ static GMutex thumbnails_mutex; static GCancellable *thumbnails_cancellable; /* A flag to indicate whether a thumbnail thread is running, so we don't start more than one. Lock thumbnails_mutex when accessing this. */ static volatile gboolean thumbnail_thread_is_running = FALSE; /* The list of NemoThumbnailInfo structs containing information about the thumbnails we are making. Lock thumbnails_mutex when accessing this. */ static volatile GQueue thumbnails_to_make = G_QUEUE_INIT; /* Quickly check if uri is in thumbnails_to_make list */ static GHashTable *thumbnails_to_make_hash = NULL; /* The currently thumbnailed icon. it also exists in the thumbnails_to_make list * to avoid adding it again. Lock thumbnails_mutex when accessing this. */ static NemoThumbnailInfo *currently_thumbnailing = NULL; static GnomeDesktopThumbnailFactory *thumbnail_factory = NULL; static gboolean get_file_mtime (const char *file_uri, time_t* mtime) { GFile *file; GFileInfo *info; gboolean ret; ret = FALSE; *mtime = INVALID_MTIME; file = g_file_new_for_uri (file_uri); info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, 0, NULL, NULL); if (info) { if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED)) { *mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); ret = TRUE; } g_object_unref (info); } g_object_unref (file); return ret; } static void free_thumbnail_info (NemoThumbnailInfo *info) { g_free (info->image_uri); g_free (info->mime_type); g_free (info); } static GnomeDesktopThumbnailFactory * get_thumbnail_factory (void) { if (thumbnail_factory == NULL) { thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); } return thumbnail_factory; } static GdkPixbuf * nemo_get_thumbnail_frame (void) { static GdkPixbuf *thumbnail_frame = NULL; if (thumbnail_frame == NULL) { GInputStream *stream = g_resources_open_stream ("/org/nemo/icons/thumbnail_frame.png", 0, NULL); if (stream != NULL) { thumbnail_frame = gdk_pixbuf_new_from_stream (stream, NULL, NULL); g_object_unref (stream); } } return thumbnail_frame; } void nemo_thumbnail_frame_image (GdkPixbuf **pixbuf) { GdkPixbuf *pixbuf_with_frame, *frame; int left_offset, top_offset, right_offset, bottom_offset; /* The pixbuf isn't already framed (i.e., it was not made by * an old Nemo), so we must embed it in a frame. */ frame = nemo_get_thumbnail_frame (); if (frame == NULL) { return; } left_offset = NEMO_THUMBNAIL_FRAME_LEFT; top_offset = NEMO_THUMBNAIL_FRAME_TOP; right_offset = NEMO_THUMBNAIL_FRAME_RIGHT; bottom_offset = NEMO_THUMBNAIL_FRAME_BOTTOM; pixbuf_with_frame = eel_embed_image_in_frame (*pixbuf, frame, left_offset, top_offset, right_offset, bottom_offset); g_object_unref (*pixbuf); *pixbuf = pixbuf_with_frame; } void nemo_thumbnail_pad_top_and_bottom (GdkPixbuf **pixbuf, gint extra_height) { GdkPixbuf *pixbuf_with_padding; GdkRectangle rect; GdkRGBA transparent = { 0, 0, 0, 0.0 }; cairo_surface_t *surface; cairo_t *cr; gint width, height; width = gdk_pixbuf_get_width (*pixbuf); height = gdk_pixbuf_get_height (*pixbuf); surface = gdk_window_create_similar_image_surface (NULL, CAIRO_FORMAT_ARGB32, width, height + extra_height, 0); cr = cairo_create (surface); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height + extra_height; gdk_cairo_rectangle (cr, &rect); gdk_cairo_set_source_rgba (cr, &transparent); cairo_fill (cr); gdk_cairo_set_source_pixbuf (cr, *pixbuf, 0, extra_height / 2); cairo_paint (cr); pixbuf_with_padding = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height + extra_height); g_object_unref (*pixbuf); cairo_surface_destroy (surface); cairo_destroy (cr); *pixbuf = pixbuf_with_padding; } static GHashTable * get_types_table (void) { static GHashTable *image_mime_types = NULL; GSList *format_list, *l; char **types; int i; if (image_mime_types == NULL) { image_mime_types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); format_list = gdk_pixbuf_get_formats (); for (l = format_list; l; l = l->next) { types = gdk_pixbuf_format_get_mime_types (l->data); for (i = 0; types[i] != NULL; i++) { g_hash_table_insert (image_mime_types, types [i], GUINT_TO_POINTER (1)); } g_free (types); } g_slist_free (format_list); } return image_mime_types; } static gboolean pixbuf_can_load_type (const char *mime_type) { GHashTable *image_mime_types; image_mime_types = get_types_table (); if (g_hash_table_lookup (image_mime_types, mime_type)) { return TRUE; } return FALSE; } gboolean nemo_can_thumbnail_internally (NemoFile *file) { char *mime_type; gboolean res; mime_type = nemo_file_get_mime_type (file); res = pixbuf_can_load_type (mime_type); g_free (mime_type); return res; } gboolean nemo_thumbnail_is_mimetype_limited_by_size (const char *mime_type) { return pixbuf_can_load_type (mime_type); } gboolean nemo_can_thumbnail (NemoFile *file) { GnomeDesktopThumbnailFactory *factory; gboolean res; char *uri; time_t mtime; char *mime_type; uri = nemo_file_get_uri (file); mime_type = nemo_file_get_mime_type (file); mtime = nemo_file_get_mtime (file); factory = get_thumbnail_factory (); res = gnome_desktop_thumbnail_factory_can_thumbnail (factory, uri, mime_type, mtime); g_free (mime_type); g_free (uri); return res; } /*************************************************************************** * Thumbnail Thread Functions. ***************************************************************************/ void nemo_thumbnail_remove_from_queue (const char *file_uri) { GList *node; if (DEBUGGING) { g_message ("(Remove from queue) Locking mutex"); } g_mutex_lock (&thumbnails_mutex); /********************************* * MUTEX LOCKED *********************************/ if (thumbnails_to_make_hash) { node = g_hash_table_lookup (thumbnails_to_make_hash, file_uri); if (node && node->data != currently_thumbnailing) { g_hash_table_remove (thumbnails_to_make_hash, file_uri); free_thumbnail_info (node->data); g_queue_delete_link ((GQueue *)&thumbnails_to_make, node); } } /********************************* * MUTEX UNLOCKED *********************************/ if (DEBUGGING) { g_message ("(Remove from queue) Unlocking mutex"); } g_mutex_unlock (&thumbnails_mutex); } void nemo_thumbnail_prioritize (const char *file_uri) { GList *node; if (DEBUGGING) { g_message ("(Prioritize) Locking mutex"); } g_mutex_lock (&thumbnails_mutex); /********************************* * MUTEX LOCKED *********************************/ if (thumbnails_to_make_hash) { node = g_hash_table_lookup (thumbnails_to_make_hash, file_uri); if (node && node->data != currently_thumbnailing) { g_queue_unlink ((GQueue *)&thumbnails_to_make, node); g_queue_push_head_link ((GQueue *)&thumbnails_to_make, node); } } /********************************* * MUTEX UNLOCKED *********************************/ if (DEBUGGING) { g_message ("(Prioritize) Unlocking mutex"); } g_mutex_unlock (&thumbnails_mutex); } /* This is a one-shot idle callback called from the main loop to call notify_file_changed() for a thumbnail. It frees the uri afterwards. We do this in an idle callback as I don't think nemo_file_changed() is thread-safe. */ static gboolean thumbnail_thread_notify_file_changed (gpointer image_uri) { NemoFile *file; file = nemo_file_get_by_uri ((char *) image_uri); if (DEBUGGING) { g_message ("(Thumbnail Thread) Notifying file changed file:%p uri: %s", file, (char*) image_uri); } if (file != NULL) { nemo_file_set_is_thumbnailing (file, FALSE); nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_THUMBNAIL | NEMO_FILE_ATTRIBUTE_INFO); nemo_file_unref (file); } g_free (image_uri); return FALSE; } static void on_thumbnail_thread_finished (GObject *source, GAsyncResult *res, gpointer user_data) { GError *error; error = NULL; g_task_propagate_boolean (G_TASK (res), &error); if (error != NULL) { g_warning ("Error thumbnailing: %s", error->message); g_error_free (error); } if (DEBUGGING) { g_message ("(Main Thread) Thumbnail thread finished"); } /* Thread is no longer running, no need to lock mutex */ thumbnail_thread_is_running = FALSE; } /* thumbnail_thread is invoked as a separate thread to to make thumbnails. */ static void thumbnail_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { NemoThumbnailInfo *info = NULL; GdkPixbuf *pixbuf; time_t current_orig_mtime = 0; time_t current_time; GList *node; /* We loop until there are no more thumbails to make, at which point we exit the thread. */ for (;;) { if (DEBUGGING) { g_message ("(Thumbnail Thread) Locking mutex"); } g_mutex_lock (&thumbnails_mutex); /********************************* * MUTEX LOCKED *********************************/ /* Pop the last thumbnail we just made off the head of the list and free it. I did this here so we only have to lock the mutex once per thumbnail, rather than once before creating it and once after. Don't pop the thumbnail off the queue if the original file mtime of the request changed. Then we need to redo the thumbnail. */ if (currently_thumbnailing && currently_thumbnailing->original_file_mtime == current_orig_mtime) { g_assert (info == currently_thumbnailing); node = g_hash_table_lookup (thumbnails_to_make_hash, info->image_uri); g_assert (node != NULL); g_hash_table_remove (thumbnails_to_make_hash, info->image_uri); free_thumbnail_info (info); g_queue_delete_link ((GQueue *)&thumbnails_to_make, node); } currently_thumbnailing = NULL; /* If there are no more thumbnails to make, reset the thumbnail_thread_is_running flag, unlock the mutex, and exit the thread. */ if (g_queue_is_empty ((GQueue *)&thumbnails_to_make)) { if (DEBUGGING) { g_message ("(Thumbnail Thread) Exiting"); } g_mutex_unlock (&thumbnails_mutex); g_task_return_boolean (task, TRUE); return; } /* Get the next one to make. We leave it on the list until it is created so the main thread doesn't add it again while we are creating it. */ info = g_queue_peek_head ((GQueue *)&thumbnails_to_make); currently_thumbnailing = info; current_orig_mtime = info->original_file_mtime; /********************************* * MUTEX UNLOCKED *********************************/ if (DEBUGGING) { g_message ("(Thumbnail Thread) Unlocking mutex"); } g_mutex_unlock (&thumbnails_mutex); time (¤t_time); /* Don't try to create a thumbnail if the file was modified recently. This prevents constant re-thumbnailing of changing files. */ if (current_time < current_orig_mtime + (THUMBNAIL_CREATION_DELAY_SECS * info->throttle_count) && current_time >= current_orig_mtime) { if (DEBUGGING) { g_message ("(Thumbnail Thread) Skipping for %d seconds: %s", THUMBNAIL_CREATION_DELAY_SECS * info->throttle_count, info->image_uri); } /* Reschedule thumbnailing via a change notification */ g_timeout_add_seconds (THUMBNAIL_CREATION_DELAY_SECS * info->throttle_count, thumbnail_thread_notify_file_changed, g_strdup (info->image_uri)); continue; } /* Create the thumbnail. */ if (DEBUGGING) { g_message ("(Thumbnail Thread) Creating thumbnail: %s", info->image_uri); } pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory, info->image_uri, info->mime_type); if (pixbuf) { gnome_desktop_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, info->image_uri, current_orig_mtime); g_object_unref (pixbuf); } else { gnome_desktop_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, info->image_uri, current_orig_mtime); } /* We need to call nemo_file_changed(), but I don't think that is thread safe. So add an idle handler and do it from the main loop. */ g_idle_add_full (G_PRIORITY_HIGH_IDLE, thumbnail_thread_notify_file_changed, g_strdup (info->image_uri), NULL); } g_task_return_boolean (task, TRUE); } /* This function is added as a very low priority idle function to start the thread to create any needed thumbnails. It is added with a very low priority so that it doesn't delay showing the directory in the icon/list views. We want to show the files in the directory as quickly as possible. */ static gboolean thumbnail_thread_starter_cb (gpointer data) { GTask *thumbnail_task; /* Don't do this in thread, since g_object_ref is not threadsafe */ if (thumbnail_factory == NULL) { thumbnail_factory = get_thumbnail_factory (); } thumbnails_cancellable = g_cancellable_new (); if (DEBUGGING) { g_message ("(Main Thread) Creating thumbnails thread"); } thumbnail_task = g_task_new (thumbnail_factory, thumbnails_cancellable, on_thumbnail_thread_finished, NULL); /* We set a flag to indicate the thread is running, so we don't create a new one. We don't need to lock a mutex here, as the thumbnail thread isn't running yet. And we know we won't create the thread twice, as we also check thumbnail_thread_starter_id before scheduling this idle function. */ thumbnail_thread_is_running = TRUE; g_task_run_in_thread (thumbnail_task, thumbnail_thread); thumbnail_thread_starter_id = 0; return FALSE; } void nemo_create_thumbnail (NemoFile *file, gint throttle_count) { time_t file_mtime = 0; NemoThumbnailInfo *info; NemoThumbnailInfo *existing_info; GList *existing, *node; nemo_file_set_is_thumbnailing (file, TRUE); info = g_new0 (NemoThumbnailInfo, 1); info->image_uri = nemo_file_get_uri (file); info->mime_type = nemo_file_get_mime_type (file); info->throttle_count = MIN (10, throttle_count); /* Hopefully the NemoFile will already have the image file mtime, so we can just use that. Otherwise we have to get it ourselves. */ if (file->details->got_file_info && file->details->file_info_is_up_to_date && file->details->mtime != 0) { file_mtime = file->details->mtime; } else { get_file_mtime (info->image_uri, &file_mtime); } info->original_file_mtime = file_mtime; if (DEBUGGING) { g_message ("(Main Thread) Locking mutex"); } g_mutex_lock (&thumbnails_mutex); /********************************* * MUTEX LOCKED *********************************/ if (thumbnails_to_make_hash == NULL) { thumbnails_to_make_hash = g_hash_table_new (g_str_hash, g_str_equal); } /* Check if it is already in the list of thumbnails to make. */ existing = g_hash_table_lookup (thumbnails_to_make_hash, info->image_uri); if (existing == NULL) { /* Add the thumbnail to the list. */ if (DEBUGGING) { g_message ("(Main Thread) Adding thumbnail: %s", info->image_uri); } g_queue_push_tail ((GQueue *)&thumbnails_to_make, info); node = g_queue_peek_tail_link ((GQueue *)&thumbnails_to_make); g_hash_table_insert (thumbnails_to_make_hash, info->image_uri, node); /* If the thumbnail thread isn't running, and we haven't scheduled an idle function to start it up, do that now. We don't want to start it until all the other work is done, so the GUI will be updated as quickly as possible.*/ if (thumbnail_thread_is_running == FALSE && thumbnail_thread_starter_id == 0) { thumbnail_thread_starter_id = g_idle_add_full (G_PRIORITY_LOW, thumbnail_thread_starter_cb, NULL, NULL); } } else { if (DEBUGGING) { g_message ("(Main Thread) Updating non-current mtime: %s", info->image_uri); } /* The file in the queue might need a new original mtime */ existing_info = existing->data; existing_info->original_file_mtime = info->original_file_mtime; free_thumbnail_info (info); } /********************************* * MUTEX UNLOCKED *********************************/ if (DEBUGGING) { g_message ("(Main Thread) Unlocking mutex"); } g_mutex_unlock (&thumbnails_mutex); } gboolean nemo_thumbnail_factory_check_status (void) { return gnome_desktop_thumbnail_cache_check_permissions (get_thumbnail_factory (), TRUE); } nemo-4.4.2/libnemo-private/nemo-thumbnails.h000066400000000000000000000037521357442400300210400ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-thumbnails.h: Thumbnail code for icon factory. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Andy Hertzfeld */ #ifndef NEMO_THUMBNAILS_H #define NEMO_THUMBNAILS_H #include #include /* Cool-off period between last file modification time and thumbnail creation */ #define THUMBNAIL_CREATION_DELAY_SECS 3 /* Returns NULL if there's no thumbnail yet. */ void nemo_create_thumbnail (NemoFile *file, gint throttle_count); gboolean nemo_can_thumbnail (NemoFile *file); gboolean nemo_can_thumbnail_internally (NemoFile *file); gboolean nemo_thumbnail_is_mimetype_limited_by_size (const char *mime_type); void nemo_thumbnail_frame_image (GdkPixbuf **pixbuf); void nemo_thumbnail_pad_top_and_bottom (GdkPixbuf **pixbuf, gint extra_height); /* Queue handling: */ void nemo_thumbnail_remove_from_queue (const char *file_uri); void nemo_thumbnail_prioritize (const char *file_uri); gboolean nemo_thumbnail_factory_check_status (void); #endif /* NEMO_THUMBNAILS_H */ nemo-4.4.2/libnemo-private/nemo-trash-monitor.c000066400000000000000000000154331357442400300214720ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-trash-monitor.c: Nemo trash state watcher. Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Pavel Cisler */ #include #include "nemo-trash-monitor.h" #include "nemo-directory-notify.h" #include "nemo-directory.h" #include "nemo-file-attributes.h" #include "nemo-icon-names.h" #include #include #include struct NemoTrashMonitorDetails { gboolean empty; GIcon *icon; const gchar *symbolic_icon_name; GFileMonitor *file_monitor; }; enum { TRASH_STATE_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static NemoTrashMonitor *nemo_trash_monitor = NULL; G_DEFINE_TYPE(NemoTrashMonitor, nemo_trash_monitor, G_TYPE_OBJECT) static void nemo_trash_monitor_finalize (GObject *object) { NemoTrashMonitor *trash_monitor; trash_monitor = NEMO_TRASH_MONITOR (object); if (trash_monitor->details->icon) { g_object_unref (trash_monitor->details->icon); } if (trash_monitor->details->file_monitor) { g_object_unref (trash_monitor->details->file_monitor); } G_OBJECT_CLASS (nemo_trash_monitor_parent_class)->finalize (object); } static void nemo_trash_monitor_class_init (NemoTrashMonitorClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = nemo_trash_monitor_finalize; signals[TRASH_STATE_CHANGED] = g_signal_new ("trash_state_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTrashMonitorClass, trash_state_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_type_class_add_private (object_class, sizeof(NemoTrashMonitorDetails)); } static void update_icon (NemoTrashMonitor *trash_monitor) { g_clear_object (&trash_monitor->details->icon); if (trash_monitor->details->empty) { trash_monitor->details->icon = g_themed_icon_new (NEMO_ICON_TRASH); trash_monitor->details->symbolic_icon_name = NEMO_ICON_SYMBOLIC_TRASH; } else { trash_monitor->details->icon = g_themed_icon_new (NEMO_ICON_TRASH_FULL); trash_monitor->details->symbolic_icon_name = NEMO_ICON_SYMBOLIC_TRASH_FULL; } } static void update_empty_info (NemoTrashMonitor *trash_monitor, gboolean is_empty) { if (trash_monitor->details->empty == is_empty) { return; } trash_monitor->details->empty = is_empty; update_icon (trash_monitor); /* trash got empty or full, notify everyone who cares */ g_signal_emit (trash_monitor, signals[TRASH_STATE_CHANGED], 0, trash_monitor->details->empty); } /* Use G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT since we only want to know whether the * trash is empty or not, not access its children. This is available for the * trash backend since it uses a cache. In this way we prevent flooding the * trash backend with enumeration requests when trashing > 1000 files */ static void trash_query_info_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NemoTrashMonitor *trash_monitor = user_data; GFileInfo *info; guint32 item_count; gboolean is_empty = TRUE; info = g_file_query_info_finish (G_FILE (source), res, NULL); if (info != NULL) { item_count = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT); is_empty = item_count == 0; g_object_unref (info); } update_empty_info (trash_monitor, is_empty); g_object_unref (trash_monitor); } static void schedule_update_info (NemoTrashMonitor *trash_monitor) { GFile *location; location = g_file_new_for_uri ("trash:///"); g_file_query_info_async (location, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL, trash_query_info_cb, g_object_ref (trash_monitor)); g_object_unref (location); } static void file_changed (GFileMonitor* monitor, GFile *child, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { NemoTrashMonitor *trash_monitor; trash_monitor = NEMO_TRASH_MONITOR (user_data); schedule_update_info (trash_monitor); } static void nemo_trash_monitor_init (NemoTrashMonitor *trash_monitor) { GFile *location; trash_monitor->details = G_TYPE_INSTANCE_GET_PRIVATE (trash_monitor, NEMO_TYPE_TRASH_MONITOR, NemoTrashMonitorDetails); trash_monitor->details->empty = TRUE; update_icon (trash_monitor); location = g_file_new_for_uri ("trash:///"); trash_monitor->details->file_monitor = g_file_monitor_file (location, 0, NULL, NULL); g_signal_connect (trash_monitor->details->file_monitor, "changed", (GCallback)file_changed, trash_monitor); g_object_unref (location); schedule_update_info (trash_monitor); } static void unref_trash_monitor (void) { g_object_unref (nemo_trash_monitor); } NemoTrashMonitor * nemo_trash_monitor_get (void) { if (nemo_trash_monitor == NULL) { /* not running yet, start it up */ nemo_trash_monitor = NEMO_TRASH_MONITOR (g_object_new (NEMO_TYPE_TRASH_MONITOR, NULL)); eel_debug_call_at_shutdown (unref_trash_monitor); } return nemo_trash_monitor; } gboolean nemo_trash_monitor_is_empty (void) { NemoTrashMonitor *monitor; monitor = nemo_trash_monitor_get (); return monitor->details->empty; } GIcon * nemo_trash_monitor_get_icon (void) { NemoTrashMonitor *monitor; monitor = nemo_trash_monitor_get (); if (monitor->details->icon) { return g_object_ref (monitor->details->icon); } return NULL; } gchar * nemo_trash_monitor_get_symbolic_icon_name (void) { NemoTrashMonitor *monitor; monitor = nemo_trash_monitor_get (); if (monitor->details->symbolic_icon_name) { return g_strdup (monitor->details->symbolic_icon_name); } return NULL; } void nemo_trash_monitor_add_new_trash_directories (void) { /* We trashed something... */ } nemo-4.4.2/libnemo-private/nemo-trash-monitor.h000066400000000000000000000047231357442400300214770ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-trash-monitor.h: Nemo trash state watcher. Copyright (C) 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Pavel Cisler */ #ifndef NEMO_TRASH_MONITOR_H #define NEMO_TRASH_MONITOR_H #include #include typedef struct NemoTrashMonitor NemoTrashMonitor; typedef struct NemoTrashMonitorClass NemoTrashMonitorClass; typedef struct NemoTrashMonitorDetails NemoTrashMonitorDetails; #define NEMO_TYPE_TRASH_MONITOR nemo_trash_monitor_get_type() #define NEMO_TRASH_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_TRASH_MONITOR, NemoTrashMonitor)) #define NEMO_TRASH_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_TRASH_MONITOR, NemoTrashMonitorClass)) #define NEMO_IS_TRASH_MONITOR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_TRASH_MONITOR)) #define NEMO_IS_TRASH_MONITOR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_TRASH_MONITOR)) #define NEMO_TRASH_MONITOR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_TRASH_MONITOR, NemoTrashMonitorClass)) struct NemoTrashMonitor { GObject object; NemoTrashMonitorDetails *details; }; struct NemoTrashMonitorClass { GObjectClass parent_class; void (* trash_state_changed) (NemoTrashMonitor *trash_monitor, gboolean new_state); }; GType nemo_trash_monitor_get_type (void); NemoTrashMonitor *nemo_trash_monitor_get (void); gboolean nemo_trash_monitor_is_empty (void); GIcon *nemo_trash_monitor_get_icon (void); gchar *nemo_trash_monitor_get_symbolic_icon_name (void); void nemo_trash_monitor_add_new_trash_directories (void); #endif nemo-4.4.2/libnemo-private/nemo-tree-view-drag-dest.c000066400000000000000000000703631357442400300224460ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* * Nemo * * Copyright (C) 2002 Sun Microsystems, Inc. * * Nemo 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. * * Nemo 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Dave Camp * XDS support: Benedikt Meurer (adapted by Amos Brocco ) */ /* nemo-tree-view-drag-dest.c: Handles drag and drop for treeviews which * contain a hierarchy of files */ #include #include "nemo-tree-view-drag-dest.h" #include "nemo-file-dnd.h" #include "nemo-file-changes-queue.h" #include "nemo-icon-dnd.h" #include "nemo-link.h" #include #include #include #define DEBUG_FLAG NEMO_DEBUG_LIST_VIEW #include "nemo-debug.h" #define AUTO_SCROLL_MARGIN 20 #define HOVER_EXPAND_TIMEOUT 1 struct _NemoTreeViewDragDestDetails { GtkTreeView *tree_view; gboolean drop_occurred; gboolean have_drag_data; guint drag_type; GtkSelectionData *drag_data; GList *drag_list; guint highlight_id; guint scroll_id; guint expand_id; gchar *desktop_dnd_source_fs; gboolean desktop_dnd_can_delete_source; char *direct_save_uri; }; enum { GET_ROOT_URI, GET_FILE_FOR_PATH, MOVE_COPY_ITEMS, HANDLE_NETSCAPE_URL, HANDLE_URI_LIST, HANDLE_TEXT, HANDLE_RAW, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (NemoTreeViewDragDest, nemo_tree_view_drag_dest, G_TYPE_OBJECT); static const GtkTargetEntry drag_types [] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST }, /* prefer XDS Protocol Type over "_NETSCAPE_URL" to make DnD work in Firefox. */ { (char *)NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, 0, NEMO_ICON_DND_XDNDDIRECTSAVE }, /* prefer "_NETSCAPE_URL" over "text/uri-list" to satisfy web browsers. */ { (char *)NEMO_ICON_DND_NETSCAPE_URL_TYPE, 0, NEMO_ICON_DND_NETSCAPE_URL }, { (char *)NEMO_ICON_DND_URI_LIST_TYPE, 0, NEMO_ICON_DND_URI_LIST }, { (char *)NEMO_ICON_DND_RAW_TYPE, 0, NEMO_ICON_DND_RAW } }; static void gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view) { GdkRectangle visible_rect; GtkAdjustment *vadjustment; GdkDeviceManager *manager; GdkDevice *pointer; GdkWindow *window; int y; int offset; float value; window = gtk_tree_view_get_bin_window (tree_view); vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view)); manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (tree_view))); pointer = gdk_device_manager_get_client_pointer (manager); gdk_window_get_device_position (window, pointer, NULL, &y, NULL); y += gtk_adjustment_get_value (vadjustment); gtk_tree_view_get_visible_rect (tree_view, &visible_rect); offset = y - (visible_rect.y + 2 * AUTO_SCROLL_MARGIN); if (offset > 0) { offset = y - (visible_rect.y + visible_rect.height - 2 * AUTO_SCROLL_MARGIN); if (offset < 0) { return; } } value = CLAMP (gtk_adjustment_get_value (vadjustment) + offset, 0.0, gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment)); gtk_adjustment_set_value (vadjustment, value); } static int scroll_timeout (gpointer data) { GtkTreeView *tree_view = GTK_TREE_VIEW (data); gtk_tree_view_vertical_autoscroll (tree_view); return TRUE; } static void remove_scroll_timeout (NemoTreeViewDragDest *dest) { if (dest->details->scroll_id) { g_source_remove (dest->details->scroll_id); dest->details->scroll_id = 0; } } static int expand_timeout (gpointer data) { GtkTreeView *tree_view; GtkTreePath *drop_path; tree_view = GTK_TREE_VIEW (data); gtk_tree_view_get_drag_dest_row (tree_view, &drop_path, NULL); if (drop_path) { gtk_tree_view_expand_row (tree_view, drop_path, FALSE); gtk_tree_path_free (drop_path); } return FALSE; } static void remove_expand_timeout (NemoTreeViewDragDest *dest) { if (dest->details->expand_id) { g_source_remove (dest->details->expand_id); dest->details->expand_id = 0; } } static gboolean highlight_draw (GtkWidget *widget, cairo_t *cr, gpointer data) { GdkWindow *bin_window; int width; int height; GtkStyleContext *style; /* FIXMEchpe: is bin window right here??? */ bin_window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget)); width = gdk_window_get_width (bin_window); height = gdk_window_get_height (bin_window); style = gtk_widget_get_style_context (widget); gtk_style_context_save (style); gtk_style_context_add_class (style, "treeview-drop-indicator"); gtk_render_focus (style, cr, 0, 0, width, height); gtk_style_context_restore (style); return FALSE; } static void set_widget_highlight (NemoTreeViewDragDest *dest, gboolean highlight) { if (!highlight && dest->details->highlight_id) { g_signal_handler_disconnect (dest->details->tree_view, dest->details->highlight_id); dest->details->highlight_id = 0; gtk_widget_queue_draw (GTK_WIDGET (dest->details->tree_view)); } if (highlight && !dest->details->highlight_id) { dest->details->highlight_id = g_signal_connect_object (dest->details->tree_view, "draw", G_CALLBACK (highlight_draw), dest, 0); gtk_widget_queue_draw (GTK_WIDGET (dest->details->tree_view)); } } static void set_drag_dest_row (NemoTreeViewDragDest *dest, GtkTreePath *path) { if (path) { set_widget_highlight (dest, FALSE); gtk_tree_view_set_drag_dest_row (dest->details->tree_view, path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); } else { set_widget_highlight (dest, TRUE); gtk_tree_view_set_drag_dest_row (dest->details->tree_view, NULL, 0); } } static void clear_drag_dest_row (NemoTreeViewDragDest *dest) { gtk_tree_view_set_drag_dest_row (dest->details->tree_view, NULL, 0); set_widget_highlight (dest, FALSE); } static gboolean get_drag_data (NemoTreeViewDragDest *dest, GdkDragContext *context, guint32 time) { GdkAtom target; target = gtk_drag_dest_find_target (GTK_WIDGET (dest->details->tree_view), context, NULL); if (target == GDK_NONE) { return FALSE; } if (target == gdk_atom_intern (NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE) && !dest->details->drop_occurred) { dest->details->drag_type = NEMO_ICON_DND_XDNDDIRECTSAVE; dest->details->have_drag_data = TRUE; return TRUE; } gtk_drag_get_data (GTK_WIDGET (dest->details->tree_view), context, target, time); return TRUE; } static void free_drag_data (NemoTreeViewDragDest *dest) { dest->details->have_drag_data = FALSE; if (dest->details->drag_data) { gtk_selection_data_free (dest->details->drag_data); dest->details->drag_data = NULL; } if (dest->details->drag_list) { nemo_drag_destroy_selection_list (dest->details->drag_list); dest->details->drag_list = NULL; } g_clear_pointer (&dest->details->direct_save_uri, g_free); g_clear_pointer (&dest->details->desktop_dnd_source_fs, g_free); dest->details->desktop_dnd_can_delete_source = FALSE; } static char * get_root_uri (NemoTreeViewDragDest *dest) { char *uri; g_signal_emit (dest, signals[GET_ROOT_URI], 0, &uri); return uri; } static NemoFile * file_for_path (NemoTreeViewDragDest *dest, GtkTreePath *path) { NemoFile *file; char *uri; if (path) { g_signal_emit (dest, signals[GET_FILE_FOR_PATH], 0, path, &file); } else { uri = get_root_uri (dest); file = NULL; if (uri != NULL) { file = nemo_file_get_by_uri (uri); } g_free (uri); } return file; } static GtkTreePath * get_drop_path (NemoTreeViewDragDest *dest, GtkTreePath *path) { NemoFile *file; GtkTreePath *ret; if (!path || !dest->details->have_drag_data) { return NULL; } ret = gtk_tree_path_copy (path); file = file_for_path (dest, ret); /* Go up the tree until we find a file that can accept a drop */ while (file == NULL /* dummy row */ || !nemo_drag_can_accept_info (file, dest->details->drag_type, dest->details->drag_list)) { if (gtk_tree_path_get_depth (ret) == 1) { gtk_tree_path_free (ret); ret = NULL; break; } else { gtk_tree_path_up (ret); nemo_file_unref (file); file = file_for_path (dest, ret); } } nemo_file_unref (file); return ret; } static char * get_drop_target_uri_for_path (NemoTreeViewDragDest *dest, GtkTreePath *path) { NemoFile *file; char *target; file = file_for_path (dest, path); if (file == NULL) { return NULL; } target = nemo_file_get_drop_target_uri (file); nemo_file_unref (file); return target; } static guint get_drop_action (NemoTreeViewDragDest *dest, GdkDragContext *context, GtkTreePath *path) { char *drop_target; int action; if (!dest->details->have_drag_data || (dest->details->drag_type == NEMO_ICON_DND_GNOME_ICON_LIST && dest->details->drag_list == NULL)) { return 0; } switch (dest->details->drag_type) { case NEMO_ICON_DND_GNOME_ICON_LIST : drop_target = get_drop_target_uri_for_path (dest, path); if (!drop_target) { return 0; } nemo_drag_default_drop_action_for_icons (context, drop_target, dest->details->drag_list, &action, &dest->details->desktop_dnd_source_fs, &dest->details->desktop_dnd_can_delete_source); g_free (drop_target); return action; case NEMO_ICON_DND_NETSCAPE_URL: drop_target = get_drop_target_uri_for_path (dest, path); if (drop_target == NULL) { return 0; } action = nemo_drag_default_drop_action_for_netscape_url (context); g_free (drop_target); return action; case NEMO_ICON_DND_URI_LIST : drop_target = get_drop_target_uri_for_path (dest, path); if (drop_target == NULL) { return 0; } g_free (drop_target); return gdk_drag_context_get_suggested_action (context); case NEMO_ICON_DND_TEXT: case NEMO_ICON_DND_RAW: case NEMO_ICON_DND_XDNDDIRECTSAVE: return GDK_ACTION_COPY; default: break; } return 0; } static gboolean drag_motion_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, guint32 time, gpointer data) { NemoTreeViewDragDest *dest; GtkTreePath *path; GtkTreePath *drop_path, *old_drop_path; GtkTreeModel *model; GtkTreeIter drop_iter; GtkTreeViewDropPosition pos; GdkWindow *bin_window; guint action; gboolean res = TRUE; dest = NEMO_TREE_VIEW_DRAG_DEST (data); gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y, &path, &pos); if (!dest->details->have_drag_data) { res = get_drag_data (dest, context, time); } if (!res) { return FALSE; } drop_path = get_drop_path (dest, path); action = 0; bin_window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget)); if (bin_window != NULL) { int bin_x, bin_y; gdk_window_get_position (bin_window, &bin_x, &bin_y); if (bin_y <= y) { /* ignore drags on the header */ action = get_drop_action (dest, context, drop_path); } } gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (widget), &old_drop_path, NULL); if (action) { set_drag_dest_row (dest, drop_path); model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); if (drop_path == NULL || (old_drop_path != NULL && gtk_tree_path_compare (old_drop_path, drop_path) != 0)) { remove_expand_timeout (dest); } if (dest->details->expand_id == 0 && drop_path != NULL) { gtk_tree_model_get_iter (model, &drop_iter, drop_path); if (gtk_tree_model_iter_has_child (model, &drop_iter)) { dest->details->expand_id = g_timeout_add_seconds (HOVER_EXPAND_TIMEOUT, expand_timeout, dest->details->tree_view); } } } else { clear_drag_dest_row (dest); remove_expand_timeout (dest); } if (path) { gtk_tree_path_free (path); } if (drop_path) { gtk_tree_path_free (drop_path); } if (old_drop_path) { gtk_tree_path_free (old_drop_path); } if (dest->details->scroll_id == 0) { dest->details->scroll_id = g_timeout_add (150, scroll_timeout, dest->details->tree_view); } gdk_drag_status (context, action, time); return TRUE; } static void drag_leave_callback (GtkWidget *widget, GdkDragContext *context, guint32 time, gpointer data) { NemoTreeViewDragDest *dest; dest = NEMO_TREE_VIEW_DRAG_DEST (data); clear_drag_dest_row (dest); free_drag_data (dest); remove_scroll_timeout (dest); remove_expand_timeout (dest); } static char * get_drop_target_uri_at_pos (NemoTreeViewDragDest *dest, int x, int y) { char *drop_target; GtkTreePath *path; GtkTreePath *drop_path; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos (dest->details->tree_view, x, y, &path, &pos); drop_path = get_drop_path (dest, path); drop_target = get_drop_target_uri_for_path (dest, drop_path); if (path != NULL) { gtk_tree_path_free (path); } if (drop_path != NULL) { gtk_tree_path_free (drop_path); } return drop_target; } static void receive_uris (NemoTreeViewDragDest *dest, GdkDragContext *context, GList *source_uris, int x, int y) { char *drop_target; GdkDragAction action, real_action; drop_target = get_drop_target_uri_at_pos (dest, x, y); g_assert (drop_target != NULL); real_action = gdk_drag_context_get_selected_action (context); if (real_action == GDK_ACTION_ASK) { if (nemo_drag_selection_includes_special_link (dest->details->drag_list)) { /* We only want to move the trash */ action = GDK_ACTION_MOVE; } else { action = GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK; } real_action = nemo_drag_drop_action_ask (GTK_WIDGET (dest->details->tree_view), action); } if (real_action > 0) { if (!nemo_drag_uris_local (drop_target, source_uris) || real_action != GDK_ACTION_MOVE) { g_signal_emit (dest, signals[MOVE_COPY_ITEMS], 0, source_uris, drop_target, real_action, x, y); } } g_free (drop_target); } static void receive_dropped_icons (NemoTreeViewDragDest *dest, GdkDragContext *context, int x, int y) { GList *source_uris; GList *l; /* FIXME: ignore local only moves */ if (!dest->details->drag_list) { return; } source_uris = NULL; for (l = dest->details->drag_list; l != NULL; l = l->next) { source_uris = g_list_prepend (source_uris, ((NemoDragSelectionItem *)l->data)->uri); } source_uris = g_list_reverse (source_uris); receive_uris (dest, context, source_uris, x, y); g_list_free (source_uris); } static void receive_dropped_uri_list (NemoTreeViewDragDest *dest, GdkDragContext *context, int x, int y) { char *drop_target; if (!dest->details->drag_data) { return; } drop_target = get_drop_target_uri_at_pos (dest, x, y); g_assert (drop_target != NULL); g_signal_emit (dest, signals[HANDLE_URI_LIST], 0, (char*) gtk_selection_data_get_data (dest->details->drag_data), drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } static void receive_dropped_text (NemoTreeViewDragDest *dest, GdkDragContext *context, int x, int y) { char *drop_target; guchar *text; if (!dest->details->drag_data) { return; } drop_target = get_drop_target_uri_at_pos (dest, x, y); g_assert (drop_target != NULL); text = gtk_selection_data_get_text (dest->details->drag_data); g_signal_emit (dest, signals[HANDLE_TEXT], 0, (char *) text, drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (text); g_free (drop_target); } static void receive_dropped_raw (NemoTreeViewDragDest *dest, const char *raw_data, int length, GdkDragContext *context, int x, int y) { char *drop_target; if (!dest->details->drag_data) { return; } drop_target = get_drop_target_uri_at_pos (dest, x, y); g_assert (drop_target != NULL); g_signal_emit (dest, signals[HANDLE_RAW], 0, raw_data, length, drop_target, dest->details->direct_save_uri, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } static void receive_dropped_netscape_url (NemoTreeViewDragDest *dest, GdkDragContext *context, int x, int y) { char *drop_target; if (!dest->details->drag_data) { return; } drop_target = get_drop_target_uri_at_pos (dest, x, y); g_assert (drop_target != NULL); g_signal_emit (dest, signals[HANDLE_NETSCAPE_URL], 0, (char*) gtk_selection_data_get_data (dest->details->drag_data), drop_target, gdk_drag_context_get_selected_action (context), x, y); g_free (drop_target); } static gboolean receive_xds (NemoTreeViewDragDest *dest, GtkWidget *widget, guint32 time, GdkDragContext *context, int x, int y) { GFile *location; const guchar *selection_data; gint selection_format; gint selection_length; selection_data = gtk_selection_data_get_data (dest->details->drag_data); selection_format = gtk_selection_data_get_format (dest->details->drag_data); selection_length = gtk_selection_data_get_length (dest->details->drag_data); if (selection_format == 8 && selection_length == 1 && selection_data[0] == 'F') { gtk_drag_get_data (widget, context, gdk_atom_intern (NEMO_ICON_DND_RAW_TYPE, FALSE), time); return FALSE; } else if (selection_format == 8 && selection_length == 1 && selection_data[0] == 'S') { g_assert (dest->details->direct_save_uri != NULL); location = g_file_new_for_uri (dest->details->direct_save_uri); nemo_file_changes_queue_file_added (location); nemo_file_changes_consume_changes (TRUE); g_object_unref (location); } return TRUE; } static gboolean drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint32 time, gpointer data) { NemoTreeViewDragDest *dest; const gchar *tmp; int length; gboolean success, finished; dest = NEMO_TREE_VIEW_DRAG_DEST (data); if (!dest->details->have_drag_data) { dest->details->have_drag_data = TRUE; dest->details->drag_type = info; dest->details->drag_data = gtk_selection_data_copy (selection_data); if (info == NEMO_ICON_DND_GNOME_ICON_LIST) { dest->details->drag_list = nemo_drag_build_selection_list (selection_data); } } if (dest->details->drop_occurred) { success = FALSE; finished = TRUE; switch (info) { case NEMO_ICON_DND_GNOME_ICON_LIST : receive_dropped_icons (dest, context, x, y); success = TRUE; break; case NEMO_ICON_DND_NETSCAPE_URL : receive_dropped_netscape_url (dest, context, x, y); success = TRUE; break; case NEMO_ICON_DND_URI_LIST : receive_dropped_uri_list (dest, context, x, y); success = TRUE; break; case NEMO_ICON_DND_TEXT: receive_dropped_text (dest, context, x, y); success = TRUE; break; case NEMO_ICON_DND_RAW: length = gtk_selection_data_get_length (selection_data); tmp = (const gchar *) gtk_selection_data_get_data (selection_data); receive_dropped_raw (dest, tmp, length, context, x, y); success = TRUE; break; case NEMO_ICON_DND_XDNDDIRECTSAVE: finished = receive_xds (dest, widget, time, context, x, y); success = TRUE; break; default: break; } if (finished) { dest->details->drop_occurred = FALSE; free_drag_data (dest); gtk_drag_finish (context, success, FALSE, time); } } /* appease GtkTreeView by preventing its drag_data_receive * from being called */ g_signal_stop_emission_by_name (dest->details->tree_view, "drag_data_received"); return TRUE; } static char * get_direct_save_filename (GdkDragContext *context) { guchar *prop_text; gint prop_len; if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern (NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL, &prop_len, &prop_text)) { return NULL; } /* Zero-terminate the string */ prop_text = g_realloc (prop_text, prop_len + 1); prop_text[prop_len] = '\0'; /* Verify that the file name provided by the source is valid */ if (*prop_text == '\0' || strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) != NULL) { DEBUG ("Invalid filename provided by XDS drag site"); g_free (prop_text); return NULL; } return (gchar *) prop_text; } static gboolean set_direct_save_uri (NemoTreeViewDragDest *dest, GdkDragContext *context, int x, int y) { GFile *base, *child; char *drop_uri; char *filename, *uri; g_assert (dest->details->direct_save_uri == NULL); uri = NULL; drop_uri = get_drop_target_uri_at_pos (dest, x, y); if (drop_uri != NULL) { filename = get_direct_save_filename (context); if (filename != NULL) { /* Resolve relative path */ base = g_file_new_for_uri (drop_uri); child = g_file_get_child (base, filename); uri = g_file_get_uri (child); g_object_unref (base); g_object_unref (child); /* Change the property */ gdk_property_change (gdk_drag_context_get_source_window (context), gdk_atom_intern (NEMO_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), gdk_atom_intern ("text/plain", FALSE), 8, GDK_PROP_MODE_REPLACE, (const guchar *) uri, strlen (uri)); dest->details->direct_save_uri = uri; } else { DEBUG ("Invalid filename provided by XDS drag site"); } } else { DEBUG ("Could not retrieve XDS drop destination"); } return uri != NULL; } static gboolean drag_drop_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, guint32 time, gpointer data) { NemoTreeViewDragDest *dest; guint info; GdkAtom target; dest = NEMO_TREE_VIEW_DRAG_DEST (data); target = gtk_drag_dest_find_target (GTK_WIDGET (dest->details->tree_view), context, NULL); if (target == GDK_NONE) { return FALSE; } info = dest->details->drag_type; if (info == NEMO_ICON_DND_XDNDDIRECTSAVE) { /* We need to set this or get_drop_path will fail, and it was unset by drag_leave_callback */ dest->details->have_drag_data = TRUE; if (!set_direct_save_uri (dest, context, x, y)) { return FALSE; } dest->details->have_drag_data = FALSE; } dest->details->drop_occurred = TRUE; get_drag_data (dest, context, time); remove_scroll_timeout (dest); remove_expand_timeout (dest); clear_drag_dest_row (dest); return TRUE; } static void tree_view_weak_notify (gpointer user_data, GObject *object) { NemoTreeViewDragDest *dest; dest = NEMO_TREE_VIEW_DRAG_DEST (user_data); remove_scroll_timeout (dest); remove_expand_timeout (dest); dest->details->tree_view = NULL; } static void nemo_tree_view_drag_dest_dispose (GObject *object) { NemoTreeViewDragDest *dest; dest = NEMO_TREE_VIEW_DRAG_DEST (object); if (dest->details->tree_view) { g_object_weak_unref (G_OBJECT (dest->details->tree_view), tree_view_weak_notify, dest); } remove_scroll_timeout (dest); remove_expand_timeout (dest); G_OBJECT_CLASS (nemo_tree_view_drag_dest_parent_class)->dispose (object); } static void nemo_tree_view_drag_dest_finalize (GObject *object) { NemoTreeViewDragDest *dest; dest = NEMO_TREE_VIEW_DRAG_DEST (object); free_drag_data (dest); G_OBJECT_CLASS (nemo_tree_view_drag_dest_parent_class)->finalize (object); } static void nemo_tree_view_drag_dest_init (NemoTreeViewDragDest *dest) { dest->details = G_TYPE_INSTANCE_GET_PRIVATE (dest, NEMO_TYPE_TREE_VIEW_DRAG_DEST, NemoTreeViewDragDestDetails); } static void nemo_tree_view_drag_dest_class_init (NemoTreeViewDragDestClass *class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = nemo_tree_view_drag_dest_dispose; gobject_class->finalize = nemo_tree_view_drag_dest_finalize; g_type_class_add_private (class, sizeof (NemoTreeViewDragDestDetails)); signals[GET_ROOT_URI] = g_signal_new ("get_root_uri", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, get_root_uri), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_STRING, 0); signals[GET_FILE_FOR_PATH] = g_signal_new ("get_file_for_path", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, get_file_for_path), NULL, NULL, g_cclosure_marshal_generic, NEMO_TYPE_FILE, 1, GTK_TYPE_TREE_PATH); signals[MOVE_COPY_ITEMS] = g_signal_new ("move_copy_items", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, move_copy_items), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_NETSCAPE_URL] = g_signal_new ("handle_netscape_url", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, handle_netscape_url), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_URI_LIST] = g_signal_new ("handle_uri_list", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, handle_uri_list), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_TEXT] = g_signal_new ("handle_text", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, handle_text), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); signals[HANDLE_RAW] = g_signal_new ("handle_raw", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoTreeViewDragDestClass, handle_raw), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 7, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_DRAG_ACTION, G_TYPE_INT, G_TYPE_INT); } NemoTreeViewDragDest * nemo_tree_view_drag_dest_new (GtkTreeView *tree_view) { NemoTreeViewDragDest *dest; GtkTargetList *targets; dest = g_object_new (NEMO_TYPE_TREE_VIEW_DRAG_DEST, NULL); dest->details->tree_view = tree_view; dest->details->desktop_dnd_source_fs = NULL; dest->details->desktop_dnd_can_delete_source = FALSE; g_object_weak_ref (G_OBJECT (dest->details->tree_view), tree_view_weak_notify, dest); gtk_drag_dest_set (GTK_WIDGET (tree_view), 0, drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK); targets = gtk_drag_dest_get_target_list (GTK_WIDGET (tree_view)); gtk_target_list_add_text_targets (targets, NEMO_ICON_DND_TEXT); g_signal_connect_object (tree_view, "drag_motion", G_CALLBACK (drag_motion_callback), dest, 0); g_signal_connect_object (tree_view, "drag_leave", G_CALLBACK (drag_leave_callback), dest, 0); g_signal_connect_object (tree_view, "drag_drop", G_CALLBACK (drag_drop_callback), dest, 0); g_signal_connect_object (tree_view, "drag_data_received", G_CALLBACK (drag_data_received_callback), dest, 0); return dest; } nemo-4.4.2/libnemo-private/nemo-tree-view-drag-dest.h000066400000000000000000000063411357442400300224460ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2002 Sun Microsystems, Inc. * * Nemo 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. * * Nemo 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Dave Camp */ /* nemo-tree-view-drag-dest.h: Handles drag and drop for treeviews which * contain a hierarchy of files */ #ifndef NEMO_TREE_VIEW_DRAG_DEST_H #define NEMO_TREE_VIEW_DRAG_DEST_H #include #include "nemo-file.h" G_BEGIN_DECLS #define NEMO_TYPE_TREE_VIEW_DRAG_DEST (nemo_tree_view_drag_dest_get_type ()) #define NEMO_TREE_VIEW_DRAG_DEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_TREE_VIEW_DRAG_DEST, NemoTreeViewDragDest)) #define NEMO_TREE_VIEW_DRAG_DEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_TREE_VIEW_DRAG_DEST, NemoTreeViewDragDestClass)) #define NEMO_IS_TREE_VIEW_DRAG_DEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_TREE_VIEW_DRAG_DEST)) #define NEMO_IS_TREE_VIEW_DRAG_DEST_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_TREE_VIEW_DRAG_DEST)) typedef struct _NemoTreeViewDragDest NemoTreeViewDragDest; typedef struct _NemoTreeViewDragDestClass NemoTreeViewDragDestClass; typedef struct _NemoTreeViewDragDestDetails NemoTreeViewDragDestDetails; struct _NemoTreeViewDragDest { GObject parent; NemoTreeViewDragDestDetails *details; }; struct _NemoTreeViewDragDestClass { GObjectClass parent; char *(*get_root_uri) (NemoTreeViewDragDest *dest); NemoFile *(*get_file_for_path) (NemoTreeViewDragDest *dest, GtkTreePath *path); void (*move_copy_items) (NemoTreeViewDragDest *dest, const GList *item_uris, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_netscape_url) (NemoTreeViewDragDest *dest, const char *url, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_uri_list) (NemoTreeViewDragDest *dest, const char *uri_list, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_text) (NemoTreeViewDragDest *dest, const char *text, const char *target_uri, GdkDragAction action, int x, int y); void (* handle_raw) (NemoTreeViewDragDest *dest, char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y); }; GType nemo_tree_view_drag_dest_get_type (void); NemoTreeViewDragDest *nemo_tree_view_drag_dest_new (GtkTreeView *tree_view); G_END_DECLS #endif nemo-4.4.2/libnemo-private/nemo-ui-utilities.c000066400000000000000000000073061357442400300213120ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-ui-utilities.c - helper functions for GtkUIManager stuff Copyright (C) 2004 Red Hat, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Alexander Larsson */ #include #include "nemo-ui-utilities.h" #include "nemo-icon-info.h" #include #include #include void nemo_ui_unmerge_ui (GtkUIManager *ui_manager, guint *merge_id, GtkActionGroup **action_group) { if (*merge_id != 0) { gtk_ui_manager_remove_ui (ui_manager, *merge_id); *merge_id = 0; } if (*action_group != NULL) { gtk_ui_manager_remove_action_group (ui_manager, *action_group); *action_group = NULL; } } void nemo_ui_prepare_merge_ui (GtkUIManager *ui_manager, const char *name, guint *merge_id, GtkActionGroup **action_group) { *merge_id = gtk_ui_manager_new_merge_id (ui_manager); *action_group = gtk_action_group_new (name); gtk_action_group_set_translation_domain (*action_group, GETTEXT_PACKAGE); gtk_ui_manager_insert_action_group (ui_manager, *action_group, 0); g_object_unref (*action_group); /* owned by ui manager */ } static void extension_action_callback (GtkAction *action, gpointer callback_data) { nemo_menu_item_activate (NEMO_MENU_ITEM (callback_data)); } GtkAction * nemo_action_from_menu_item (NemoMenuItem *item, GtkWidget *parent_widget) { char *name, *label, *tip, *icon_name; gboolean sensitive, priority; GtkAction *action; GdkPixbuf *pixbuf; g_object_get (G_OBJECT (item), "name", &name, "label", &label, "tip", &tip, "icon", &icon_name, "sensitive", &sensitive, "priority", &priority, NULL); action = gtk_action_new (name, label, tip, NULL); if (icon_name != NULL) { pixbuf = nemo_ui_get_menu_icon (icon_name, parent_widget); if (pixbuf != NULL) { gtk_action_set_gicon (action, G_ICON (pixbuf)); g_object_unref (pixbuf); } } gtk_action_set_sensitive (action, sensitive); g_object_set (action, "is-important", priority, NULL); g_signal_connect_data (action, "activate", G_CALLBACK (extension_action_callback), g_object_ref (item), (GClosureNotify)g_object_unref, 0); g_free (name); g_free (label); g_free (tip); g_free (icon_name); return action; } GdkPixbuf * nemo_ui_get_menu_icon (const char *icon_name, GtkWidget *parent_widget) { NemoIconInfo *info; GdkPixbuf *pixbuf; int size; int scale; size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); scale = gtk_widget_get_scale_factor (parent_widget); if (g_path_is_absolute (icon_name)) { info = nemo_icon_info_lookup_from_path (icon_name, size, scale); } else { info = nemo_icon_info_lookup_from_name (icon_name, size, scale); } pixbuf = nemo_icon_info_get_pixbuf_nodefault_at_size (info, size); nemo_icon_info_unref (info); return pixbuf; } nemo-4.4.2/libnemo-private/nemo-ui-utilities.h000066400000000000000000000034631357442400300213170ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-ui-utilities.h - helper functions for GtkUIManager stuff Copyright (C) 2004 Red Hat, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Alexander Larsson */ #ifndef NEMO_UI_UTILITIES_H #define NEMO_UI_UTILITIES_H #include #include void nemo_ui_unmerge_ui (GtkUIManager *ui_manager, guint *merge_id, GtkActionGroup **action_group); void nemo_ui_prepare_merge_ui (GtkUIManager *ui_manager, const char *name, guint *merge_id, GtkActionGroup **action_group); GtkAction * nemo_action_from_menu_item (NemoMenuItem *item, GtkWidget *parent_widget); GdkPixbuf * nemo_ui_get_menu_icon (const char *icon_name, GtkWidget *parent_widget); #endif /* NEMO_UI_UTILITIES_H */ nemo-4.4.2/libnemo-private/nemo-undo-manager.c000066400000000000000000000131631357442400300212370ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoUndoManager - Undo/Redo transaction manager. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include #include #include "nemo-undo-private.h" struct NemoUndoManagerDetails { NemoUndoTransaction *transaction; /* These are used to tell undo from redo. */ gboolean current_transaction_is_redo; gboolean new_transaction_is_redo; /* These are used only so that we can complain if we get more * than one transaction inside undo. */ gboolean undo_in_progress; int num_transactions_during_undo; }; enum { CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { char *path; char *no_undo_menu_item_label; char *no_undo_menu_item_hint; } UndoMenuHandlerConnection; G_DEFINE_TYPE (NemoUndoManager, nemo_undo_manager, G_TYPE_OBJECT) static void release_transaction (NemoUndoManager *manager) { NemoUndoTransaction *transaction; transaction = manager->details->transaction; manager->details->transaction = NULL; if (transaction != NULL) { g_object_unref (transaction); } } void nemo_undo_manager_append (NemoUndoManager *manager, NemoUndoTransaction *transaction) { NemoUndoTransaction *duplicate_transaction; /* Check, complain, and ignore the passed-in transaction if we * get more than one within a single undo operation. The single * transaction we get during the undo operation is supposed to * be the one for redoing the undo (or re-undoing the redo). */ if (manager->details->undo_in_progress) { manager->details->num_transactions_during_undo += 1; g_return_if_fail (manager->details->num_transactions_during_undo == 1); } g_return_if_fail (transaction != NULL); /* Keep a copy of this transaction (dump the old one). */ duplicate_transaction = g_object_ref (transaction); release_transaction (manager); manager->details->transaction = duplicate_transaction; manager->details->current_transaction_is_redo = manager->details->new_transaction_is_redo; /* Fire off signal indicating that the undo state has changed. */ g_signal_emit (manager, signals[CHANGED], 0); } void nemo_undo_manager_forget (NemoUndoManager *manager, NemoUndoTransaction *transaction) { /* Nothing to forget unless the item we are passed is the * transaction we are currently holding. */ if (transaction != manager->details->transaction) { return; } /* Get rid of the transaction we are holding on to. */ release_transaction (manager); /* Fire off signal indicating that the undo state has changed. */ g_signal_emit (manager, signals[CHANGED], 0); } NemoUndoManager * nemo_undo_manager_new (void) { return NEMO_UNDO_MANAGER (g_object_new (nemo_undo_manager_get_type (), NULL)); } static void nemo_undo_manager_init (NemoUndoManager *manager) { manager->details = g_new0 (NemoUndoManagerDetails, 1); } void nemo_undo_manager_undo (NemoUndoManager *manager) { NemoUndoTransaction *transaction; g_return_if_fail (NEMO_IS_UNDO_MANAGER (manager)); transaction = manager->details->transaction; manager->details->transaction = NULL; if (transaction != NULL) { /* Perform the undo. New transactions that come in * during an undo are redo transactions. New * transactions that come in during a redo are undo * transactions. Transactions that come in outside * are always undo and never redo. */ manager->details->new_transaction_is_redo = !manager->details->current_transaction_is_redo; manager->details->undo_in_progress = TRUE; manager->details->num_transactions_during_undo = 0; nemo_undo_transaction_undo (transaction); manager->details->undo_in_progress = FALSE; manager->details->new_transaction_is_redo = FALSE; /* Let go of the transaction. */ g_object_unref (transaction); /* Fire off signal indicating the undo state has changed. */ g_signal_emit (manager, signals[CHANGED], 0); } } static void finalize (GObject *object) { NemoUndoManager *manager; manager = NEMO_UNDO_MANAGER (object); release_transaction (manager); g_free (manager->details); if (G_OBJECT_CLASS (nemo_undo_manager_parent_class)->finalize) { (* G_OBJECT_CLASS (nemo_undo_manager_parent_class)->finalize) (object); } } void nemo_undo_manager_attach (NemoUndoManager *manager, GObject *target) { g_return_if_fail (NEMO_IS_UNDO_MANAGER (manager)); g_return_if_fail (G_IS_OBJECT (target)); nemo_undo_attach_undo_manager (G_OBJECT (target), manager); } static void nemo_undo_manager_class_init (NemoUndoManagerClass *class) { G_OBJECT_CLASS (class)->finalize = finalize; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoUndoManagerClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } nemo-4.4.2/libnemo-private/nemo-undo-manager.h000066400000000000000000000054711357442400300212470ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoUndoManager - Manages undo and redo transactions. * This is the public interface used by the application. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_UNDO_MANAGER_H #define NEMO_UNDO_MANAGER_H #include #define NEMO_TYPE_UNDO_MANAGER nemo_undo_manager_get_type() #define NEMO_UNDO_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_UNDO_MANAGER, NemoUndoManager)) #define NEMO_UNDO_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_UNDO_MANAGER, NemoUndoManagerClass)) #define NEMO_IS_UNDO_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_UNDO_MANAGER)) #define NEMO_IS_UNDO_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_UNDO_MANAGER)) #define NEMO_UNDO_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_UNDO_MANAGER, NemoUndoManagerClass)) typedef struct NemoUndoManagerDetails NemoUndoManagerDetails; typedef struct { GObject parent; NemoUndoManagerDetails *details; } NemoUndoManager; typedef struct { GObjectClass parent_slot; void (* changed) (GObject *object, gpointer data); } NemoUndoManagerClass; GType nemo_undo_manager_get_type (void); NemoUndoManager *nemo_undo_manager_new (void); /* Undo operations. */ void nemo_undo_manager_undo (NemoUndoManager *undo_manager); /* Attach the undo manager to a Gtk object so that object and the widgets inside it can participate in undo. */ void nemo_undo_manager_attach (NemoUndoManager *manager, GObject *object); void nemo_undo_manager_append (NemoUndoManager *manager, NemoUndoTransaction *transaction); void nemo_undo_manager_forget (NemoUndoManager *manager, NemoUndoTransaction *transaction); #endif /* NEMO_UNDO_MANAGER_H */ nemo-4.4.2/libnemo-private/nemo-undo-private.h000066400000000000000000000024631357442400300213050ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* xxx * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_UNDO_PRIVATE_H #define NEMO_UNDO_PRIVATE_H #include #include #include NemoUndoManager * nemo_undo_get_undo_manager (GObject *attached_object); void nemo_undo_attach_undo_manager (GObject *object, NemoUndoManager *manager); #endif /* NEMO_UNDO_PRIVATE_H */ nemo-4.4.2/libnemo-private/nemo-undo-signal-handlers.c000066400000000000000000000151671357442400300227060ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Signal handlers to enable undo in Gtk Widgets. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include #include #include #include "nemo-undo-signal-handlers.h" typedef struct { char *undo_text; gint position; guint selection_start; guint selection_end; } EditableUndoData; typedef struct { gboolean undo_registered; } EditableUndoObjectData; static void restore_editable_from_undo_snapshot_callback (GObject *target, gpointer callback_data); static void editable_register_edit_undo (GtkEditable *editable); static void free_editable_object_data (gpointer data); /* nemo_undo_set_up_nemo_entry_for_undo * * Functions and callback methods to handle undo * in a NemoEntry */ static void nemo_entry_user_changed_callback (NemoEntry *entry) { /* Register undo transaction */ editable_register_edit_undo (GTK_EDITABLE (entry)); } void nemo_undo_set_up_nemo_entry_for_undo (NemoEntry *entry) { EditableUndoObjectData *data; if (!NEMO_IS_ENTRY (entry) ) { return; } data = g_new(EditableUndoObjectData, 1); data->undo_registered = FALSE; g_object_set_data_full (G_OBJECT (entry), "undo_registered", data, free_editable_object_data); /* Connect to entry signals */ g_signal_connect (entry, "user_changed", G_CALLBACK (nemo_entry_user_changed_callback), NULL); } void nemo_undo_tear_down_nemo_entry_for_undo (NemoEntry *entry) { if (!NEMO_IS_ENTRY (entry) ) { return; } /* Disconnect from entry signals */ g_signal_handlers_disconnect_by_func (entry, G_CALLBACK (nemo_entry_user_changed_callback), NULL); } /* nemo_undo_set_up_nemo_entry_for_undo * * Functions and callback methods to handle undo * in a NemoEntry */ static void free_editable_undo_data (gpointer data) { EditableUndoData *undo_data; undo_data = (EditableUndoData *) data; g_free (undo_data->undo_text); g_free (undo_data); } static void free_editable_object_data (gpointer data) { g_free (data); } static void editable_insert_text_callback (GtkEditable *editable) { /* Register undo transaction */ editable_register_edit_undo (editable); } static void editable_delete_text_callback (GtkEditable *editable) { /* Register undo transaction */ editable_register_edit_undo (editable); } static void editable_register_edit_undo (GtkEditable *editable) { EditableUndoData *undo_data; EditableUndoObjectData *undo_info; gpointer data; if (!GTK_IS_EDITABLE (editable) ) { return; } /* Check our undo registered flag */ data = g_object_get_data (G_OBJECT (editable), "undo_registered"); if (data == NULL) { g_warning ("Undo data is NULL"); return; } undo_info = (EditableUndoObjectData *)data; if (undo_info->undo_registered) { return; } undo_data = g_new0 (EditableUndoData, 1); undo_data->undo_text = gtk_editable_get_chars (editable, 0, -1); undo_data->position = gtk_editable_get_position (editable); gtk_editable_get_selection_bounds (editable, (int *)&undo_data->selection_start, (int *)&undo_data->selection_end); nemo_undo_register (G_OBJECT (editable), restore_editable_from_undo_snapshot_callback, undo_data, (GDestroyNotify) free_editable_undo_data, _("Edit"), _("Undo Edit"), _("Undo the edit"), _("Redo Edit"), _("Redo the edit")); undo_info->undo_registered = TRUE; } void nemo_undo_set_up_editable_for_undo (GtkEditable *editable) { EditableUndoObjectData *data; if (!GTK_IS_EDITABLE (editable) ) { return; } /* Connect to editable signals */ g_signal_connect (editable, "insert_text", G_CALLBACK (editable_insert_text_callback), NULL); g_signal_connect (editable, "delete_text", G_CALLBACK (editable_delete_text_callback), NULL); data = g_new (EditableUndoObjectData, 1); data->undo_registered = FALSE; g_object_set_data_full (G_OBJECT (editable), "undo_registered", data, free_editable_object_data); } void nemo_undo_tear_down_editable_for_undo (GtkEditable *editable) { if (!GTK_IS_EDITABLE (editable) ) { return; } /* Disconnect from entry signals */ g_signal_handlers_disconnect_by_func (editable, G_CALLBACK (editable_insert_text_callback), NULL); g_signal_handlers_disconnect_by_func (editable, G_CALLBACK (editable_delete_text_callback), NULL); } /* restore_editable_from_undo_snapshot_callback * * Restore edited text. */ static void restore_editable_from_undo_snapshot_callback (GObject *target, gpointer callback_data) { GtkEditable *editable; GtkWindow *window; EditableUndoData *undo_data; EditableUndoObjectData *data; gint position; editable = GTK_EDITABLE (target); undo_data = (EditableUndoData *) callback_data; /* Check our undo registered flag */ data = g_object_get_data (target, "undo_registered"); if (data == NULL) { g_warning ("Undo regisetred flag not found"); return; } /* Reset the registered flag so we get a new item for future editing. */ data->undo_registered = FALSE; /* Register a new undo transaction for redo. */ editable_register_edit_undo (editable); /* Restore the text. */ position = 0; gtk_editable_delete_text (editable, 0, -1); gtk_editable_insert_text (editable, undo_data->undo_text, strlen (undo_data->undo_text), &position); /* Set focus to widget */ window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (target))); gtk_window_set_focus (window, GTK_WIDGET (editable)); /* We have to do this call, because the previous call selects all text */ gtk_editable_select_region (editable, 0, 0); /* Restore selection */ gtk_editable_select_region (editable, undo_data->selection_start, undo_data->selection_end); /* Set the i-beam to the saved position */ gtk_editable_set_position (editable, undo_data->position); /* Reset the registered flag so we get a new item for future editing. */ data->undo_registered = FALSE; } nemo-4.4.2/libnemo-private/nemo-undo-signal-handlers.h000066400000000000000000000025501357442400300227030ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Signal handlers to enable undo in Gtk Widgets. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_UNDO_SIGNAL_HANDLERS_H #define NEMO_UNDO_SIGNAL_HANDLERS_H #include void nemo_undo_set_up_nemo_entry_for_undo (NemoEntry *entry); void nemo_undo_tear_down_nemo_entry_for_undo (NemoEntry *entry); void nemo_undo_set_up_editable_for_undo (GtkEditable *editable); void nemo_undo_tear_down_editable_for_undo (GtkEditable *editable); #endif /* NEMO_UNDO_SIGNAL_HANDLERS_H */ nemo-4.4.2/libnemo-private/nemo-undo-transaction.c000066400000000000000000000176411357442400300221570ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoUndoTransaction - An object for an undoable transaction. * Used internally by undo machinery. * Not public. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include #include #include "nemo-undo-private.h" #include #define NEMO_UNDO_TRANSACTION_LIST_DATA "Nemo undo transaction list" /* undo atoms */ static void undo_atom_list_free (GList *list); static void undo_atom_list_undo_and_free (GList *list); G_DEFINE_TYPE (NemoUndoTransaction, nemo_undo_transaction, G_TYPE_OBJECT); NemoUndoTransaction * nemo_undo_transaction_new (const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint) { NemoUndoTransaction *transaction; transaction = NEMO_UNDO_TRANSACTION (g_object_new (nemo_undo_transaction_get_type (), NULL)); transaction->operation_name = g_strdup (operation_name); transaction->undo_menu_item_label = g_strdup (undo_menu_item_label); transaction->undo_menu_item_hint = g_strdup (undo_menu_item_hint); transaction->redo_menu_item_label = g_strdup (redo_menu_item_label); transaction->redo_menu_item_hint = g_strdup (redo_menu_item_hint); return transaction; } static void nemo_undo_transaction_init (NemoUndoTransaction *transaction) { } static void remove_transaction_from_object (gpointer list_data, gpointer callback_data) { NemoUndoAtom *atom; NemoUndoTransaction *transaction; GList *list; g_assert (list_data != NULL); atom = list_data; transaction = NEMO_UNDO_TRANSACTION (callback_data); /* Remove the transaction from the list on the atom. */ list = g_object_get_data (atom->target, NEMO_UNDO_TRANSACTION_LIST_DATA); if (list != NULL) { list = g_list_remove (list, transaction); g_object_set_data (atom->target, NEMO_UNDO_TRANSACTION_LIST_DATA, list); } } static void remove_transaction_from_atom_targets (NemoUndoTransaction *transaction) { g_list_foreach (transaction->atom_list, remove_transaction_from_object, transaction); } static void nemo_undo_transaction_finalize (GObject *object) { NemoUndoTransaction *transaction; transaction = NEMO_UNDO_TRANSACTION (object); remove_transaction_from_atom_targets (transaction); undo_atom_list_free (transaction->atom_list); g_free (transaction->operation_name); g_free (transaction->undo_menu_item_label); g_free (transaction->undo_menu_item_hint); g_free (transaction->redo_menu_item_label); g_free (transaction->redo_menu_item_hint); if (transaction->owner != NULL) { g_object_unref (transaction->owner); } G_OBJECT_CLASS (nemo_undo_transaction_parent_class)->finalize (object); } void nemo_undo_transaction_add_atom (NemoUndoTransaction *transaction, const NemoUndoAtom *atom) { GList *list; g_return_if_fail (NEMO_IS_UNDO_TRANSACTION (transaction)); g_return_if_fail (atom != NULL); g_return_if_fail (G_IS_OBJECT (atom->target)); /* Add the atom to the atom list in the transaction. */ transaction->atom_list = g_list_append (transaction->atom_list, g_memdup (atom, sizeof (*atom))); /* Add the transaction to the list on the atoms target object. */ list = g_object_get_data (atom->target, NEMO_UNDO_TRANSACTION_LIST_DATA); if (g_list_find (list, transaction) != NULL) { return; } /* If it's not already on that atom, this object is new. */ list = g_list_prepend (list, transaction); g_object_set_data (atom->target, NEMO_UNDO_TRANSACTION_LIST_DATA, list); /* Connect a signal handler to the atom so it will unregister * itself when it's destroyed. */ g_signal_connect (atom->target, "destroy", G_CALLBACK (nemo_undo_transaction_unregister_object), NULL); } void nemo_undo_transaction_undo (NemoUndoTransaction *transaction) { g_return_if_fail (NEMO_IS_UNDO_TRANSACTION (transaction)); remove_transaction_from_atom_targets (transaction); undo_atom_list_undo_and_free (transaction->atom_list); transaction->atom_list = NULL; } void nemo_undo_transaction_add_to_undo_manager (NemoUndoTransaction *transaction, NemoUndoManager *manager) { g_return_if_fail (NEMO_IS_UNDO_TRANSACTION (transaction)); g_return_if_fail (transaction->owner == NULL); if (manager != NULL) { nemo_undo_manager_append (manager, transaction); transaction->owner = g_object_ref (manager); } } static void remove_atoms (NemoUndoTransaction *transaction, GObject *object) { GList *p, *next; NemoUndoAtom *atom; g_assert (NEMO_IS_UNDO_TRANSACTION (transaction)); g_assert (G_IS_OBJECT (object)); /* Destroy any atoms for this object. */ for (p = transaction->atom_list; p != NULL; p = next) { atom = p->data; next = p->next; if (atom->target == object) { transaction->atom_list = g_list_remove_link (transaction->atom_list, p); undo_atom_list_free (p); } } /* If all the atoms are gone, forget this transaction. * This may end up freeing the transaction. */ if (transaction->atom_list == NULL) { nemo_undo_manager_forget ( transaction->owner, transaction); } } static void remove_atoms_cover (gpointer list_data, gpointer callback_data) { if (NEMO_IS_UNDO_TRANSACTION (list_data)) { remove_atoms (NEMO_UNDO_TRANSACTION (list_data), G_OBJECT (callback_data)); } } void nemo_undo_transaction_unregister_object (GObject *object) { GList *list; g_return_if_fail (G_IS_OBJECT (object)); /* Remove atoms from each transaction on the list. */ list = g_object_get_data (object, NEMO_UNDO_TRANSACTION_LIST_DATA); if (list != NULL) { g_list_foreach (list, remove_atoms_cover, object); g_list_free (list); g_object_set_data (object, NEMO_UNDO_TRANSACTION_LIST_DATA, NULL); } } static void undo_atom_free (NemoUndoAtom *atom) { /* Call the destroy-notify function if it's present. */ if (atom->callback_data_destroy_notify != NULL) { (* atom->callback_data_destroy_notify) (atom->callback_data); } /* Free the atom storage. */ g_free (atom); } static void undo_atom_undo_and_free (NemoUndoAtom *atom) { /* Call the function that does the actual undo. */ (* atom->callback) (atom->target, atom->callback_data); /* Get rid of the atom now that it's spent. */ undo_atom_free (atom); } static void undo_atom_free_cover (gpointer atom, gpointer callback_data) { g_assert (atom != NULL); g_assert (callback_data == NULL); undo_atom_free (atom); } static void undo_atom_undo_and_free_cover (gpointer atom, gpointer callback_data) { g_assert (atom != NULL); g_assert (callback_data == NULL); undo_atom_undo_and_free (atom); } static void undo_atom_list_free (GList *list) { g_list_foreach (list, undo_atom_free_cover, NULL); g_list_free (list); } static void undo_atom_list_undo_and_free (GList *list) { g_list_foreach (list, undo_atom_undo_and_free_cover, NULL); g_list_free (list); } static void nemo_undo_transaction_class_init (NemoUndoTransactionClass *klass) { G_OBJECT_CLASS (klass)->finalize = nemo_undo_transaction_finalize; } nemo-4.4.2/libnemo-private/nemo-undo-transaction.h000066400000000000000000000063031357442400300221550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* NemoUndoTransaction - An object for an undoable transaction. * Used internally by undo machinery. * Not public. * * Copyright (C) 2000 Eazel, Inc. * * Author: Gene Z. Ragan * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_UNDO_TRANSACTION_H #define NEMO_UNDO_TRANSACTION_H #include #define NEMO_TYPE_UNDO_TRANSACTION nemo_undo_transaction_get_type() #define NEMO_UNDO_TRANSACTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_UNDO_TRANSACTION, NemoUndoTransaction)) #define NEMO_UNDO_TRANSACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_UNDO_TRANSACTION, NemoUndoTransactionClass)) #define NEMO_IS_UNDO_TRANSACTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_UNDO_TRANSACTION)) #define NEMO_IS_UNDO_TRANSACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_UNDO_TRANSACTION)) #define NEMO_UNDO_TRANSACTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_UNDO_TRANSACTION, NemoUndoTransactionClass)) /* The typedef for NemoUndoTransaction is in nemo-undo.h to avoid circular deps */ typedef struct _NemoUndoTransactionClass NemoUndoTransactionClass; struct _NemoUndoTransaction { GObject parent_slot; char *operation_name; char *undo_menu_item_label; char *undo_menu_item_hint; char *redo_menu_item_label; char *redo_menu_item_hint; GList *atom_list; NemoUndoManager *owner; }; struct _NemoUndoTransactionClass { GObjectClass parent_slot; }; GType nemo_undo_transaction_get_type (void); NemoUndoTransaction *nemo_undo_transaction_new (const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint); void nemo_undo_transaction_add_atom (NemoUndoTransaction *transaction, const NemoUndoAtom *atom); void nemo_undo_transaction_add_to_undo_manager (NemoUndoTransaction *transaction, NemoUndoManager *manager); void nemo_undo_transaction_unregister_object (GObject *atom_target); void nemo_undo_transaction_undo (NemoUndoTransaction *transaction); #endif /* NEMO_UNDO_TRANSACTION_H */ nemo-4.4.2/libnemo-private/nemo-undo.c000066400000000000000000000133311357442400300176240ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-undo.c - public interface for objects that implement * undoable actions -- works across components * * Copyright (C) 2000 Eazel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Darin Adler */ #include #include "nemo-undo.h" #include "nemo-undo-private.h" #include "nemo-undo-transaction.h" #include #define NEMO_UNDO_MANAGER_DATA "Nemo undo manager" /* Register a simple undo action by calling nemo_undo_register_full. */ void nemo_undo_register (GObject *target, NemoUndoCallback callback, gpointer callback_data, GDestroyNotify callback_data_destroy_notify, const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint) { NemoUndoAtom atom; GList single_atom_list; g_return_if_fail (G_IS_OBJECT (target)); g_return_if_fail (callback != NULL); /* Make an atom. */ atom.target = target; atom.callback = callback; atom.callback_data = callback_data; atom.callback_data_destroy_notify = callback_data_destroy_notify; /* Make a single-atom list. */ single_atom_list.data = &atom; single_atom_list.next = NULL; single_atom_list.prev = NULL; /* Call the full version of the registration function, * using the undo target as the place to search for the * undo manager. */ nemo_undo_register_full (&single_atom_list, target, operation_name, undo_menu_item_label, undo_menu_item_hint, redo_menu_item_label, redo_menu_item_hint); } /* Register an undo action. */ void nemo_undo_register_full (GList *atoms, GObject *undo_manager_search_start_object, const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint) { NemoUndoTransaction *transaction; GList *p; g_return_if_fail (atoms != NULL); g_return_if_fail (G_IS_OBJECT (undo_manager_search_start_object)); /* Create an undo transaction */ transaction = nemo_undo_transaction_new (operation_name, undo_menu_item_label, undo_menu_item_hint, redo_menu_item_label, redo_menu_item_hint); for (p = atoms; p != NULL; p = p->next) { nemo_undo_transaction_add_atom (transaction, p->data); } nemo_undo_transaction_add_to_undo_manager (transaction, nemo_undo_get_undo_manager (undo_manager_search_start_object)); /* Now we are done with the transaction. * If the undo manager is holding it, then this will not destroy it. */ g_object_unref (transaction); } /* Cover for forgetting about all undo relating to a particular target. */ void nemo_undo_unregister (GObject *target) { /* Perhaps this should also unregister all children if called on a * GtkContainer? That might be handy. */ nemo_undo_transaction_unregister_object (target); } void nemo_undo (GObject *undo_manager_search_start_object) { NemoUndoManager *manager; g_return_if_fail (G_IS_OBJECT (undo_manager_search_start_object)); manager = nemo_undo_get_undo_manager (undo_manager_search_start_object); if (manager != NULL) { nemo_undo_manager_undo (manager); } } NemoUndoManager * nemo_undo_get_undo_manager (GObject *start_object) { NemoUndoManager *manager; GtkWidget *parent; GtkWindow *transient_parent; if (start_object == NULL) { return NULL; } g_return_val_if_fail (G_IS_OBJECT (start_object), NULL); /* Check for an undo manager right here. */ manager = g_object_get_data (start_object, NEMO_UNDO_MANAGER_DATA); if (manager != NULL) { return manager; } /* Check for undo manager up the parent chain. */ if (GTK_IS_WIDGET (start_object)) { parent = gtk_widget_get_parent (GTK_WIDGET (start_object)); if (parent != NULL) { manager = nemo_undo_get_undo_manager (G_OBJECT (parent)); if (manager != NULL) { return manager; } } /* Check for undo manager in our window's parent. */ if (GTK_IS_WINDOW (start_object)) { transient_parent = gtk_window_get_transient_for (GTK_WINDOW (start_object)); if (transient_parent != NULL) { manager = nemo_undo_get_undo_manager (G_OBJECT (transient_parent)); if (manager != NULL) { return manager; } } } } /* Found nothing. I can live with that. */ return NULL; } void nemo_undo_attach_undo_manager (GObject *object, NemoUndoManager *manager) { g_return_if_fail (G_IS_OBJECT (object)); if (manager == NULL) { g_object_set_data (object, NEMO_UNDO_MANAGER_DATA, NULL); } else { g_object_ref (manager); g_object_set_data_full (object, NEMO_UNDO_MANAGER_DATA, manager, g_object_unref); } } /* Copy a reference to the undo manager fromone object to another. */ void nemo_undo_share_undo_manager (GObject *destination_object, GObject *source_object) { NemoUndoManager *manager; manager = nemo_undo_get_undo_manager (source_object); nemo_undo_attach_undo_manager (destination_object, manager); } nemo-4.4.2/libnemo-private/nemo-undo.h000066400000000000000000000056151357442400300176370ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-undo.h - public interface for objects that implement * undoable actions -- works across components * * Copyright (C) 2000 Eazel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Darin Adler */ #ifndef NEMO_UNDO_H #define NEMO_UNDO_H #include typedef struct _NemoUndoTransaction NemoUndoTransaction; /* The basic undoable operation. */ typedef void (* NemoUndoCallback) (GObject *target, gpointer callback_data); /* Recipe for undo of a bit of work on an object. * Create these atoms when you want to register more * than one as a single undoable operation. */ typedef struct { GObject *target; NemoUndoCallback callback; gpointer callback_data; GDestroyNotify callback_data_destroy_notify; } NemoUndoAtom; /* Registering something that can be undone. */ void nemo_undo_register (GObject *target, NemoUndoCallback callback, gpointer callback_data, GDestroyNotify callback_data_destroy_notify, const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint); void nemo_undo_register_full (GList *atoms, GObject *undo_manager_search_start_object, const char *operation_name, const char *undo_menu_item_label, const char *undo_menu_item_hint, const char *redo_menu_item_label, const char *redo_menu_item_hint); void nemo_undo_unregister (GObject *target); /* Performing an undo explicitly. Only for use by objects "out in the field". * The menu bar itself uses a richer API in the undo manager. */ void nemo_undo (GObject *undo_manager_search_start_object); /* Connecting an undo manager. */ void nemo_undo_share_undo_manager (GObject *destination_object, GObject *source_object); #endif /* NEMO_UNDO_H */ nemo-4.4.2/libnemo-private/nemo-vfs-directory.c000066400000000000000000000100621357442400300214550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-vfs-directory.c: Subclass of NemoDirectory to help implement the virtual trash directory. Copyright (C) 1999, 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-vfs-directory.h" #include "nemo-directory-private.h" #include "nemo-file-private.h" G_DEFINE_TYPE (NemoVFSDirectory, nemo_vfs_directory, NEMO_TYPE_DIRECTORY); static void nemo_vfs_directory_init (NemoVFSDirectory *directory) { } static gboolean vfs_contains_file (NemoDirectory *directory, NemoFile *file) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); g_assert (NEMO_IS_FILE (file)); return file->details->directory == directory; } static void vfs_call_when_ready (NemoDirectory *directory, NemoFileAttributes file_attributes, gboolean wait_for_file_list, NemoDirectoryCallback callback, gpointer callback_data) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); nemo_directory_call_when_ready_internal (directory, NULL, file_attributes, wait_for_file_list, callback, NULL, callback_data); } static void vfs_cancel_callback (NemoDirectory *directory, NemoDirectoryCallback callback, gpointer callback_data) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); nemo_directory_cancel_callback_internal (directory, NULL, callback, NULL, callback_data); } static void vfs_file_monitor_add (NemoDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, NemoFileAttributes file_attributes, NemoDirectoryCallback callback, gpointer callback_data) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); g_assert (client != NULL); nemo_directory_monitor_add_internal (directory, NULL, client, monitor_hidden_files, file_attributes, callback, callback_data); } static void vfs_file_monitor_remove (NemoDirectory *directory, gconstpointer client) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); g_assert (client != NULL); nemo_directory_monitor_remove_internal (directory, NULL, client); } static void vfs_force_reload (NemoDirectory *directory) { NemoFileAttributes all_attributes; g_assert (NEMO_IS_DIRECTORY (directory)); all_attributes = nemo_file_get_all_attributes (); nemo_directory_force_reload_internal (directory, all_attributes); } static gboolean vfs_are_all_files_seen (NemoDirectory *directory) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); return directory->details->directory_loaded; } static gboolean vfs_is_not_empty (NemoDirectory *directory) { g_assert (NEMO_IS_VFS_DIRECTORY (directory)); g_assert (nemo_directory_is_anyone_monitoring_file_list (directory)); return directory->details->file_list != NULL; } static void nemo_vfs_directory_class_init (NemoVFSDirectoryClass *klass) { NemoDirectoryClass *directory_class = NEMO_DIRECTORY_CLASS (klass); directory_class->contains_file = vfs_contains_file; directory_class->call_when_ready = vfs_call_when_ready; directory_class->cancel_callback = vfs_cancel_callback; directory_class->file_monitor_add = vfs_file_monitor_add; directory_class->file_monitor_remove = vfs_file_monitor_remove; directory_class->force_reload = vfs_force_reload; directory_class->are_all_files_seen = vfs_are_all_files_seen; directory_class->is_not_empty = vfs_is_not_empty; } nemo-4.4.2/libnemo-private/nemo-vfs-directory.h000066400000000000000000000037531357442400300214730ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-vfs-directory.h: Subclass of NemoDirectory to implement the the case of a VFS directory. Copyright (C) 1999, 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_VFS_DIRECTORY_H #define NEMO_VFS_DIRECTORY_H #include #define NEMO_TYPE_VFS_DIRECTORY nemo_vfs_directory_get_type() #define NEMO_VFS_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_VFS_DIRECTORY, NemoVFSDirectory)) #define NEMO_VFS_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_VFS_DIRECTORY, NemoVFSDirectoryClass)) #define NEMO_IS_VFS_DIRECTORY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_VFS_DIRECTORY)) #define NEMO_IS_VFS_DIRECTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_VFS_DIRECTORY)) #define NEMO_VFS_DIRECTORY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_VFS_DIRECTORY, NemoVFSDirectoryClass)) typedef struct NemoVFSDirectoryDetails NemoVFSDirectoryDetails; typedef struct { NemoDirectory parent_slot; } NemoVFSDirectory; typedef struct { NemoDirectoryClass parent_slot; } NemoVFSDirectoryClass; GType nemo_vfs_directory_get_type (void); #endif /* NEMO_VFS_DIRECTORY_H */ nemo-4.4.2/libnemo-private/nemo-vfs-file.c000066400000000000000000000435231357442400300204000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-vfs-file.c: Subclass of NemoFile to help implement the virtual trash directory. Copyright (C) 1999, 2000, 2001 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #include #include "nemo-vfs-file.h" #include "nemo-directory-notify.h" #include "nemo-directory-private.h" #include "nemo-file-private.h" #include G_DEFINE_TYPE (NemoVFSFile, nemo_vfs_file, NEMO_TYPE_FILE); static void vfs_file_monitor_add (NemoFile *file, gconstpointer client, NemoFileAttributes attributes) { nemo_directory_monitor_add_internal (file->details->directory, file, client, TRUE, attributes, NULL, NULL); } static void vfs_file_monitor_remove (NemoFile *file, gconstpointer client) { nemo_directory_monitor_remove_internal (file->details->directory, file, client); } static void vfs_file_call_when_ready (NemoFile *file, NemoFileAttributes file_attributes, NemoFileCallback callback, gpointer callback_data) { nemo_directory_call_when_ready_internal (file->details->directory, file, file_attributes, FALSE, NULL, callback, callback_data); } static void vfs_file_cancel_call_when_ready (NemoFile *file, NemoFileCallback callback, gpointer callback_data) { nemo_directory_cancel_callback_internal (file->details->directory, file, NULL, callback, callback_data); } static gboolean vfs_file_check_if_ready (NemoFile *file, NemoFileAttributes file_attributes) { return nemo_directory_check_if_ready_internal (file->details->directory, file, file_attributes); } static void set_metadata_get_info_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFile *file; GFileInfo *new_info; GError *error; file = callback_data; error = NULL; new_info = g_file_query_info_finish (G_FILE (source_object), res, &error); if (new_info != NULL) { if (nemo_file_update_info (file, new_info)) { nemo_file_changed (file); } g_object_unref (new_info); } nemo_file_unref (file); if (error) { g_error_free (error); } } static void set_metadata_callback (GObject *source_object, GAsyncResult *result, gpointer callback_data) { NemoFile *file; GError *error; gboolean res; file = callback_data; error = NULL; res = g_file_set_attributes_finish (G_FILE (source_object), result, NULL, &error); if (res) { g_file_query_info_async (G_FILE (source_object), NEMO_FILE_DEFAULT_ATTRIBUTES, 0, G_PRIORITY_DEFAULT, NULL, set_metadata_get_info_callback, file); } else { nemo_file_unref (file); g_error_free (error); } } static void vfs_file_set_metadata (NemoFile *file, const char *key, const char *value) { GFileInfo *info; GFile *location; char *gio_key; info = g_file_info_new (); gio_key = g_strconcat ("metadata::", key, NULL); if (value != NULL) { g_file_info_set_attribute_string (info, gio_key, value); } else { /* Unset the key */ g_file_info_set_attribute (info, gio_key, G_FILE_ATTRIBUTE_TYPE_INVALID, NULL); } g_free (gio_key); location = nemo_file_get_location (file); g_file_set_attributes_async (location, info, 0, G_PRIORITY_DEFAULT, NULL, set_metadata_callback, nemo_file_ref (file)); g_object_unref (location); g_object_unref (info); } static void vfs_file_set_metadata_as_list (NemoFile *file, const char *key, char **value) { GFile *location; GFileInfo *info; char *gio_key; info = g_file_info_new (); gio_key = g_strconcat ("metadata::", key, NULL); g_file_info_set_attribute_stringv (info, gio_key, value); g_free (gio_key); location = nemo_file_get_location (file); g_file_set_attributes_async (location, info, 0, G_PRIORITY_DEFAULT, NULL, set_metadata_callback, nemo_file_ref (file)); g_object_unref (info); g_object_unref (location); } static gboolean vfs_file_get_item_count (NemoFile *file, guint *count, gboolean *count_unreadable) { if (count_unreadable != NULL) { *count_unreadable = file->details->directory_count_failed; } if (!file->details->got_directory_count) { if (count != NULL) { *count = 0; } return FALSE; } if (count != NULL) { *count = file->details->directory_count; } return TRUE; } static NemoRequestStatus vfs_file_get_deep_counts (NemoFile *file, guint *directory_count, guint *file_count, guint *unreadable_directory_count, guint *hidden_count, goffset *total_size) { GFileType type; if (directory_count != NULL) { *directory_count = 0; } if (file_count != NULL) { *file_count = 0; } if (unreadable_directory_count != NULL) { *unreadable_directory_count = 0; } if (total_size != NULL) { *total_size = 0; } if (hidden_count != NULL) { *hidden_count = 0; } if (!nemo_file_is_directory (file)) { return NEMO_REQUEST_DONE; } if (file->details->deep_counts_status != NEMO_REQUEST_NOT_STARTED) { if (directory_count != NULL) { *directory_count = file->details->deep_directory_count; } if (file_count != NULL) { *file_count = file->details->deep_file_count; } if (unreadable_directory_count != NULL) { *unreadable_directory_count = file->details->deep_unreadable_count; } if (total_size != NULL) { *total_size = file->details->deep_size; } if (hidden_count != NULL) { *hidden_count = file->details->deep_hidden_count; } return file->details->deep_counts_status; } /* For directories, or before we know the type, we haven't started. */ type = nemo_file_get_file_type (file); if (type == G_FILE_TYPE_UNKNOWN || type == G_FILE_TYPE_DIRECTORY) { return NEMO_REQUEST_NOT_STARTED; } /* For other types, we are done, and the zeros are permanent. */ return NEMO_REQUEST_DONE; } static gboolean vfs_file_get_date (NemoFile *file, NemoDateType date_type, time_t *date) { switch (date_type) { case NEMO_DATE_TYPE_CHANGED: /* Before we have info on a file, the date is unknown. */ if (file->details->ctime == 0) { return FALSE; } if (date != NULL) { *date = file->details->ctime; } return TRUE; case NEMO_DATE_TYPE_ACCESSED: /* Before we have info on a file, the date is unknown. */ if (file->details->atime == 0) { return FALSE; } if (date != NULL) { *date = file->details->atime; } return TRUE; case NEMO_DATE_TYPE_MODIFIED: /* Before we have info on a file, the date is unknown. */ if (file->details->mtime == 0) { return FALSE; } if (date != NULL) { *date = file->details->mtime; } return TRUE; case NEMO_DATE_TYPE_CREATED: /* Before we have info on a file, the date is unknown. */ if (file->details->btime == 0) { return FALSE; } if (date != NULL) { *date = file->details->btime; } return TRUE; case NEMO_DATE_TYPE_TRASHED: /* Before we have info on a file, the date is unknown. */ if (file->details->trash_time == 0) { return FALSE; } if (date != NULL) { *date = file->details->trash_time; } return TRUE; case NEMO_DATE_TYPE_PERMISSIONS_CHANGED: /* Before we have info on a file, the date is unknown. */ if (file->details->mtime == 0 || file->details->ctime == 0) { return FALSE; } /* mtime is when the contents changed; ctime is when the * contents or the permissions (inc. owner/group) changed. * So we can only know when the permissions changed if mtime * and ctime are different. */ if (file->details->mtime == file->details->ctime) { return FALSE; } if (date != NULL) { *date = file->details->ctime; } return TRUE; default: break; } return FALSE; } static char * vfs_file_get_where_string (NemoFile *file) { GFile *activation_location; NemoFile *location; char *where_string; if (!nemo_file_is_in_recent (file)) { location = nemo_file_ref (file); } else { activation_location = nemo_file_get_activation_location (file); location = nemo_file_get (activation_location); g_object_unref (activation_location); } where_string = nemo_file_get_parent_uri_for_display (location); nemo_file_unref (location); return where_string; } static void vfs_file_mount_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; GFile *mounted_on; GError *error; op = callback_data; error = NULL; mounted_on = g_file_mount_mountable_finish (G_FILE (source_object), res, &error); nemo_file_operation_complete (op, mounted_on, error); if (mounted_on) { g_object_unref (mounted_on); } if (error) { g_error_free (error); } } static void vfs_file_mount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GError *error; GFile *location; if (file->details->type != G_FILE_TYPE_MOUNTABLE) { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be mounted")); callback (file, NULL, error, callback_data); g_error_free (error); } return; } op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } location = nemo_file_get_location (file); g_file_mount_mountable (location, 0, mount_op, op->cancellable, vfs_file_mount_callback, op); g_object_unref (location); } static void vfs_file_unmount_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean unmounted; GError *error; op = callback_data; error = NULL; unmounted = g_file_unmount_mountable_with_operation_finish (G_FILE (source_object), res, &error); if (!unmounted && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, G_FILE (source_object), error); if (error) { g_error_free (error); } } static void vfs_file_unmount (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GFile *location; op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } location = nemo_file_get_location (file); g_file_unmount_mountable_with_operation (location, G_MOUNT_UNMOUNT_NONE, mount_op, op->cancellable, vfs_file_unmount_callback, op); g_object_unref (location); } static void vfs_file_eject_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean ejected; GError *error; op = callback_data; error = NULL; ejected = g_file_eject_mountable_with_operation_finish (G_FILE (source_object), res, &error); if (!ejected && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, G_FILE (source_object), error); if (error) { g_error_free (error); } } static void vfs_file_eject (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GFile *location; op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } location = nemo_file_get_location (file); g_file_eject_mountable_with_operation (location, G_MOUNT_UNMOUNT_NONE, mount_op, op->cancellable, vfs_file_eject_callback, op); g_object_unref (location); } static void vfs_file_start_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean started; GError *error; op = callback_data; error = NULL; started = g_file_start_mountable_finish (G_FILE (source_object), res, &error); if (!started && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, G_FILE (source_object), error); if (error) { g_error_free (error); } } static void vfs_file_start (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GError *error; GFile *location; if (file->details->type != G_FILE_TYPE_MOUNTABLE) { if (callback) { error = NULL; g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This file cannot be started")); callback (file, NULL, error, callback_data); g_error_free (error); } return; } op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } location = nemo_file_get_location (file); g_file_start_mountable (location, 0, mount_op, op->cancellable, vfs_file_start_callback, op); g_object_unref (location); } static void vfs_file_stop_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean stopped; GError *error; op = callback_data; error = NULL; stopped = g_file_stop_mountable_finish (G_FILE (source_object), res, &error); if (!stopped && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, G_FILE (source_object), error); if (error) { g_error_free (error); } } static void vfs_file_stop (NemoFile *file, GMountOperation *mount_op, GCancellable *cancellable, NemoFileOperationCallback callback, gpointer callback_data) { NemoFileOperation *op; GFile *location; op = nemo_file_operation_new (file, callback, callback_data); if (cancellable) { g_object_unref (op->cancellable); op->cancellable = g_object_ref (cancellable); } location = nemo_file_get_location (file); g_file_stop_mountable (location, G_MOUNT_UNMOUNT_NONE, mount_op, op->cancellable, vfs_file_stop_callback, op); g_object_unref (location); } static void vfs_file_poll_callback (GObject *source_object, GAsyncResult *res, gpointer callback_data) { NemoFileOperation *op; gboolean stopped; GError *error; op = callback_data; error = NULL; stopped = g_file_poll_mountable_finish (G_FILE (source_object), res, &error); if (!stopped && error->domain == G_IO_ERROR && (error->code == G_IO_ERROR_FAILED_HANDLED || error->code == G_IO_ERROR_CANCELLED)) { g_error_free (error); error = NULL; } nemo_file_operation_complete (op, G_FILE (source_object), error); if (error) { g_error_free (error); } } static void vfs_file_poll_for_media (NemoFile *file) { NemoFileOperation *op; GFile *location; op = nemo_file_operation_new (file, NULL, NULL); location = nemo_file_get_location (file); g_file_poll_mountable (location, op->cancellable, vfs_file_poll_callback, op); g_object_unref (location); } static void nemo_vfs_file_init (NemoVFSFile *file) { } static void nemo_vfs_file_class_init (NemoVFSFileClass *klass) { NemoFileClass *file_class = NEMO_FILE_CLASS (klass); file_class->monitor_add = vfs_file_monitor_add; file_class->monitor_remove = vfs_file_monitor_remove; file_class->call_when_ready = vfs_file_call_when_ready; file_class->cancel_call_when_ready = vfs_file_cancel_call_when_ready; file_class->check_if_ready = vfs_file_check_if_ready; file_class->get_item_count = vfs_file_get_item_count; file_class->get_deep_counts = vfs_file_get_deep_counts; file_class->get_date = vfs_file_get_date; file_class->get_where_string = vfs_file_get_where_string; file_class->set_metadata = vfs_file_set_metadata; file_class->set_metadata_as_list = vfs_file_set_metadata_as_list; file_class->mount = vfs_file_mount; file_class->unmount = vfs_file_unmount; file_class->eject = vfs_file_eject; file_class->start = vfs_file_start; file_class->stop = vfs_file_stop; file_class->poll_for_media = vfs_file_poll_for_media; } nemo-4.4.2/libnemo-private/nemo-vfs-file.h000066400000000000000000000035321357442400300204010ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-vfs-file.h: Subclass of NemoFile to implement the the case of a VFS file. Copyright (C) 1999, 2000 Eazel, 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Darin Adler */ #ifndef NEMO_VFS_FILE_H #define NEMO_VFS_FILE_H #include #define NEMO_TYPE_VFS_FILE nemo_vfs_file_get_type() #define NEMO_VFS_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_VFS_FILE, NemoVFSFile)) #define NEMO_VFS_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_VFS_FILE, NemoVFSFileClass)) #define NEMO_IS_VFS_FILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_VFS_FILE)) #define NEMO_IS_VFS_FILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_VFS_FILE)) #define NEMO_VFS_FILE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_VFS_FILE, NemoVFSFileClass)) typedef struct NemoVFSFileDetails NemoVFSFileDetails; typedef struct { NemoFile parent_slot; } NemoVFSFile; typedef struct { NemoFileClass parent_slot; } NemoVFSFileClass; GType nemo_vfs_file_get_type (void); #endif /* NEMO_VFS_FILE_H */ nemo-4.4.2/libnemo-private/nemo-widget-action.c000066400000000000000000000200551357442400300214160ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #include "nemo-widget-action.h" #include "nemo-widget-menu-item.h" G_DEFINE_TYPE (NemoWidgetAction, nemo_widget_action, GTK_TYPE_ACTION); static void nemo_widget_action_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void nemo_widget_action_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void nemo_widget_action_constructed (GObject *object); static void nemo_widget_action_finalize (GObject *gobject); static void nemo_widget_action_dispose (GObject *gobject); static GtkWidget *create_menu_item (GtkAction *action); static GtkWidget *create_tool_item (GtkAction *action); static gpointer parent_class; enum { PROP_0, PROP_WIDGET_A, PROP_WIDGET_B }; static void nemo_widget_action_init (NemoWidgetAction *action) { action->widget_a = NULL; action->widget_b = NULL; action->a_used = FALSE; action->b_used = FALSE; } static void nemo_widget_action_class_init (NemoWidgetActionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkActionClass *action_class = GTK_ACTION_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = nemo_widget_action_finalize; object_class->dispose = nemo_widget_action_dispose; object_class->set_property = nemo_widget_action_set_property; object_class->get_property = nemo_widget_action_get_property; object_class->constructed = nemo_widget_action_constructed; action_class->create_menu_item = create_menu_item; action_class->create_tool_item = create_tool_item; action_class->menu_item_type = NEMO_TYPE_WIDGET_MENU_ITEM; action_class->toolbar_item_type = G_TYPE_NONE; g_object_class_install_property (object_class, PROP_WIDGET_A, g_param_spec_object ("widget-a", "The widget A for this action", "The widget to use for this action", GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); g_object_class_install_property (object_class, PROP_WIDGET_B, g_param_spec_object ("widget-b", "The widget B for this action", "The widget to use for this action", GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); } void nemo_widget_action_constructed (GObject *object) { G_OBJECT_CLASS (parent_class)->constructed (object); } GtkAction * nemo_widget_action_new (const gchar *name, GtkWidget *widget_a, GtkWidget *widget_b) { return g_object_new (NEMO_TYPE_WIDGET_ACTION, "name", name, "widget-a", widget_a, "widget-b", widget_b, NULL); } static void nemo_widget_action_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } static void nemo_widget_action_dispose (GObject *object) { NemoWidgetAction *action = NEMO_WIDGET_ACTION (object); if (action->widget_a) { g_object_unref (action->widget_a); nemo_widget_action_set_widget_a (action, NULL); } if (action->widget_b) { g_object_unref (action->widget_b); nemo_widget_action_set_widget_b (action, NULL); } G_OBJECT_CLASS (parent_class)->dispose (object); } static void nemo_widget_action_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoWidgetAction *action; action = NEMO_WIDGET_ACTION (object); switch (prop_id) { case PROP_WIDGET_A: nemo_widget_action_set_widget_a (action, g_value_get_object (value)); break; case PROP_WIDGET_B: action->widget_b = g_value_get_object (value); g_object_ref_sink (action->widget_b); g_object_notify (G_OBJECT (action), "widget-b"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_widget_action_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NemoWidgetAction *action; action = NEMO_WIDGET_ACTION (object); switch (prop_id) { case PROP_WIDGET_A: g_value_set_object (value, action->widget_a); break; case PROP_WIDGET_B: g_value_set_object (value, action->widget_b); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GtkWidget * create_menu_item (GtkAction *action) { NemoWidgetAction *widget_action; GType menu_item_type; GtkWidget *w, *ret; gint slot; widget_action = NEMO_WIDGET_ACTION (action); menu_item_type = GTK_ACTION_GET_CLASS (action)->menu_item_type; if (!widget_action->a_used) { w = widget_action->widget_a; widget_action->a_used = TRUE; slot = ACTION_SLOT_A; } else if (!widget_action->b_used) { w = widget_action->widget_b; widget_action->b_used = TRUE; slot = ACTION_SLOT_B; } else return NULL; ret = g_object_new (menu_item_type, "child-widget", w, "action-slot", slot, NULL); gtk_activatable_set_related_action (GTK_ACTIVATABLE (ret), action); return ret; } static GtkWidget * create_tool_item (GtkAction *action) { g_warning ("NemoWidgetAction: Toolbar items unsupported at this time."); return NULL; } void nemo_widget_action_activate (NemoWidgetAction *action) { } GtkWidget * nemo_widget_action_get_widget_a (NemoWidgetAction *action) { if (action->widget_a) return action->widget_a; else return NULL; } void nemo_widget_action_set_widget_a (NemoWidgetAction *action, GtkWidget *widget) { action->widget_a = widget; if (widget) g_object_ref_sink (action->widget_a); g_object_notify (G_OBJECT (action), "widget-a"); } GtkWidget * nemo_widget_action_get_widget_b (NemoWidgetAction *action) { if (action->widget_b) return action->widget_b; else return NULL; } void nemo_widget_action_set_widget_b (NemoWidgetAction *action, GtkWidget *widget) { action->widget_b = widget; if (widget) g_object_ref_sink (action->widget_b); g_object_notify (G_OBJECT (action), "widget-b"); } nemo-4.4.2/libnemo-private/nemo-widget-action.h000066400000000000000000000051401357442400300214210ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- 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 - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef NEMO_WIDGET_ACTION_H #define NEMO_WIDGET_ACTION_H #include #include #define NEMO_TYPE_WIDGET_ACTION nemo_widget_action_get_type() #define NEMO_WIDGET_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_WIDGET_ACTION, NemoWidgetAction)) #define NEMO_WIDGET_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_WIDGET_ACTION, NemoWidgetActionClass)) #define NEMO_IS_WIDGET_ACTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_WIDGET_ACTION)) #define NEMO_IS_WIDGET_ACTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_WIDGET_ACTION)) #define NEMO_WIDGET_ACTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_WIDGET_ACTION, NemoWidgetActionClass)) typedef struct _NemoWidgetAction NemoWidgetAction; typedef struct _NemoWidgetActionClass NemoWidgetActionClass; struct _NemoWidgetAction { GtkAction parent; GtkWidget *widget_a; GtkWidget *widget_b; gboolean a_used; gboolean b_used; }; struct _NemoWidgetActionClass { GtkActionClass parent_class; }; enum { ACTION_SLOT_A = 0, ACTION_SLOT_B }; GType nemo_widget_action_get_type (void); GtkAction *nemo_widget_action_new (const gchar *name, GtkWidget *widget_a, GtkWidget *widget_b); void nemo_widget_action_activate (NemoWidgetAction *action); GtkWidget * nemo_widget_action_get_widget_a (NemoWidgetAction *action); void nemo_widget_action_set_widget_a (NemoWidgetAction *action, GtkWidget *widget); GtkWidget * nemo_widget_action_get_widget_b (NemoWidgetAction *action); void nemo_widget_action_set_widget_b (NemoWidgetAction *action, GtkWidget *widget); #endif /* NEMO_WIDGET_ACTION_H */ nemo-4.4.2/libnemo-private/nemo-widget-menu-item.c000066400000000000000000000477731357442400300220610ustar00rootroot00000000000000/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * 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, see . */ #include "nemo-widget-menu-item.h" #include "nemo-widget-action.h" #include enum { PROP_0, PROP_CHILD_WIDGET, PROP_ACTION_SLOT, PROP_ACTIVATABLE_RELATED_ACTION, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, }; static GtkActivatableIface *parent_activatable_iface; static void nemo_widget_menu_item_dispose (GObject *object); static void nemo_widget_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void nemo_widget_menu_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void nemo_widget_menu_item_activatable_interface_init (GtkActivatableIface *iface); static void nemo_widget_menu_item_update (GtkActivatable *activatable, GtkAction *action, const gchar *property_name); static void nemo_widget_menu_item_sync_action_properties (GtkActivatable *activatable, GtkAction *action); static void nemo_widget_menu_item_set_related_action (NemoWidgetMenuItem *menu_item, GtkAction *action); static void nemo_widget_menu_item_set_use_action_appearance (NemoWidgetMenuItem *widget_menu_item, gboolean use_appearance); static gboolean activatable_update_child_widget (NemoWidgetMenuItem *widget_menu_item, GtkAction *action); static gboolean nemo_widget_menu_item_draw (GtkWidget *widget, cairo_t *cr); static void nemo_widget_menu_item_realize (GtkWidget *widget); static void nemo_widget_menu_item_unrealize (GtkWidget *widget); static void nemo_widget_menu_item_map (GtkWidget *widget); static void nemo_widget_menu_item_unmap (GtkWidget *widget); static void nemo_widget_menu_item_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void nemo_widget_menu_item_activate (GtkMenuItem *menu_item); G_DEFINE_TYPE_WITH_CODE (NemoWidgetMenuItem, nemo_widget_menu_item, GTK_TYPE_MENU_ITEM, G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, nemo_widget_menu_item_activatable_interface_init)); static void nemo_widget_menu_item_class_init (NemoWidgetMenuItemClass *klass) { GObjectClass *gobject_class = (GObjectClass*) klass; GtkWidgetClass *widget_class = (GtkWidgetClass*) klass; GtkMenuItemClass *menu_item_class = (GtkMenuItemClass*) klass; gobject_class->dispose = nemo_widget_menu_item_dispose; gobject_class->set_property = nemo_widget_menu_item_set_property; gobject_class->get_property = nemo_widget_menu_item_get_property; menu_item_class->activate = nemo_widget_menu_item_activate; widget_class->realize = nemo_widget_menu_item_realize; widget_class->unrealize = nemo_widget_menu_item_unrealize; widget_class->map = nemo_widget_menu_item_map; widget_class->unmap = nemo_widget_menu_item_unmap; widget_class->size_allocate = nemo_widget_menu_item_size_allocate; widget_class->draw = nemo_widget_menu_item_draw; /** * NemoWidgetMenuItem:widget: * * Child widget to use in place of a label. * */ g_object_class_install_property (gobject_class, PROP_CHILD_WIDGET, g_param_spec_object ("child-widget", "Child widget", "Child widget to appear next to the menu text", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); /** * NemoWidgetMenuItem:action-slot: * * The action widget slot the child-widget came from. * */ g_object_class_install_property (gobject_class, PROP_ACTION_SLOT, g_param_spec_int ("action-slot", "Action slot", "The action's widget slot child-widget came from", -1, 1, -1, G_PARAM_READWRITE) ); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action"); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance"); } static void nemo_widget_menu_item_init (NemoWidgetMenuItem *item) { item->child_widget = NULL; item->action_slot = -1; } static void nemo_widget_menu_item_dispose (GObject *object) { NemoWidgetMenuItem *widget_menu_item = NEMO_WIDGET_MENU_ITEM (object); if (widget_menu_item->related_action) { gtk_action_disconnect_accelerator (widget_menu_item->related_action); nemo_widget_menu_item_set_related_action (widget_menu_item, NULL); widget_menu_item->related_action = NULL; } G_OBJECT_CLASS (nemo_widget_menu_item_parent_class)->dispose (object); } static void nemo_widget_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoWidgetMenuItem *widget_menu_item = NEMO_WIDGET_MENU_ITEM (object); switch (prop_id) { case PROP_CHILD_WIDGET: nemo_widget_menu_item_set_child_widget (widget_menu_item, (GtkWidget *) g_value_get_object (value)); break; case PROP_ACTION_SLOT: widget_menu_item->action_slot = g_value_get_int (value); break; case PROP_ACTIVATABLE_RELATED_ACTION: nemo_widget_menu_item_set_related_action (widget_menu_item, g_value_get_object (value)); break; case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: nemo_widget_menu_item_set_use_action_appearance (widget_menu_item, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_widget_menu_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NemoWidgetMenuItem *widget_menu_item = NEMO_WIDGET_MENU_ITEM (object); switch (prop_id) { case PROP_CHILD_WIDGET: g_value_set_object (value, nemo_widget_menu_item_get_child_widget (widget_menu_item)); break; case PROP_ACTION_SLOT: g_value_set_int (value, widget_menu_item->action_slot); break; case PROP_ACTIVATABLE_RELATED_ACTION: g_value_set_object (value, widget_menu_item->related_action); break; case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: g_value_set_boolean (value, widget_menu_item->use_action_appearance); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_widget_menu_item_activatable_interface_init (GtkActivatableIface *iface) { parent_activatable_iface = g_type_interface_peek_parent (iface); iface->update = nemo_widget_menu_item_update; iface->sync_action_properties = nemo_widget_menu_item_sync_action_properties; } static gboolean activatable_update_child_widget (NemoWidgetMenuItem *widget_menu_item, GtkAction *action) { GtkWidget *widget, *action_widget; NemoWidgetAction *widget_action = NEMO_WIDGET_ACTION (action); widget = nemo_widget_menu_item_get_child_widget (widget_menu_item); if (widget_menu_item->action_slot == ACTION_SLOT_A) { action_widget = nemo_widget_action_get_widget_a (widget_action); } else if (widget_menu_item->action_slot == ACTION_SLOT_B) { action_widget = nemo_widget_action_get_widget_b (widget_action); } else return FALSE; if (widget && action_widget && (widget == action_widget)) { return FALSE; } if (action_widget) { nemo_widget_menu_item_set_child_widget (widget_menu_item, action_widget); return TRUE; } if (!action_widget) { nemo_widget_menu_item_set_child_widget (widget_menu_item, NULL); return TRUE; } return FALSE; } static void nemo_widget_menu_item_update (GtkActivatable *activatable, GtkAction *action, const gchar *property_name) { NemoWidgetMenuItem *widget_menu_item; widget_menu_item = NEMO_WIDGET_MENU_ITEM (activatable); if (!gtk_activatable_get_use_action_appearance (activatable)) return; if (strcmp (property_name, "widget-a") == 0) activatable_update_child_widget (widget_menu_item, action); else if (strcmp (property_name, "widget-b") == 0) activatable_update_child_widget (widget_menu_item, action); } static void nemo_widget_menu_item_sync_action_properties (GtkActivatable *activatable, GtkAction *action) { NemoWidgetMenuItem *widget_menu_item; GtkWidget *widget; widget_menu_item = NEMO_WIDGET_MENU_ITEM (activatable); // parent_activatable_iface->sync_action_properties (activatable, action); if (!action) return; if (!gtk_activatable_get_use_action_appearance (activatable)) return; widget = nemo_widget_menu_item_get_child_widget (widget_menu_item); if (widget && !GTK_IS_WIDGET (widget)) { nemo_widget_menu_item_set_child_widget (widget_menu_item, NULL); widget = NULL; } activatable_update_child_widget (widget_menu_item, action); gtk_widget_show (GTK_WIDGET (widget_menu_item)); } static void nemo_widget_menu_item_set_related_action (NemoWidgetMenuItem *widget_menu_item, GtkAction *action) { if (widget_menu_item->related_action == action) return; if (widget_menu_item->related_action) { gtk_action_disconnect_accelerator (widget_menu_item->related_action); } if (action) { const gchar *accel_path; accel_path = gtk_action_get_accel_path (action); if (accel_path) { gtk_action_connect_accelerator (action); gtk_menu_item_set_accel_path (GTK_MENU_ITEM (widget_menu_item), accel_path); } } gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (widget_menu_item), action); nemo_widget_menu_item_sync_action_properties (GTK_ACTIVATABLE (widget_menu_item), action); widget_menu_item->related_action = action; } static void nemo_widget_menu_item_set_use_action_appearance (NemoWidgetMenuItem *widget_menu_item, gboolean use_appearance) { if (widget_menu_item->use_action_appearance != use_appearance) { widget_menu_item->use_action_appearance = use_appearance; gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (widget_menu_item), widget_menu_item->related_action); } } static void nemo_widget_menu_item_activate (GtkMenuItem *menu_item) { } static gboolean nemo_widget_menu_item_draw (GtkWidget *widget, cairo_t *cr) { return GTK_WIDGET_CLASS (g_type_class_peek_parent (nemo_widget_menu_item_parent_class))->draw (widget, cr); } static void nemo_widget_menu_item_realize (GtkWidget *widget) { GTK_WIDGET_CLASS (g_type_class_peek_parent (nemo_widget_menu_item_parent_class))->realize (widget); } static void nemo_widget_menu_item_unrealize (GtkWidget *widget) { GTK_WIDGET_CLASS (g_type_class_peek_parent (nemo_widget_menu_item_parent_class))->unrealize (widget); } static void nemo_widget_menu_item_map (GtkWidget *widget) { GTK_WIDGET_CLASS (g_type_class_peek_parent (nemo_widget_menu_item_parent_class))->map (widget); } static void nemo_widget_menu_item_unmap (GtkWidget *widget) { GTK_WIDGET_CLASS (g_type_class_peek_parent (nemo_widget_menu_item_parent_class))->unmap (widget); } static void get_arrow_size (GtkWidget *widget, GtkWidget *child, gint *size, gint *spacing) { PangoContext *context; PangoFontMetrics *metrics; gfloat arrow_scaling; gint arrow_spacing; g_assert (size); gtk_widget_style_get (widget, "arrow-scaling", &arrow_scaling, "arrow-spacing", &arrow_spacing, NULL); if (spacing != NULL) *spacing = arrow_spacing; context = gtk_widget_get_pango_context (child); metrics = pango_context_get_metrics (context, pango_context_get_font_description (context), pango_context_get_language (context)); *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics))); pango_font_metrics_unref (metrics); *size = *size * arrow_scaling; } static gint get_toggle_size (GtkMenuItem *menu_item) { NemoWidgetMenuItem *widget_menu_item = NEMO_WIDGET_MENU_ITEM (menu_item); GtkPackDirection pack_dir; GtkWidget *parent; gint req = 0; GtkWidget *widget = GTK_WIDGET (menu_item); parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU_BAR (parent)) pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); else pack_dir = GTK_PACK_DIRECTION_LTR; if (widget_menu_item->child_widget && gtk_widget_get_visible (widget_menu_item->child_widget)) { gint icon_size; guint toggle_spacing; gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, NULL); gtk_widget_style_get (GTK_WIDGET (menu_item), "toggle-spacing", &toggle_spacing, NULL); if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) { if (icon_size > 0) req = icon_size + toggle_spacing; } else { if (icon_size > 0) req = icon_size + toggle_spacing; } } return req; } static void nemo_widget_menu_item_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkBin *bin; GtkAllocation child_allocation; GtkTextDirection direction; GtkPackDirection child_pack_dir; GtkWidget *child; GtkWidget *parent; g_return_if_fail (GTK_IS_MENU_ITEM (widget)); g_return_if_fail (allocation != NULL); bin = GTK_BIN (widget); direction = gtk_widget_get_direction (widget); parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU_BAR (parent)) { child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); } else { child_pack_dir = GTK_PACK_DIRECTION_LTR; } gtk_widget_set_allocation (widget, allocation); child = gtk_bin_get_child (bin); if (child) { GtkStyleContext *context; GtkStateFlags state; GtkBorder padding; guint border_width; gint toggle_size; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_get_padding (context, state, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); child_allocation.x = border_width + padding.left; child_allocation.y = border_width + padding.top; child_allocation.width = allocation->width - (border_width * 2) - padding.left - padding.right; child_allocation.height = allocation->height - (border_width * 2) - padding.top - padding.bottom; toggle_size = get_toggle_size (GTK_MENU_ITEM (widget)); if (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL) { if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL)) child_allocation.x += toggle_size; child_allocation.width -= toggle_size; } else { if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT)) child_allocation.y += toggle_size; child_allocation.height -= toggle_size; } child_allocation.x += allocation->x; child_allocation.y += allocation->y; if ((gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)) && !GTK_IS_MENU_BAR (parent)) || gtk_menu_item_get_reserve_indicator (GTK_MENU_ITEM (widget))) { gint arrow_spacing, arrow_size; get_arrow_size (widget, child, &arrow_size, &arrow_spacing); if (direction == GTK_TEXT_DIR_RTL) child_allocation.x += arrow_size + arrow_spacing; child_allocation.width -= arrow_size + arrow_spacing; } if (child_allocation.width < 1) child_allocation.width = 1; gtk_widget_size_allocate (child, &child_allocation); } if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget))) gtk_menu_reposition (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))); } /** * nemo_widget_menu_item_new: * @widget: The custom widget to use * * Creates a new #NemoWidgetMenuItem. * * Returns: a new #NemoWidgetMenuItem. */ GtkWidget * nemo_widget_menu_item_new (GtkWidget *widget) { return g_object_new (NEMO_TYPE_WIDGET_MENU_ITEM, "widget", widget, NULL); } /** * nemo_widget_menu_item_set_child_widget: * @widget_menu_item: a #GtkNemoWidgetMenuItem. * @widget: (allow-none): a widget to set as the child widget for the menu item. * * Sets the child-widget of @widget_menu_item to the given widget. * */ void nemo_widget_menu_item_set_child_widget (NemoWidgetMenuItem *widget_menu_item, GtkWidget *widget) { g_return_if_fail (NEMO_IS_WIDGET_MENU_ITEM (widget_menu_item)); GtkWidget *old_w; old_w = gtk_bin_get_child (GTK_BIN (widget_menu_item)); if (widget == widget_menu_item->child_widget && widget == old_w) return; if (old_w) gtk_container_remove (GTK_CONTAINER (widget_menu_item), old_w); widget_menu_item->child_widget = widget; if (widget == NULL) return; if (!gtk_widget_get_parent (widget)) gtk_container_add (GTK_CONTAINER (widget_menu_item), widget); g_object_set (widget, "visible", TRUE, NULL); g_object_notify (G_OBJECT (widget_menu_item), "child-widget"); } /** * nemo_widget_menu_item_get_child_widget: * @widget_menu_item: a #NemoWidgetMenuItem * * Gets the widget that is currently set as the child-widget of @widget_menu_item. * See nemo_widget_menu_item_set_child_widget(). * * Returns: (transfer none): the widget set as child-widget of @widget_menu_item * * Deprecated: 3.10 **/ GtkWidget* nemo_widget_menu_item_get_child_widget (NemoWidgetMenuItem *widget_menu_item) { g_return_val_if_fail (NEMO_IS_WIDGET_MENU_ITEM (widget_menu_item), NULL); return widget_menu_item->child_widget; } nemo-4.4.2/libnemo-private/nemo-widget-menu-item.h000066400000000000000000000053031357442400300220450ustar00rootroot00000000000000/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * 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, see . */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #ifndef __NEMO_WIDGET_MENU_ITEM_H__ #define __NEMO_WIDGET_MENU_ITEM_H__ #include G_BEGIN_DECLS #define NEMO_TYPE_WIDGET_MENU_ITEM (nemo_widget_menu_item_get_type ()) #define NEMO_WIDGET_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_WIDGET_MENU_ITEM, NemoWidgetMenuItem)) #define NEMO_WIDGET_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_WIDGET_MENU_ITEM, NemoWidgetMenuItemClass)) #define NEMO_IS_WIDGET_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_WIDGET_MENU_ITEM)) #define NEMO_IS_WIDGET_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_WIDGET_MENU_ITEM)) #define NEMO_WIDGET_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_WIDGET_MENU_ITEM, NemoWidgetMenuItemClass)) typedef struct _NemoWidgetMenuItem NemoWidgetMenuItem; typedef struct _NemoWidgetMenuItemClass NemoWidgetMenuItemClass; struct _NemoWidgetMenuItem { GtkMenuItem menu_item; GtkWidget *child_widget; gint action_slot; /* GtkActivatable */ GtkAction *related_action; gboolean use_action_appearance; }; /** * NemoWidgetMenuItemClass: * @parent_class: The parent class. */ struct _NemoWidgetMenuItemClass { GtkMenuItemClass parent_class; }; GType nemo_widget_menu_item_get_type (void) G_GNUC_CONST; GtkWidget* nemo_widget_menu_item_new (GtkWidget *widget); void nemo_widget_menu_item_set_child_widget (NemoWidgetMenuItem *widget_menu_item, GtkWidget *widget); GtkWidget* nemo_widget_menu_item_get_child_widget (NemoWidgetMenuItem *widget_menu_item); G_END_DECLS #endif /* __NEMO_WIDGET_MENU_ITEM_H__ */ nemo-4.4.2/libnemo-private/org.nemo.gschema.xml000066400000000000000000001212411357442400300214330ustar00rootroot00000000000000 'after-current-tab' Where to position newly open tabs in browser windows. If set to "after-current-tab", then new tabs are inserted after the current tab. If set to "end", then new tabs are appended to the end of the tab list. true Enables the classic Nemo behavior, where all windows are browsers If set to true, then all Nemo windows will be browser windows. This is how Nemo used to behave before version 2.6, and some people prefer this behavior. false Enables renaming of icons by two times clicking with pause between clicks If set to true, then icons in all Nemo windows will be able to get renamed quickly. Users should click two times on icons with a pause time more than double-click time of their system. false Show the location entry by default If set to true, then Nemo browser windows will show a textual input entry for the location toolbar. true Show Previous button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show Next button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show Up button in nemo toolbar If set to true, then Nemo browser windows will show the button. false Show refresh button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show toggle button location entry/pathbar If set to true, then Nemo browser windows will show the button. false Show Home button in nemo toolbar If set to true, then Nemo browser windows will show the button. false Show Computer button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show Search button in nemo toolbar If set to true, then Nemo browser windows will show the button. false Show new folder button in nemo toolbar If set to true, then Nemo browser windows will show the button. false Show open in terminal in the nemo toolbar If set to true, then Nemo browser windows will show the button. true Show Icon View button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show List View button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show Compact View button in nemo toolbar If set to true, then Nemo browser windows will show the button. false Show Thumbnails button in nemo toolbar If set to true, then Nemo browser windows will show the button. true Show warning when opening as root If set to true, then Nemo show warning message when run Nemo as root user. false Whether to ask for confirmation when moving files to Trash If set to true, then Nemo will ask for confirmation when you attempt to move files to the Trash. true Whether to ask for confirmation when deleting files, or emptying Trash If set to true, then Nemo will ask for confirmation when you attempt to delete files, or empty the Trash. true Whether to enable immediate deletion If set to true, then Nemo will have a feature allowing you to delete a file immediately and in-place, instead of moving it to the trash. This feature can be dangerous, so use caution. false Whether to swap the hotkeys for Trash and Delete If set to true, the Delete key will permanently delete a file, and the Shift-Delete key will only trash a file. 'local-only' When to show number of items in a folder Speed tradeoff for when to show the number of items in a folder. If set to "always" then always show item counts, even if the folder is on a remote server. If set to "local-only" then only show counts for local file systems. If set to "never" then never bother to compute item counts. 'double' Type of click used to launch/open files Possible values are "single" to launch files on a single click, or "double" to launch them on a double click. 'ask' What to do with executable text files when activated What to do with executable text files when they are activated (single or double clicked). Possible values are "launch" to launch them as programs, "ask" to ask what to do via a dialog, and "display" to display them as text files. true Use extra mouse button events in Nemo' browser window For users with mice that have "Forward" and "Back" buttons, this key will determine if any action is taken inside of Nemo when either is pressed. 9 Mouse button to activate the "Forward" command in browser window For users with mice that have buttons for "Forward" and "Back", this key will set which button activates the "Forward" command in a browser window. Possible values range between 6 and 14. 8 Mouse button to activate the "Back" command in browser window For users with mice that have buttons for "Forward" and "Back", this key will set which button activates the "Back" command in a browser window. Possible values range between 6 and 14. 'local-only' When to show thumbnails of image files Speed tradeoff for when to show an image file as a thumbnail. If set to "always" then always thumbnail, even if the folder is on a remote server. If set to "local-only" then only show thumbnails for local file systems. If set to "never" then never bother to thumbnail images, just use a generic icon. false Inherit thumbnail visibility from parent If set, folders will inherit their thumbnail visibility from their parents 1048576 Maximum image size for thumbnailing Images over this size (in bytes) won't be thumbnailed. The purpose of this setting is to avoid thumbnailing large images that may take a long time to load or use lots of memory. false Show advanced permissions in the file property dialog If set to true, then Nemo lets you edit and display file permissions in a more unix-like way, accessing some more esoteric options. true Show folders first in windows If set to true, then Nemo shows folders prior to showing files in the icon and list views. 'name' Default sort order The default sort-order for items in the icon view. Possible values are "name", "size", "type" and "mtime". false Reverse sort order in new windows If true, files in new windows will be sorted in reverse order. ie, if sorted by name, then instead of sorting the files from "a" to "z", they will be sorted from "z" to "a"; if sorted by size, instead of being incrementally they will be sorted decrementally. false Nemo uses the users home folder as the desktop If set to true, then Nemo will use the user's home folder as the desktop. If it is false, then it will use ~/Desktop as the desktop. 'icon-view' Default folder viewer When a folder is visited this viewer is used unless you have selected another view for that particular folder. Possible values are "list-view", "icon-view" and "compact-view". false Inherit the view type (icon, compact, list) from parent to children When a folder is visited the viewer is inherited from that folder's parent unless you have selected another view for that particular folder. 'locale' Date Format The format of file dates. Possible values are "locale", "iso", and "informal". false Whether to show hidden files If set to true, then hidden files are shown by default in the file manager. Hidden files are either dotfiles, listed in the folder's .hidden file or backup files ending with a tilde (~). false Whether to show the full path of the current view in the title bar and tab bars If set to true, will show the normal title of a window or tab, followed by the full path to that location in parentheses. [] Bulk rename utility If set, Nemo will append URIs of selected files and treat the result as a command line for bulk renaming. Bulk rename applications can register themselves in this key by setting the key to a space-separated string of their executable name and any command line options. If the executable name is not set to a full path, it will be searched for in the search path. 'base-10' Prefixes used for file sizes Determines whether Nemo uses base-10, base-10 long, base-2 or base-2 long file size prefixes false Whether to close a view of a removeable device instead of navigating Home If set to true, a view open for a removeable device will be closed instead of sent Home if the device is ejected false Whether to default to showing dual-pane view when a new window is opened If set to true, new Nemo windows will default to showing two panes false Whether to ignore folder metadata for view zoom levels and layouts If set to true, views will not change according to their metadata, but stay consistent for the life of that window true Whether to list bookmarks in the Move To/Copy To menus If set to true, bookmarks will be listed in the MoveTo/CopyTo menus true Whether to list places in the Move To/Copy To menus If set to true, places will be listed in the MoveTo/CopyTo menus false deprecated - no longer used false Show tooltips for desktop items If true, tooltips will be displayed for desktop items. false Show tooltips when hovering on items in an icon or compact view If true, tooltips will be displayed for icon and compact view items false Show tooltips when hovering on items in a list view If true, tooltips will be displayed for list view items false Show detailed file type in tooltip If true, tooltips will show a detailed file type. false Show file modified date in tooltip If true, tooltips will show their modified date. false Show file accessed date in tooltip If true, tooltips will show their accessed date. false Show file creation (birth) date in tooltip If true, tooltips will show their creation date. false Show full path in tooltip If true, tooltips will show the file's full path. false Don't show the explainer message when turning off the main menu If true, you will no longer recieve a popup explaining how to reactivate the main menu once you've hidden it 2 Last server connect method used false If true, all file operations will start immediately false If true, double click left on blank area will go to parent folder [] List of saved search strings false Display the 'Make executable and run' button in the mime-action dialog (open an unknown filetype) [ 'none', 'size', 'date_modified' ] List of possible captions on icons A list of captions below an icon in the icon view and the desktop. The actual number of captions shown depends on the zoom level. Some possible values are: "size", "type", "date_modified", "date_changed", "date_accessed", "owner", "group", "permissions", "octal_permissions" and "mime_type". false deprecated - not used false Put labels beside icons If true, labels will be placed beside icons rather than underneath them. 'standard' Default icon zoom level Default zoom level used by the icon view. 64 Default Thumbnail Icon Size The default size of an icon for a thumbnail in the icon view. [ '3' ] Text Ellipsis Limit A string specifying how parts of overlong file names should be replaced by ellipses, depending on the zoom level. Each of the list entries is of the form "Zoom Level:Integer". For each specified zoom level, if the given integer is larger than 0, the file name will not exceed the given number of lines. If the integer is 0 or smaller, no limit is imposed on the specified zoom level. A default entry of the form "Integer" without any specified zoom level is also allowed. It defines the maximum number of lines for all other zoom levels. Examples: 0 - always display overlong file names; 3 - shorten file names if they exceed three lines; smallest:5,smaller:4,0 - shorten file names if they exceed five lines for zoom level "smallest". Shorten file names if they exceed four lines for zoom level "smaller". Do not shorten file names for other zoom levels. Available zoom levels: smallest (33%), smaller (50%), small (66%), standard (100%), large (150%), larger (200%), largest (400%) 'standard' Default compact view zoom level Default zoom level used by the compact view. false All columns have same width If this preference is set, all columns in the compact view have the same width. Otherwise, the width of each column is determined seperately. 'smaller' Default list zoom level Default zoom level used by the list view. [ 'name', 'size', 'type', 'date_modified' ] Default list of columns visible in the list view Default list of columns visible in the list view. [ 'name', 'size', 'type', 'date_modified' ] Default column order in the list view Default column order in the list view. [ 'name', 'size', 'type', 'where' ] Default list of columns visible in the search view. Default list of columns visible in the search view. true Only show folders in the tree side pane If set to true, Nemo will only show folders in the tree side pane. Otherwise it will show both folders and files. 'Noto Sans 10' Desktop font The font description used for the icons on the desktop. "true::false" Desktop layout Format bool:bool, show desktop folder on primary monitor:show desktop on remaining monitors true Whether to show icons from inactive monitors on another monitor true Deprecated: Allow Nemo to manage the desktop Deprecated: If this is set to true, Nemo will autostart and manage the desktop true Which desktop view type to use If true, the new desktop grid view will be used by nemo-desktop, otherwise the legacy view will be used. 1.0 Vertical desktop grid adjustment Overrides the standard vertical spacing for the desktop grid, in situation where default spacing is not ideal due to label customizations. This is a value from 0.5 to 1.5, with 1.0 being no adjustment, and 0.5 being half the default spacing. 1.0 Horizontal desktop grid adjustment Overrides the standard horizontal spacing for the desktop grid, in situation where default spacing is not ideal due to label customizations. This is a value from 0.5 to 1.5, with 1.0 being no adjustment, and 0.5 being half the default spacing. false Home icon visible on desktop If this is set to true, an icon linking to the home folder will be put on the desktop. false Computer icon visible on desktop If this is set to true, an icon linking to the computer location will be put on the desktop. false Trash icon visible on desktop If this is set to true, an icon linking to the trash will be put on the desktop. false Show mounted volumes on the desktop If this is set to true, icons linking to mounted volumes will be put on the desktop. false Network Servers icon visible on the desktop If this is set to true, an icon linking to the Network Servers view will be put on the desktop. 2 Text Ellipsis Limit An integer specifying how parts of overlong file names should be replaced by ellipses on the desktop. If the number is larger than 0, the file name will not exceed the given number of lines. If the number is 0 or smaller, no limit is imposed on the number of displayed lines. ['conky'] List of desktop-handling to ignore when determining whether or not to manager the desktop. Nemo checks for _NET_WM_WINDOW_TYPE_DESKTOP-type windows, and skips managing the desktop if any others are detected. Add potential names to this list to ignore when performing this check. This means that you want nemo to create its own desktop window(s) even though something else already seems to. The check is based on a program's WM_CLASS. true Fade the background on change If set to true, then Nemo will use a fade effect to change the desktop background. '' The geometry string for a navigation window. A string containing the saved geometry and coordinates string for navigation windows. false Whether the navigation window should be maximized. Whether the navigation window should be maximized by default. 148 Width of the side pane The default width of the side pane in new windows. -1 Index of the bookmark list to jump to the dedicated sidebar bookmark section This is an internal setting for the sidebar that tracks the index in the bookmark list that separates bookmarks in the Computer section from bookmarks in the Bookmark section. true Show toolbar in new windows If set to true, newly opened windows will have toolbars visible. true Show location bar in new windows If set to true, newly opened windows will have the location bar visible. true Show status bar in new windows If set to true, newly opened windows will have the status bar visible. true Show side pane in new windows If set to true, newly opened windows will have the side pane visible. true Show menu bar in new windows If set to true, newly opened windows will have the menu bar visible. true Expand My Computer section in places sidebar View state storage for My Computer in places sidebar true Expand Bookmark section in places sidebar View state storage for Bookmarks in places sidebar true Expand Devices section in places sidebar View state storage for My Computer in places sidebar true Expand Network section in places sidebar View state storage for My Computer in places sidebar 'places' Side pane view The side pane view to show in newly opened windows. [] List of extensions -not- to load. List of extension names you do -not- want to load. This maintains the behavior of an installed extension being enabled by default. [] List of NemoActions -not- to load. List of action files you do -not- want loaded. This maintains the behavior of an installed action being enabled by default. [] List of scripts -not- to load. List of script files you do -not- want loaded. This maintains the behavior of an installed script being enabled by default. true Show the selection context menu's Open item. true Show the selection context menu's Open in New Tab item. true Show the selection context menu's Open in New Window item. true Show the selection context menu's Scripts submenu. true Show the selection context menu's Cut item. true Show the selection context menu's Copy item. true Show the selection context menu's Paste item. false Show the selection context menu's Duplicate item. true Show the selection context menu's Pin/Unpin item. false Show the selection context menu's Create Link item. true Show the selection context menu's Rename item. false Show the selection context menu's Copy To submenu. false Show the selection context menu's Move To submenu. true Show the selection context menu's Open in Terminal item. true Show the selection context menu's Open As Root item. true Show the selection context menu's Move to Trash item. true Show the selection context menu's Properties item. true Show the background context menu's Create New Folder item. true Show the background context menu's Scripts submenu. true Show the background context menu's Open in Terminal item. true Show the background context menu's Open as Root item. true Show the background context menu's Show Hidden Files item. true Show the background context menu's Paste item. true Show the background context menu's Properties item. true Show the background context menu's Arrange Items submenu (icon view only). true Show the background context menu's Organize by Name item (icon view only). true Show the background context menu's Customize item (new-style desktop only). nemo-4.4.2/makepot000077500000000000000000000005531357442400300140520ustar00rootroot00000000000000#!/bin/bash data/nemo-actions/extract_action_strings data/nemo-actions xgettext -c --from-code=UTF-8 --keyword=_ --keyword=N_ --output=nemo.pot \ src/*.c libnemo-extension/*.c libnemo-private/*.c eel/*.c \ data/nemo-actions/action_i18n_strings.py generate_additional_file xgettext -c --join-existing -L Glade gresources/*.glade --output=nemo.pot nemo-4.4.2/meson.build000066400000000000000000000136401357442400300146270ustar00rootroot00000000000000# Meson build file # https://github.com/linuxmint/nemo project('nemo', 'c', version: '4.4.2', meson_version: '>=0.41.0' ) # 1. If the library code has changed at all since last release, then increment revision. # 2. If any interfaces have been added, then increment current and set revision to 0. # Interface break is not allowed. nemo_extension_current = 5 nemo_extension_revision = 0 # We need to decrement current by one in the calculation of the age because # the library was started with version "1:0:0" instead of "0:0:0" NEMO_EXTENSION_VERSION_INFO = '@0@:@1@:@2@'.format( nemo_extension_current, nemo_extension_revision, nemo_extension_current - 1 ) ################################################################################ conf = configuration_data() gnome = import('gnome') pkgconfig = import('pkgconfig') cc = meson.get_compiler('c') prefix = get_option('prefix') buildtype = get_option('buildtype') # Surround the version in quotes to make it a C string conf.set_quoted('VERSION', meson.project_version()) conf.set('ENABLE_DEBUG', buildtype == 'debug') check_headers = [ 'malloc.h', 'sys/mount.h', 'sys/param.h', 'sys/vfs.h', 'X11/XF86keysym.h', ] foreach h : check_headers conf.set10('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach conf.set10('HAVE_MALLOPT', cc.has_function('mallopt', prefix: '#include ')) if not get_option('deprecated_warnings') add_global_arguments([ '-Wno-deprecated-declarations', '-Wno-deprecated', '-Wno-declaration-after-statement', '-DGLIB_DISABLE_DEPRECATION_WARNINGS', ], language: 'c', ) endif if get_option('profiling') add_global_arguments('-fno-omit-frame-pointer', language: 'c') endif ################################################################################ # Find dependencies glib_version = '>=2.37.3' math = cc.find_library('m', required: true) gtk = dependency('gtk+-3.0', version: '>=3.9.10') gio = dependency('gio-2.0', version: glib_version) gio_unix= dependency('gio-unix-2.0', version: glib_version) glib = dependency('glib-2.0', version: glib_version) gmodule = dependency('gmodule-no-export-2.0', version: glib_version) gobject = dependency('gobject-2.0', version: '>=2.0') go_intr = dependency('gobject-introspection-1.0', version: '>=1.0') libnotif= dependency('libnotify', version: '>=0.7.0') cinnamon= dependency('cinnamon-desktop', version: '>=2.6.1') gail = dependency('gail-3.0') libxml = dependency('libxml-2.0', version: '>=2.7.8') x11 = dependency('x11') xapp = dependency('xapp', version: '>=1.4.0') # Facultative dependencies gtkdoc_enabled = get_option('gtk_doc') if gtkdoc_enabled find_program('gtkdoc-scan', required: true) endif libexif_enabled = get_option('exif') if libexif_enabled libexif = dependency('libexif', version: '>=0.6.20') endif conf.set('HAVE_EXIF', libexif_enabled) exempi_enabled = get_option('xmp') if exempi_enabled exempi = dependency('exempi-2.0', version: '>=2.2.0') endif conf.set('HAVE_EXEMPI', exempi_enabled) libselinux_enabled = get_option('selinux') if libselinux_enabled libselinux = dependency('libselinux', version: '>=2.0') endif conf.set('HAVE_SELINUX', libselinux_enabled) new_pango = dependency('pango', version: '>=1.44.0', required: false) if new_pango.found() conf.set('HAVE_PANGO_144', true) endif enableEmptyView = get_option('empty_view') conf.set10('ENABLE_EMPTY_VIEW', enableEmptyView) conf.set_quoted('GETTEXT_PACKAGE', 'nemo') conf.set_quoted('LOCALE_DIR', join_paths(get_option('prefix'), get_option('localedir'))) conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) conf.set('ENABLE_NLS', cc.has_header('libintl.h')) conf.set('HAVE_GETTEXT', true) conf.set('HAVE_LOCALE_H', cc.has_header('locale.h')) # STATX Support check statx_supported = cc.compiles( ''' #define _GNU_SOURCE #include struct statx stxbuf; ''' ) if not statx_supported message('WARNING: No native statx support (Kernel < 4.11) - using compatibility wrappers.') else message('Native statx support used.') endif conf.set10('NATIVE_STATX', statx_supported) # End STATX configure_file( input : 'config.h.meson.in', output: 'config.h', configuration: conf ) ################################################################################ rootInclude = include_directories('.') nemoDataPath = join_paths(get_option('prefix'), get_option('datadir'), 'nemo') libExecPath = join_paths(get_option('prefix'), get_option('libexecdir')) # Keep this constant, in case some extensions are behind in being updated... nemoExtensionPath = join_paths(get_option('prefix'), get_option('libdir'), 'nemo', 'extensions-3.0') nemo_definitions = [ '-DNEMO_DATADIR="@0@"'.format(nemoDataPath), '-DNEMO_EXTENSIONDIR="@0@"'.format(nemoExtensionPath), '-DLIBEXECDIR="@0@"'.format(libExecPath), ] po_subdir = join_paths(meson.source_root(), 'po') subdir('install-scripts') subdir('cut-n-paste-code/libegg') subdir('data') subdir('eel') subdir('files') subdir('gresources') subdir('libnemo-extension') subdir('libnemo-private') # subdir('po') subdir('src') subdir('test') subdir('docs') message('\n'.join(['', ' @0@-@1@'.format(meson.project_name(), meson.project_version()), '', ' prefix: @0@'.format(prefix), ' source code location: @0@'.format(meson.source_root()), ' compiler: @0@'.format(cc.get_id()), ' debugging support: @0@'.format(buildtype), ' libexif support: @0@'.format(libexif_enabled), ' exempi support: @0@'.format(exempi_enabled), '', ' nemo-extension documentation: @0@'.format(gtkdoc_enabled), ' nemo-extension introspection: @0@'.format(true), '', ' perf profiling support: @0@'.format(get_option('profiling')) ])) nemo-4.4.2/meson_options.txt000066400000000000000000000013761357442400300161250ustar00rootroot00000000000000option('deprecated_warnings', type : 'boolean', value : false, description: 'Show compiler warnings about deprecated features') option('exif', type : 'boolean', value : true, description: 'EXIF parsing support (requires libexif)') option('xmp', type : 'boolean', value : true, description: 'XMP support (requires Exempi)') option('gtk_doc', type : 'boolean', value : false, description: 'Generate API reference (requires GTK-Doc)') option('selinux', type : 'boolean', value : false, description: 'SELinux support') option('empty_view', type : 'boolean', value : false, description: 'Enable empty view') option('profiling', type : 'boolean', value : false, description: 'keep frame pointers (for profiling purposes)') nemo-4.4.2/nemo.pot000066400000000000000000004375501357442400300141610ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-11-16 15:32+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: src/nemo-action-config-widget.c:237 msgid "No actions found" msgstr "" #: src/nemo-action-config-widget.c:447 msgid "Actions" msgstr "" #: src/nemo-application.c:402 #, c-format msgid "Nemo could not create the required folder \"%s\"." msgstr "" #: src/nemo-application.c:404 msgid "" "Before running Nemo, please create the following folder, or set permissions " "such that Nemo can create it." msgstr "" #: src/nemo-autorun-software.c:143 src/nemo-autorun-software.c:146 #, c-format msgid "Error starting autorun program: %s" msgstr "" #: src/nemo-autorun-software.c:149 msgid "Cannot find the autorun program" msgstr "" #: src/nemo-autorun-software.c:171 msgid "Error autorunning software" msgstr "" #: src/nemo-autorun-software.c:197 msgid "" "This medium contains software intended to be automatically started. " "Would you like to run it?" msgstr "" #: src/nemo-autorun-software.c:199 #, c-format msgid "" "The software will run directly from the medium \"%s\". You should never run " "software that you don't trust.\n" "\n" "If in doubt, press Cancel." msgstr "" #: src/nemo-autorun-software.c:234 src/nemo-mime-actions.c:731 msgid "_Run" msgstr "" #: src/nemo-blank-desktop-window.c:145 msgid "Customize" msgstr "" #. hardcode "Desktop" #: src/nemo-blank-desktop-window.c:214 src/nemo-desktop-window.c:125 #: src/nemo-desktop-window.c:294 src/nemo-pathbar.c:1440 #: src/nemo-places-sidebar.c:779 libnemo-private/nemo-action.c:1330 #: gresources/nemo-file-management-properties.glade:3982 msgid "Desktop" msgstr "" #: src/nemo-bookmarks-window.c:176 msgid "No bookmarks defined" msgstr "" #: src/nemo-config-base-widget.c:70 msgid "Disable all" msgstr "" #: src/nemo-config-base-widget.c:73 msgid "Enable all" msgstr "" #: src/nemo-connect-server-dialog.c:125 msgid "SSH" msgstr "" #: src/nemo-connect-server-dialog.c:128 msgid "Public FTP" msgstr "" #: src/nemo-connect-server-dialog.c:130 msgid "FTP (with login)" msgstr "" #: src/nemo-connect-server-dialog.c:133 msgid "Windows share" msgstr "" #: src/nemo-connect-server-dialog.c:135 msgid "WebDAV (HTTP)" msgstr "" #: src/nemo-connect-server-dialog.c:137 msgid "Secure WebDAV (HTTPS)" msgstr "" #: src/nemo-connect-server-dialog.c:184 msgid "Connecting..." msgstr "" #: src/nemo-connect-server-dialog.c:208 msgid "" "Can't load the supported server method list.\n" "Please check your gvfs installation." msgstr "" #: src/nemo-connect-server-dialog.c:286 #, c-format msgid "The folder \"%s\" cannot be opened on \"%s\"." msgstr "" #: src/nemo-connect-server-dialog.c:296 #, c-format msgid "The server at \"%s\" cannot be found." msgstr "" #: src/nemo-connect-server-dialog.c:331 msgid "Try Again" msgstr "" #: src/nemo-connect-server-dialog.c:396 msgid "Please verify your user details." msgstr "" #: src/nemo-connect-server-dialog.c:426 msgid "Continue" msgstr "" #: src/nemo-connect-server-dialog.c:695 src/nemo-properties-window.c:5166 #: src/nemo-view.c:1654 msgid "There was an error displaying help." msgstr "" #: src/nemo-connect-server-dialog.c:713 src/nemo-connect-server-dialog.c:1110 msgid "C_onnect" msgstr "" #. set dialog properties #: src/nemo-connect-server-dialog.c:842 msgid "Connect to Server" msgstr "" #: src/nemo-connect-server-dialog.c:860 msgid "Server Details" msgstr "" #. first row: server entry + port spinbutton #: src/nemo-connect-server-dialog.c:885 msgid "_Server:" msgstr "" #. port #: src/nemo-connect-server-dialog.c:905 msgid "_Port:" msgstr "" #. second row: type combobox #: src/nemo-connect-server-dialog.c:923 msgid "_Type:" msgstr "" #. third row: share entry #: src/nemo-connect-server-dialog.c:993 msgid "Sh_are:" msgstr "" #. fourth row: folder entry #: src/nemo-connect-server-dialog.c:1008 src/nemo-view.c:1848 msgid "_Folder:" msgstr "" #: src/nemo-connect-server-dialog.c:1026 msgid "User Details" msgstr "" #. first row: domain entry #: src/nemo-connect-server-dialog.c:1050 msgid "_Domain name:" msgstr "" #. second row: username entry #: src/nemo-connect-server-dialog.c:1065 msgid "_User name:" msgstr "" #. third row: password entry #: src/nemo-connect-server-dialog.c:1080 msgid "Pass_word:" msgstr "" #. fourth row: remember checkbox #: src/nemo-connect-server-dialog.c:1096 msgid "_Remember this password" msgstr "" #: src/nemo-connect-server-dialog.c:1196 msgid "Operation cancelled" msgstr "" #: src/nemo-connect-server-dialog-main.c:120 msgid "Print but do not open the URI" msgstr "" #. Translators: This is the --help description for the connect to server app, #. the initial newlines are between the command line arg and the description #: src/nemo-connect-server-dialog-main.c:131 msgid "" "\n" "\n" "Add connect to server mount" msgstr "" #: src/nemo-desktop-application.c:259 src/nemo-main-application.c:591 msgid "Show the version of the program." msgstr "" #: src/nemo-desktop-application.c:263 msgid "Quit Nemo Desktop." msgstr "" #: src/nemo-desktop-application.c:274 msgid "" "\n" "\n" "Manage the desktop with the file manager" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-grid-view.c:917 src/nemo-desktop-icon-view.c:682 #: src/nemo-view.c:8314 src/nemo-view.c:9933 msgid "E_mpty Trash" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-grid-view.c:1027 #: gresources/nemo-desktop-overlay.glade:293 msgid "Auto-arrange" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-grid-view.c:1032 #: gresources/nemo-desktop-overlay.glade:539 #: gresources/nemo-file-management-properties.glade:543 msgid "Reverse sort" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1040 msgid "Smaller" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1044 msgid "Small" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1048 msgid "Normal" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1052 msgid "Large" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1056 msgid "Larger" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1063 msgid "_Vertical" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1067 msgid "_Horizontal" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1074 src/nemo-list-view.c:2331 #: libnemo-private/nemo-column-utilities.c:43 #: gresources/nemo-desktop-overlay.glade:116 msgid "Name" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1078 #: libnemo-private/nemo-column-utilities.c:50 #: gresources/nemo-desktop-overlay.glade:121 msgid "Size" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1082 #: libnemo-private/nemo-column-utilities.c:58 #: gresources/nemo-desktop-overlay.glade:126 msgid "Type" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1086 #: gresources/nemo-desktop-overlay.glade:131 msgid "Date" msgstr "" #. name, stock id, label #: src/nemo-desktop-icon-grid-view.c:1092 msgid "_Sort" msgstr "" #. name, stock id, label #: src/nemo-desktop-icon-grid-view.c:1093 msgid "_Icon Size" msgstr "" #. label, accelerator #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-grid-view.c:1097 src/nemo-desktop-icon-view.c:723 msgid "Empty Trash" msgstr "" #. tooltip #: src/nemo-desktop-icon-grid-view.c:1099 src/nemo-desktop-icon-view.c:724 #: src/nemo-trash-bar.c:227 src/nemo-view.c:8315 msgid "Delete all items in the Trash" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1103 #: gresources/nemo-file-management-properties.glade:4005 msgid "_Customize" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1104 msgid "Adjust the desktop layout for this monitor" msgstr "" #: src/nemo-desktop-icon-grid-view.c:1195 src/nemo-desktop-icon-view.c:787 msgid "The desktop view encountered an error." msgstr "" #: src/nemo-desktop-icon-grid-view.c:1196 src/nemo-desktop-icon-view.c:788 msgid "The desktop view encountered an error while starting up." msgstr "" #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-view.c:704 src/nemo-desktop-icon-view.c:719 msgid "Restore Icons' Original Si_zes" msgstr "" #: src/nemo-desktop-icon-view.c:705 msgid "Restore Icon's Original Si_ze" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-desktop-icon-view.c:715 msgid "Resize Icon..." msgstr "" #. tooltip #: src/nemo-desktop-icon-view.c:716 msgid "Make the selected icon resizable" msgstr "" #. tooltip #: src/nemo-desktop-icon-view.c:720 msgid "Restore each selected icon to its original size" msgstr "" #: src/nemo-desktop-item-properties.c:408 #: src/nemo-desktop-item-properties.c:418 src/nemo-image-properties-page.c:368 msgid "Comment" msgstr "" #: src/nemo-desktop-item-properties.c:411 msgid "URL" msgstr "" #: src/nemo-desktop-item-properties.c:414 #: src/nemo-desktop-item-properties.c:424 src/nemo-image-properties-page.c:361 #: src/nemo-image-properties-page.c:414 msgid "Description" msgstr "" #: src/nemo-desktop-item-properties.c:421 msgid "Command" msgstr "" #: src/nemo-desktop-overlay.c:78 #, c-format msgid "Current Monitor Layout (%s - %dx%d)" msgstr "" #: src/nemo-desktop-overlay.c:90 #, c-format msgid "Current Monitor Layout (%dx%d)" msgstr "" #: src/nemo-desktop-overlay.c:365 src/nemo-desktop-overlay.c:503 #: src/nemo-desktop-overlay.c:506 msgid "Desktop Settings" msgstr "" #: src/nemo-desktop-overlay.c:469 msgid "Current Monitor Preferences" msgstr "" #: src/nemo-desktop-overlay.c:493 msgid "Show global desktop settings" msgstr "" #: src/nemo-error-reporting.c:68 #, c-format msgid "" "You do not have the permissions necessary to view the contents of \"%s\"." msgstr "" #: src/nemo-error-reporting.c:72 #, c-format msgid "\"%s\" could not be found. Perhaps it has recently been deleted." msgstr "" #: src/nemo-error-reporting.c:76 #, c-format msgid "Sorry, could not display all the contents of \"%s\": %s" msgstr "" #: src/nemo-error-reporting.c:83 msgid "The folder contents could not be displayed." msgstr "" #: src/nemo-error-reporting.c:107 #, c-format msgid "" "You do not have the permissions necessary to change the group of \"%s\"." msgstr "" #. fall through #: src/nemo-error-reporting.c:120 #, c-format msgid "Sorry, could not change the group of \"%s\": %s" msgstr "" #: src/nemo-error-reporting.c:125 msgid "The group could not be changed." msgstr "" #: src/nemo-error-reporting.c:145 #, c-format msgid "Sorry, could not change the owner of \"%s\": %s" msgstr "" #: src/nemo-error-reporting.c:147 msgid "The owner could not be changed." msgstr "" #: src/nemo-error-reporting.c:167 #, c-format msgid "Sorry, could not change the permissions of \"%s\": %s" msgstr "" #: src/nemo-error-reporting.c:169 msgid "The permissions could not be changed." msgstr "" #: src/nemo-error-reporting.c:204 #, c-format msgid "" "The name \"%s\" is already used in this folder. Please use a different name." msgstr "" #: src/nemo-error-reporting.c:209 #, c-format msgid "" "There is no \"%s\" in this folder. Perhaps it was just moved or deleted?" msgstr "" #: src/nemo-error-reporting.c:214 #, c-format msgid "You do not have the permissions necessary to rename \"%s\"." msgstr "" #: src/nemo-error-reporting.c:219 #, c-format msgid "" "The name \"%s\" is not valid because it contains the character \"/\". Please " "use a different name." msgstr "" #: src/nemo-error-reporting.c:223 #, c-format msgid "The name \"%s\" is not valid. Please use a different name." msgstr "" #: src/nemo-error-reporting.c:229 #, c-format msgid "The name \"%s\" is too long. Please use a different name." msgstr "" #. fall through #: src/nemo-error-reporting.c:243 #, c-format msgid "Sorry, could not rename \"%s\" to \"%s\": %s" msgstr "" #: src/nemo-error-reporting.c:251 msgid "The item could not be renamed." msgstr "" #: src/nemo-error-reporting.c:348 #, c-format msgid "Renaming \"%s\" to \"%s\"." msgstr "" #: src/nemo-extension-config-widget.c:212 msgid "No extensions found" msgstr "" #: src/nemo-extension-config-widget.c:277 msgid "no information available" msgstr "" #: src/nemo-extension-config-widget.c:287 msgid "Configure" msgstr "" #: src/nemo-extension-config-widget.c:398 msgid "Extensions" msgstr "" #: src/nemo-extension-config-widget.c:406 msgid "Extensions changed. Restart required." msgstr "" #. Translators: this is referred to captions under icons. #. Translators: this is referred to the permissions #. * the user has in a directory. #. #: src/nemo-file-management-properties.c:290 src/nemo-properties-window.c:3927 #: src/nemo-properties-window.c:3938 msgid "None" msgstr "" #: src/nemo-file-management-properties.c:483 libnemo-private/nemo-file.c:4953 #, no-c-format msgid "Yesterday" msgstr "" #: src/nemo-icon-view.c:137 msgid "by _Name" msgstr "" #: src/nemo-icon-view.c:138 src/nemo-icon-view.c:1429 msgid "Keep icons sorted by name in rows" msgstr "" #: src/nemo-icon-view.c:144 msgid "by _Size" msgstr "" #: src/nemo-icon-view.c:145 src/nemo-icon-view.c:1433 msgid "Keep icons sorted by size in rows" msgstr "" #: src/nemo-icon-view.c:151 msgid "by _Type" msgstr "" #: src/nemo-icon-view.c:152 src/nemo-icon-view.c:1437 msgid "Keep icons sorted by type in rows" msgstr "" #: src/nemo-icon-view.c:158 msgid "by _Detailed Type" msgstr "" #: src/nemo-icon-view.c:159 src/nemo-icon-view.c:1441 msgid "Keep icons sorted by detailed type in rows" msgstr "" #: src/nemo-icon-view.c:165 msgid "by Modification _Date" msgstr "" #: src/nemo-icon-view.c:166 src/nemo-icon-view.c:1445 msgid "Keep icons sorted by modification date in rows" msgstr "" #: src/nemo-icon-view.c:172 msgid "by T_rash Time" msgstr "" #: src/nemo-icon-view.c:173 src/nemo-icon-view.c:1449 msgid "Keep icons sorted by trash time in rows" msgstr "" #: src/nemo-icon-view.c:607 msgid "_Organize Desktop by Name" msgstr "" #. name, stock id, label #: src/nemo-icon-view.c:1401 #: gresources/nemo-file-management-properties.glade:3925 msgid "Arran_ge Items" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-icon-view.c:1403 #: gresources/nemo-file-management-properties.glade:3944 msgid "_Organize by Name" msgstr "" #. tooltip #: src/nemo-icon-view.c:1404 msgid "Reposition icons to better fit in the window and avoid overlapping" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-icon-view.c:1411 msgid "Re_versed Order" msgstr "" #. tooltip #: src/nemo-icon-view.c:1412 msgid "Display icons in the opposite order" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-icon-view.c:1416 msgid "_Keep Aligned" msgstr "" #. tooltip #: src/nemo-icon-view.c:1417 msgid "Keep icons lined up on a grid" msgstr "" #: src/nemo-icon-view.c:1424 msgid "_Manually" msgstr "" #: src/nemo-icon-view.c:1425 msgid "Leave icons wherever they are dropped" msgstr "" #: src/nemo-icon-view.c:1428 msgid "By _Name" msgstr "" #: src/nemo-icon-view.c:1432 msgid "By _Size" msgstr "" #: src/nemo-icon-view.c:1436 msgid "By _Type" msgstr "" #: src/nemo-icon-view.c:1440 msgid "By _Detailed Type" msgstr "" #: src/nemo-icon-view.c:1444 msgid "By Modification _Date" msgstr "" #: src/nemo-icon-view.c:1448 msgid "By T_rash Time" msgstr "" #. translators: this is used in the view selection dropdown #. * of navigation windows and in the preferences dialog #: src/nemo-icon-view.c:2840 src/nemo-icon-view-container.c:2147 #: src/nemo-icon-view-grid-container.c:1601 src/nemo-window-menus.c:1487 #: src/nemo-window-menus.c:1637 #: gresources/nemo-file-management-properties.glade:110 #: gresources/nemo-file-management-properties.glade:3902 msgid "Icon View" msgstr "" #. translators: this is used in the view menu #: src/nemo-icon-view.c:2842 msgid "_Icons" msgstr "" #: src/nemo-icon-view.c:2843 msgid "The icon view encountered an error." msgstr "" #: src/nemo-icon-view.c:2844 msgid "The icon view encountered an error while starting up." msgstr "" #: src/nemo-icon-view.c:2845 msgid "Display this location with the icon view." msgstr "" #. translators: this is used in the view selection dropdown #. * of navigation windows and in the preferences dialog #: src/nemo-icon-view.c:2854 src/nemo-window-menus.c:1493 #: src/nemo-window-menus.c:1660 #: gresources/nemo-file-management-properties.glade:116 msgid "Compact View" msgstr "" #. translators: this is used in the view menu #: src/nemo-icon-view.c:2856 msgid "_Compact" msgstr "" #: src/nemo-icon-view.c:2857 msgid "The compact view encountered an error." msgstr "" #: src/nemo-icon-view.c:2858 msgid "The compact view encountered an error while starting up." msgstr "" #: src/nemo-icon-view.c:2859 msgid "Display this location with the compact view." msgstr "" #: src/nemo-image-properties-page.c:331 msgid "Image Type" msgstr "" #: src/nemo-image-properties-page.c:333 src/nemo-image-properties-page.c:339 #, c-format msgid "%d pixel" msgid_plural "%d pixels" msgstr[0] "" msgstr[1] "" #: src/nemo-image-properties-page.c:337 msgid "Width" msgstr "" #: src/nemo-image-properties-page.c:343 msgid "Height" msgstr "" #: src/nemo-image-properties-page.c:356 src/nemo-image-properties-page.c:357 msgid "Title" msgstr "" #: src/nemo-image-properties-page.c:358 src/nemo-image-properties-page.c:359 msgid "Author" msgstr "" #: src/nemo-image-properties-page.c:362 src/nemo-image-properties-page.c:417 msgid "Copyright" msgstr "" #: src/nemo-image-properties-page.c:363 msgid "Created On" msgstr "" #: src/nemo-image-properties-page.c:364 msgid "Created By" msgstr "" #: src/nemo-image-properties-page.c:365 msgid "Disclaimer" msgstr "" #: src/nemo-image-properties-page.c:366 msgid "Warning" msgstr "" #: src/nemo-image-properties-page.c:367 msgid "Source" msgstr "" #: src/nemo-image-properties-page.c:382 msgid "Camera Brand" msgstr "" #: src/nemo-image-properties-page.c:383 msgid "Camera Model" msgstr "" #. Choose which date to show in order of relevance #: src/nemo-image-properties-page.c:386 msgid "Date Taken" msgstr "" #: src/nemo-image-properties-page.c:387 msgid "Date Digitized" msgstr "" #: src/nemo-image-properties-page.c:388 #: libnemo-private/nemo-column-utilities.c:72 msgid "Date Modified" msgstr "" #: src/nemo-image-properties-page.c:392 msgid "Exposure Time" msgstr "" #: src/nemo-image-properties-page.c:393 msgid "Aperture Value" msgstr "" #: src/nemo-image-properties-page.c:394 msgid "ISO Speed Rating" msgstr "" #: src/nemo-image-properties-page.c:395 msgid "Flash Fired" msgstr "" #: src/nemo-image-properties-page.c:396 msgid "Metering Mode" msgstr "" #: src/nemo-image-properties-page.c:397 msgid "Exposure Program" msgstr "" #: src/nemo-image-properties-page.c:398 msgid "Focal Length" msgstr "" #: src/nemo-image-properties-page.c:399 msgid "Software" msgstr "" #: src/nemo-image-properties-page.c:413 src/nemo-window-menus.c:1602 #: libnemo-private/nemo-column-utilities.c:159 msgid "Location" msgstr "" #: src/nemo-image-properties-page.c:415 msgid "Keywords" msgstr "" #: src/nemo-image-properties-page.c:416 msgid "Creator" msgstr "" #: src/nemo-image-properties-page.c:418 msgid "Rating" msgstr "" #: src/nemo-image-properties-page.c:441 msgid "Failed to load image information" msgstr "" #: src/nemo-image-properties-page.c:706 src/nemo-list-model.c:435 #: src/nemo-tree-sidebar-model.c:1252 src/nemo-window-manage-views.c:1221 #: src/nemo-window-slot.c:311 msgid "Loading..." msgstr "" #: src/nemo-image-properties-page.c:767 libnemo-private/nemo-file.c:6761 msgid "Image" msgstr "" #: src/nemo-interesting-folder-bar.c:126 msgid "" "Actions: Action files can be added to this folder and will appear in the " "menu." msgstr "" #: src/nemo-interesting-folder-bar.c:128 src/nemo-interesting-folder-bar.c:136 msgid "More info" msgstr "" #: src/nemo-interesting-folder-bar.c:130 msgid "View a sample action file with documentation" msgstr "" #: src/nemo-interesting-folder-bar.c:133 msgid "" "Scripts: All executable files in this folder will appear in the Scripts menu." msgstr "" #: src/nemo-interesting-folder-bar.c:138 msgid "View additional information about creating scripts" msgstr "" #: src/nemo-list-model.c:433 src/nemo-tree-sidebar-model.c:1252 msgid "(Empty)" msgstr "" #: src/nemo-list-view.c:1971 msgid "Use Default" msgstr "" #: src/nemo-list-view.c:1982 msgid "Temporarily disable auto-sort" msgstr "" #. translators: this is used in the view selection dropdown #. * of navigation windows and in the preferences dialog #: src/nemo-list-view.c:2417 src/nemo-list-view.c:4043 #: src/nemo-window-menus.c:1490 src/nemo-window-menus.c:1648 #: gresources/nemo-file-management-properties.glade:113 msgid "List View" msgstr "" #. translators: this is used in the view menu #: src/nemo-list-view.c:4045 msgid "_List" msgstr "" #: src/nemo-list-view.c:4046 msgid "The list view encountered an error." msgstr "" #: src/nemo-list-view.c:4047 msgid "The list view encountered an error while starting up." msgstr "" #: src/nemo-list-view.c:4048 msgid "Display this location with the list view." msgstr "" #: src/nemo-location-bar.c:164 #, c-format msgid "Do you want to view %d location?" msgid_plural "Do you want to view %d locations?" msgstr[0] "" msgstr[1] "" #: src/nemo-location-bar.c:168 src/nemo-mime-actions.c:1059 #, c-format msgid "This will open %d separate window." msgid_plural "This will open %d separate windows." msgstr[0] "" msgstr[1] "" #: src/nemo-main-application.c:522 msgid "--check cannot be used with other options." msgstr "" #: src/nemo-main-application.c:528 msgid "--quit cannot be used with URIs." msgstr "" #: src/nemo-main-application.c:536 msgid "--geometry cannot be used with more than one URI." msgstr "" #: src/nemo-main-application.c:585 msgid "Perform a quick set of self-check tests." msgstr "" #: src/nemo-main-application.c:593 msgid "" "Create the initial window with the given geometry. Examples: nemo --geometry=" "+100+100, nemo --geometry=600x400, nemo --geometry=600x400+100+100." msgstr "" #: src/nemo-main-application.c:594 msgid "GEOMETRY" msgstr "" #: src/nemo-main-application.c:596 msgid "Only create windows for explicitly specified URIs." msgstr "" #: src/nemo-main-application.c:598 msgid "Ignored argument - left for compatibility only." msgstr "" #: src/nemo-main-application.c:600 msgid "Open URIs in tabs." msgstr "" #: src/nemo-main-application.c:602 msgid "" "Repair the user thumbnail cache - this can be useful if you're having " "trouble with file thumbnails. Must be run as root" msgstr "" #: src/nemo-main-application.c:606 msgid "Quit Nemo." msgstr "" #: src/nemo-main-application.c:607 msgid "[URI...]" msgstr "" #: src/nemo-main-application.c:618 msgid "" "\n" "\n" "Browse the file system with the file manager" msgstr "" #: src/nemo-main-application.c:773 msgid "Nemo's main menu is now hidden" msgstr "" #: src/nemo-main-application.c:776 msgid "" "You have chosen to hide the main menu. You can get it back temporarily by:\n" "\n" "- Tapping the key\n" "- Right-clicking an empty region of the main toolbar\n" "- Right-clicking an empty region of the status bar.\n" "\n" "You can restore it permanently by selecting this option again from the View " "menu." msgstr "" #: src/nemo-main-application.c:787 msgid "Don't show this message again." msgstr "" #: src/nemo-mime-actions.c:639 #, c-format msgid "The Link \"%s\" is Broken." msgstr "" #: src/nemo-mime-actions.c:641 #, c-format msgid "The Link \"%s\" is Broken. Move it to Trash?" msgstr "" #: src/nemo-mime-actions.c:647 msgid "This link cannot be used, because it has no target." msgstr "" #: src/nemo-mime-actions.c:649 #, c-format msgid "This link cannot be used, because its target \"%s\" doesn't exist." msgstr "" #. name, stock id #. label, accelerator #: src/nemo-mime-actions.c:659 src/nemo-tree-sidebar.c:1412 #: src/nemo-view.c:8366 src/nemo-view.c:8484 src/nemo-view.c:9531 #: src/nemo-view.c:9856 gresources/nemo-file-management-properties.glade:3659 msgid "Mo_ve to Trash" msgstr "" #: src/nemo-mime-actions.c:719 #, c-format msgid "Do you want to run \"%s\", or display its contents?" msgstr "" #: src/nemo-mime-actions.c:721 #, c-format msgid "\"%s\" is an executable text file." msgstr "" #: src/nemo-mime-actions.c:727 msgid "Run in _Terminal" msgstr "" #: src/nemo-mime-actions.c:728 msgid "_Display" msgstr "" #: src/nemo-mime-actions.c:1054 src/nemo-mime-actions.c:1615 #: src/nemo-view.c:1071 msgid "Are you sure you want to open all files?" msgstr "" #: src/nemo-mime-actions.c:1056 #, c-format msgid "This will open %d separate tab." msgid_plural "This will open %d separate tabs." msgstr[0] "" msgstr[1] "" #: src/nemo-mime-actions.c:1158 src/nemo-open-with-main.c:151 #: src/nemo-view.c:1357 msgid "Open with" msgstr "" #: src/nemo-mime-actions.c:1235 msgid "Unknown file type" msgstr "" #: src/nemo-mime-actions.c:1240 #, c-format msgid "" "The file \"%s\" has no known programs associated with it. If you trust the " "source of this file, and have sufficient permissions, you can mark it " "executable and launch it. Or, you can use the Open With dialog to pick a " "program to associate it with." msgstr "" #: src/nemo-mime-actions.c:1247 msgid "Make executable and run" msgstr "" #: src/nemo-mime-actions.c:1249 #, c-format msgid "" "The file \"%s\" has no known programs associated with it. Use the Open With " "dialog to pick a program to open it with." msgstr "" #: src/nemo-mime-actions.c:1260 msgid "Choose a program" msgstr "" #: src/nemo-mime-actions.c:1339 msgid "Untrusted application launcher" msgstr "" #: src/nemo-mime-actions.c:1342 #, c-format msgid "" "The application launcher \"%s\" has not been marked as trusted (executable). " "If you do not know the source of this file, launching it may be unsafe." msgstr "" #: src/nemo-mime-actions.c:1358 msgid "_Launch Anyway" msgstr "" #: src/nemo-mime-actions.c:1361 msgid "Mark as _Trusted" msgstr "" #: src/nemo-mime-actions.c:1616 #, c-format msgid "This will open %d separate application." msgid_plural "This will open %d separate applications." msgstr[0] "" msgstr[1] "" #: src/nemo-mime-actions.c:1688 src/nemo-mime-actions.c:1962 #: src/nemo-view.c:7484 msgid "Unable to mount location" msgstr "" #: src/nemo-mime-actions.c:2041 src/nemo-view.c:7631 msgid "Unable to start location" msgstr "" #: src/nemo-mime-actions.c:2125 #, c-format msgid "Opening \"%s\"." msgstr "" #: src/nemo-mime-actions.c:2128 #, c-format msgid "Opening %d item." msgid_plural "Opening %d items." msgstr[0] "" msgstr[1] "" #: src/nemo-notebook.c:369 msgid "Close tab" msgstr "" #. Translators: This is the --help description for the open-with app, #. the initial newlines are between the command line arg and the description #: src/nemo-open-with-main.c:104 msgid "" "\n" "\n" "Show an open-with dialog given a uri, to allow the user to change the " "default mimetype handler." msgstr "" #: src/nemo-places-sidebar.c:381 msgid "Devices" msgstr "" #: src/nemo-places-sidebar.c:610 src/nemo-view.c:3198 #, c-format msgid "Free space: %s" msgstr "" #: src/nemo-places-sidebar.c:747 msgid "My Computer" msgstr "" #: src/nemo-places-sidebar.c:758 #, c-format msgid "" "Open your personal folder\n" "%s" msgstr "" #: src/nemo-places-sidebar.c:762 src/nemo-tree-sidebar.c:1551 #: libnemo-private/nemo-bookmark.c:130 libnemo-private/nemo-desktop-link.c:118 #: libnemo-private/nemo-file-utilities.c:67 #: libnemo-private/nemo-file-utilities.c:116 generate_additional_file:41 #: gresources/nemo-desktop-preferences.glade:211 #: gresources/nemo-file-management-properties.glade:2968 msgid "Home" msgstr "" #: src/nemo-places-sidebar.c:781 msgid "Open the contents of your desktop in a folder" msgstr "" #: src/nemo-places-sidebar.c:831 msgid "Recent" msgstr "" #: src/nemo-places-sidebar.c:833 msgid "Recent files" msgstr "" #: src/nemo-places-sidebar.c:845 #, c-format msgid "" "Open the contents of the File System\n" "%s" msgstr "" #: src/nemo-places-sidebar.c:849 src/nemo-tree-sidebar.c:1555 msgid "File System" msgstr "" #: src/nemo-places-sidebar.c:863 src/nemo-trash-bar.c:211 #: libnemo-private/nemo-desktop-link.c:135 generate_additional_file:55 #: gresources/nemo-desktop-preferences.glade:289 msgid "Trash" msgstr "" #: src/nemo-places-sidebar.c:865 msgid "Open the trash" msgstr "" #: src/nemo-places-sidebar.c:870 msgid "Bookmarks" msgstr "" #: src/nemo-places-sidebar.c:994 #, c-format msgid "" "%s (%s)\n" "%s" msgstr "" #: src/nemo-places-sidebar.c:1028 #, c-format msgid "Mount and open %s (%s)" msgstr "" #: src/nemo-places-sidebar.c:1055 src/nemo-places-sidebar.c:1148 #, c-format msgid "Mount and open %s" msgstr "" #: src/nemo-places-sidebar.c:1101 #, c-format msgid "" "%s\n" "%s" msgstr "" #: src/nemo-places-sidebar.c:1135 src/nemo-places-sidebar.c:1190 #: src/nemo-tree-sidebar.c:1559 libnemo-private/nemo-desktop-link.c:147 #: gresources/nemo-desktop-preferences.glade:445 msgid "Network" msgstr "" #: src/nemo-places-sidebar.c:1192 msgid "Browse the contents of the network" msgstr "" #. Adjust start/stop items to reflect the type of the drive #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:2275 src/nemo-places-sidebar.c:3553 #: src/nemo-view.c:8412 src/nemo-view.c:8436 src/nemo-view.c:8508 #: src/nemo-view.c:9154 src/nemo-view.c:9158 src/nemo-view.c:9241 #: src/nemo-view.c:9245 src/nemo-view.c:9345 src/nemo-view.c:9349 msgid "_Start" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:2276 src/nemo-places-sidebar.c:3560 #: src/nemo-view.c:8416 src/nemo-view.c:8440 src/nemo-view.c:8512 #: src/nemo-view.c:9183 src/nemo-view.c:9270 src/nemo-view.c:9374 #: src/nemo-window-menus.c:1302 msgid "_Stop" msgstr "" #. start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used #: src/nemo-places-sidebar.c:2281 msgid "_Power On" msgstr "" #: src/nemo-places-sidebar.c:2282 src/nemo-view.c:9187 src/nemo-view.c:9274 #: src/nemo-view.c:9378 msgid "_Safely Remove Drive" msgstr "" #: src/nemo-places-sidebar.c:2285 msgid "_Connect Drive" msgstr "" #: src/nemo-places-sidebar.c:2286 msgid "_Disconnect Drive" msgstr "" #: src/nemo-places-sidebar.c:2289 msgid "_Start Multi-disk Device" msgstr "" #: src/nemo-places-sidebar.c:2290 msgid "_Stop Multi-disk Device" msgstr "" #. stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used #: src/nemo-places-sidebar.c:2294 src/nemo-view.c:9257 src/nemo-view.c:9361 msgid "_Unlock Drive" msgstr "" #: src/nemo-places-sidebar.c:2295 src/nemo-view.c:9199 src/nemo-view.c:9286 #: src/nemo-view.c:9390 msgid "_Lock Drive" msgstr "" #: src/nemo-places-sidebar.c:2414 src/nemo-places-sidebar.c:3033 #, c-format msgid "Unable to start %s" msgstr "" #: src/nemo-places-sidebar.c:2800 src/nemo-places-sidebar.c:2826 #: src/nemo-places-sidebar.c:2852 #, c-format msgid "Unable to eject %s" msgstr "" #: src/nemo-places-sidebar.c:2989 #, c-format msgid "Unable to poll %s for media changes" msgstr "" #: src/nemo-places-sidebar.c:3087 #, c-format msgid "Unable to stop %s" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3465 src/nemo-tree-sidebar.c:1304 #: src/nemo-view.c:8273 src/nemo-view.c:9787 #: libnemo-private/nemo-mime-application-chooser.c:483 #: gresources/nemo-file-management-properties.glade:3376 msgid "_Open" msgstr "" #. add the "open in new tab" menu item #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3473 src/nemo-tree-sidebar.c:1315 #: src/nemo-view.c:8285 src/nemo-view.c:8466 src/nemo-view.c:9478 #: src/nemo-view.c:9833 gresources/nemo-file-management-properties.glade:3395 msgid "Open in New _Tab" msgstr "" #. add the "open in new window" menu item #: src/nemo-places-sidebar.c:3483 src/nemo-tree-sidebar.c:1329 #: src/nemo-view.c:9469 src/nemo-view.c:9813 #: gresources/nemo-file-management-properties.glade:3414 msgid "Open in New _Window" msgstr "" #. name, stock id, label #: src/nemo-places-sidebar.c:3494 src/nemo-window-menus.c:1412 msgid "_Add Bookmark" msgstr "" #: src/nemo-places-sidebar.c:3500 msgid "Remove" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3509 src/nemo-view.c:8358 #: gresources/nemo-file-management-properties.glade:3566 msgid "_Rename..." msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3525 src/nemo-view.c:8400 src/nemo-view.c:8424 #: src/nemo-view.c:8496 msgid "_Mount" msgstr "" #. add the "Unmount" menu item #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3532 src/nemo-tree-sidebar.c:1444 #: src/nemo-view.c:8404 src/nemo-view.c:8428 src/nemo-view.c:8500 msgid "_Unmount" msgstr "" #. add the "Eject" menu item #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3539 src/nemo-tree-sidebar.c:1453 #: src/nemo-view.c:8408 src/nemo-view.c:8432 src/nemo-view.c:8504 msgid "_Eject" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3546 src/nemo-view.c:8420 src/nemo-view.c:8444 #: src/nemo-view.c:8516 msgid "_Detect Media" msgstr "" #. Empty Trash menu item #: src/nemo-places-sidebar.c:3569 src/nemo-trash-bar.c:224 #: libnemo-private/nemo-file-operations.c:1294 #: libnemo-private/nemo-file-operations.c:1611 #: libnemo-private/nemo-file-operations.c:2495 msgid "Empty _Trash" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-places-sidebar.c:3581 src/nemo-view.c:8255 src/nemo-view.c:8521 #: gresources/nemo-file-management-properties.glade:3678 #: gresources/nemo-file-management-properties.glade:3864 msgid "_Properties" msgstr "" #: src/nemo-progress-ui-handler.c:116 #, c-format msgid "%1$s file operation active. %2$d%% complete." msgid_plural "%1$s file operations active. %2$d%% complete." msgstr[0] "" msgstr[1] "" #: src/nemo-progress-ui-handler.c:207 src/nemo-progress-ui-handler.c:264 msgid "File Operations" msgstr "" #: src/nemo-progress-ui-handler.c:265 msgid "All file operations have been successfully completed" msgstr "" #: src/nemo-progress-ui-handler.c:318 #, c-format msgid "%d%% %s" msgstr "" #: src/nemo-properties-window.c:500 msgid "You cannot assign more than one custom icon at a time!" msgstr "" #: src/nemo-properties-window.c:501 msgid "Please drag just one image to set a custom icon." msgstr "" #: src/nemo-properties-window.c:512 msgid "The file that you dropped is not local." msgstr "" #: src/nemo-properties-window.c:513 src/nemo-properties-window.c:519 msgid "You can only use local images as custom icons." msgstr "" #: src/nemo-properties-window.c:518 msgid "The file that you dropped is not an image." msgstr "" #: src/nemo-properties-window.c:648 msgid "_Name:" msgid_plural "_Names:" msgstr[0] "" msgstr[1] "" #: src/nemo-properties-window.c:843 msgid "Properties" msgstr "" #: src/nemo-properties-window.c:851 #, c-format msgid "%s Properties" msgstr "" #. Fallback, use for both unknown attributes and attributes #. * for which we have no more appropriate default. #. #: src/nemo-properties-window.c:1125 libnemo-private/nemo-file.c:6719 msgid "unknown" msgstr "" #: src/nemo-properties-window.c:1357 msgid "Cancel Group Change?" msgstr "" #: src/nemo-properties-window.c:1772 msgid "Cancel Owner Change?" msgstr "" #: src/nemo-properties-window.c:2093 msgid "nothing" msgstr "" #: src/nemo-properties-window.c:2095 msgid "unreadable" msgstr "" #: src/nemo-properties-window.c:2110 #, c-format msgid "%1$s item (and %2$s hidden), with size %3$s" msgid_plural "%1$s items (and %2$s hidden), totalling %3$s" msgstr[0] "" msgstr[1] "" #: src/nemo-properties-window.c:2115 #, c-format msgid "%1$s item, with size %2$s" msgid_plural "%1$s items, totalling %2$s" msgstr[0] "" msgstr[1] "" #: src/nemo-properties-window.c:2124 msgid "(some contents unreadable)" msgstr "" #. Also set the title field here, with a trailing carriage return & #. * space if the value field has two lines. This is a hack to get the #. * "Contents:" title to line up with the first line of the #. * 2-line value. Maybe there's a better way to do this, but I #. * couldn't think of one. #. #: src/nemo-properties-window.c:2141 msgid "Contents:" msgstr "" #. Translators: "used" refers to the capacity of the filesystem #: src/nemo-properties-window.c:2919 msgid "used" msgstr "" #. Translators: "free" refers to the capacity of the filesystem #: src/nemo-properties-window.c:2926 msgid "free" msgstr "" #: src/nemo-properties-window.c:2928 msgid "Total capacity:" msgstr "" #: src/nemo-properties-window.c:2937 msgid "Filesystem type:" msgstr "" #: src/nemo-properties-window.c:3022 msgid "Basic" msgstr "" #: src/nemo-properties-window.c:3079 #: libnemo-private/nemo-file-conflict-dialog.c:259 #: libnemo-private/nemo-file-conflict-dialog.c:291 msgid "Type:" msgstr "" #: src/nemo-properties-window.c:3088 libnemo-private/nemo-file.c:7871 msgid "Link target:" msgstr "" #: src/nemo-properties-window.c:3099 #: libnemo-private/nemo-file-conflict-dialog.c:256 #: libnemo-private/nemo-file-conflict-dialog.c:288 msgid "Size:" msgstr "" #: src/nemo-properties-window.c:3108 msgid "Location:" msgstr "" #: src/nemo-properties-window.c:3115 msgid "Volume:" msgstr "" #: src/nemo-properties-window.c:3125 msgid "Accessed:" msgstr "" #: src/nemo-properties-window.c:3129 msgid "Modified:" msgstr "" #: src/nemo-properties-window.c:3133 msgid "Created:" msgstr "" #: src/nemo-properties-window.c:3142 msgid "Free space:" msgstr "" #: src/nemo-properties-window.c:3563 msgid "_Read" msgstr "" #: src/nemo-properties-window.c:3565 msgid "_Write" msgstr "" #: src/nemo-properties-window.c:3567 msgid "E_xecute" msgstr "" #. translators: this gets concatenated to "no read", #. * "no access", etc. (see following strings) #. #: src/nemo-properties-window.c:3835 src/nemo-properties-window.c:3846 #: src/nemo-properties-window.c:3858 msgid "no " msgstr "" #: src/nemo-properties-window.c:3838 msgid "list" msgstr "" #: src/nemo-properties-window.c:3840 msgid "read" msgstr "" #: src/nemo-properties-window.c:3849 msgid "create/delete" msgstr "" #: src/nemo-properties-window.c:3851 msgid "write" msgstr "" #: src/nemo-properties-window.c:3860 msgid "access" msgstr "" #: src/nemo-properties-window.c:3908 msgid "Access:" msgstr "" #: src/nemo-properties-window.c:3910 msgid "Folder access:" msgstr "" #: src/nemo-properties-window.c:3912 msgid "File access:" msgstr "" #: src/nemo-properties-window.c:3930 msgid "List files only" msgstr "" #: src/nemo-properties-window.c:3932 msgid "Access files" msgstr "" #: src/nemo-properties-window.c:3934 msgid "Create and delete files" msgstr "" #: src/nemo-properties-window.c:3941 msgid "Read-only" msgstr "" #: src/nemo-properties-window.c:3943 msgid "Read and write" msgstr "" #: src/nemo-properties-window.c:4008 msgid "Special flags:" msgstr "" #: src/nemo-properties-window.c:4010 msgid "Set _user ID" msgstr "" #: src/nemo-properties-window.c:4011 msgid "Set gro_up ID" msgstr "" #: src/nemo-properties-window.c:4012 msgid "_Sticky" msgstr "" #: src/nemo-properties-window.c:4086 src/nemo-properties-window.c:4278 msgid "_Owner:" msgstr "" #: src/nemo-properties-window.c:4094 src/nemo-properties-window.c:4183 #: src/nemo-properties-window.c:4288 msgid "Owner:" msgstr "" #: src/nemo-properties-window.c:4116 src/nemo-properties-window.c:4300 msgid "_Group:" msgstr "" #: src/nemo-properties-window.c:4124 src/nemo-properties-window.c:4184 #: src/nemo-properties-window.c:4308 msgid "Group:" msgstr "" #: src/nemo-properties-window.c:4163 msgid "Execute:" msgstr "" #: src/nemo-properties-window.c:4166 msgid "Allow _executing file as program" msgstr "" #: src/nemo-properties-window.c:4185 msgid "Others:" msgstr "" #: src/nemo-properties-window.c:4324 msgid "Folder Permissions:" msgstr "" #: src/nemo-properties-window.c:4332 msgid "File Permissions:" msgstr "" #: src/nemo-properties-window.c:4341 msgid "Text view:" msgstr "" #: src/nemo-properties-window.c:4475 #: libnemo-private/nemo-column-utilities.c:127 msgid "Permissions" msgstr "" #: src/nemo-properties-window.c:4489 msgid "You are not the owner, so you cannot change these permissions." msgstr "" #: src/nemo-properties-window.c:4509 msgid "SELinux context:" msgstr "" #: src/nemo-properties-window.c:4514 msgid "Last changed:" msgstr "" #: src/nemo-properties-window.c:4526 msgid "Apply Permissions to Enclosed Files" msgstr "" #: src/nemo-properties-window.c:4536 #, c-format msgid "The permissions of \"%s\" could not be determined." msgstr "" #: src/nemo-properties-window.c:4539 msgid "The permissions of the selected file could not be determined." msgstr "" #: src/nemo-properties-window.c:4778 msgid "Open With" msgstr "" #: src/nemo-properties-window.c:4916 msgid "Help" msgstr "" #: src/nemo-properties-window.c:4917 msgid "Close" msgstr "" #: src/nemo-properties-window.c:5135 msgid "Creating Properties window." msgstr "" #: src/nemo-properties-window.c:5396 msgid "Revert" msgstr "" #: src/nemo-query-editor.c:422 #, c-format msgid "in %s" msgstr "" #: src/nemo-query-editor.c:423 #, c-format msgid "Search for %s" msgstr "" #: src/nemo-query-editor.c:735 msgid "Type to search or arrow-up to select a favorite" msgstr "" #: src/nemo-query-editor.c:757 msgid "" "Click to save or forget a favorite search. Right-click to display favorites." msgstr "" #: src/nemo-script-config-widget.c:148 msgid "No scripts found" msgstr "" #: src/nemo-script-config-widget.c:345 msgid "Scripts" msgstr "" #: src/nemo-statusbar.c:176 msgid "Show Places" msgstr "" #: src/nemo-statusbar.c:185 msgid "Show Treeview" msgstr "" #: src/nemo-statusbar.c:199 msgid "Hide the Sidebar (F9)" msgstr "" #: src/nemo-statusbar.c:208 msgid "Show the Sidebar (F9)" msgstr "" #: src/nemo-statusbar.c:222 msgid "Adjust zoom level" msgstr "" #: src/nemo-thumbnail-problem-bar.c:114 msgid "" "A problem has been detected with your thumbnail cache. Fixing it will " "require administrative privileges." msgstr "" #: src/nemo-thumbnail-problem-bar.c:118 msgid "Fix now" msgstr "" #: src/nemo-thumbnail-problem-bar.c:121 msgid "Dismiss" msgstr "" #: src/nemo-toolbar.c:245 msgid "Elevated Privileges" msgstr "" #: src/nemo-trash-bar.c:218 msgid "Restore Selected Items" msgstr "" #: src/nemo-trash-bar.c:221 msgid "Restore selected items to their original position" msgstr "" #: src/nemo-tree-sidebar.c:788 src/nemo-view.c:8560 msgid "Unp_in" msgstr "" #: src/nemo-tree-sidebar.c:790 src/nemo-tree-sidebar.c:1396 #: src/nemo-view.c:8556 gresources/nemo-file-management-properties.glade:3528 msgid "P_in" msgstr "" #: src/nemo-tree-sidebar.c:965 src/nemo-view.c:6819 #, c-format msgid "\"%s\" will be moved if you select the Paste command" msgstr "" #: src/nemo-tree-sidebar.c:969 src/nemo-view.c:6823 #, c-format msgid "\"%s\" will be copied if you select the Paste command" msgstr "" #: src/nemo-tree-sidebar.c:1008 src/nemo-view.c:7073 msgid "There is nothing on the clipboard to paste." msgstr "" #. add the "create new folder" menu item #. name, stock id #. label, accelerator #: src/nemo-tree-sidebar.c:1345 src/nemo-view.c:8263 #: gresources/nemo-file-management-properties.glade:3752 msgid "Create New _Folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-tree-sidebar.c:1358 src/nemo-view.c:8318 src/nemo-view.c:8471 #: gresources/nemo-file-management-properties.glade:3452 msgid "Cu_t" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-tree-sidebar.c:1370 src/nemo-view.c:8322 src/nemo-view.c:8475 #: gresources/nemo-file-management-properties.glade:3471 msgid "_Copy" msgstr "" #. We make accelerator "" instead of null here to not inherit the stock #. accelerator for paste #. name, stock id #. label, accelerator #: src/nemo-tree-sidebar.c:1382 src/nemo-view.c:8332 src/nemo-view.c:8479 msgid "_Paste Into Folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-tree-sidebar.c:1426 src/nemo-view.c:8370 src/nemo-view.c:8488 #: src/nemo-view.c:9879 msgid "_Delete" msgstr "" #: src/nemo-tree-sidebar.c:1468 msgid "P_roperties" msgstr "" #: src/nemo-tree-sidebar.c:1546 libnemo-private/nemo-desktop-link.c:126 #: generate_additional_file:48 gresources/nemo-desktop-preferences.glade:133 #: gresources/nemo-file-management-properties.glade:2931 msgid "Computer" msgstr "" #: src/nemo-view.c:1073 #, c-format msgid "This will open %'d separate tab." msgid_plural "This will open %'d separate tabs." msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:1076 #, c-format msgid "This will open %'d separate window." msgid_plural "This will open %'d separate windows." msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:1674 msgid "Select Items Matching" msgstr "" #: src/nemo-view.c:1689 msgid "_Pattern:" msgstr "" #: src/nemo-view.c:1695 msgid "Examples: " msgstr "" #: src/nemo-view.c:1808 msgid "Save Search as" msgstr "" #: src/nemo-view.c:1831 msgid "Search _name:" msgstr "" #: src/nemo-view.c:1853 msgid "Select Folder to Save Search In" msgstr "" #. Reset to default info #: src/nemo-view.c:2643 libnemo-private/nemo-file-undo-operations.c:147 msgid "Undo" msgstr "" #: src/nemo-view.c:2644 libnemo-private/nemo-file-undo-operations.c:150 msgid "Undo last action" msgstr "" #. Reset to default info #: src/nemo-view.c:2662 libnemo-private/nemo-file-undo-operations.c:154 msgid "Redo" msgstr "" #: src/nemo-view.c:2663 libnemo-private/nemo-file-undo-operations.c:157 msgid "Redo last undone action" msgstr "" #: src/nemo-view.c:2851 msgid "Content View" msgstr "" #: src/nemo-view.c:2852 msgid "View of the current folder" msgstr "" #: src/nemo-view.c:3121 src/nemo-view.c:3158 #, c-format msgid "\"%s\" selected" msgstr "" #: src/nemo-view.c:3123 #, c-format msgid "%'d folder selected" msgid_plural "%'d folders selected" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:3133 #, c-format msgid " (containing %'d item)" msgid_plural " (containing %'d items)" msgstr[0] "" msgstr[1] "" #. translators: this is preceded with a string of form 'N folders' (N more than 1) #: src/nemo-view.c:3144 #, c-format msgid " (containing a total of %'d item)" msgid_plural " (containing a total of %'d items)" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:3161 #, c-format msgid "%'d item selected" msgid_plural "%'d items selected" msgstr[0] "" msgstr[1] "" #. Folders selected also, use "other" terminology #: src/nemo-view.c:3168 #, c-format msgid "%'d other item selected" msgid_plural "%'d other items selected" msgstr[0] "" msgstr[1] "" #. This is marked for translation in case a localiser #. * needs to use something other than parentheses. The #. * first message gives the number of items selected; #. * the message in parentheses the size of those items. #. #: src/nemo-view.c:3185 #, c-format msgid "%s (%s)" msgstr "" #: src/nemo-view.c:3206 libnemo-private/nemo-file.c:6235 #, c-format msgid "%'u item" msgid_plural "%'u items" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:3209 #, c-format msgid "%s, Free space: %s" msgstr "" #. Marking this for translation, since you #. * might want to change "," to something else. #. * After the comma the amount of free space will #. * be shown. #. #: src/nemo-view.c:3224 #, c-format msgid "%s, %s" msgstr "" #. Marking this for translation, since you #. * might want to change "," to something else. #. * After the comma the amount of free space will #. * be shown. #. #. This is marked for translation in case a localizer #. * needs to change ", " to something else. The comma #. * is between the message about the number of folders #. * and the number of items in those folders and the #. * message about the number of other items and the #. * total size of those items. #. #: src/nemo-view.c:3243 src/nemo-view.c:3256 #, c-format msgid "%s%s, %s" msgstr "" #. This is marked for translation in case a localizer #. * needs to change ", " to something else. The first comma #. * is between the message about the number of folders #. * and the number of items in those folders and the #. * message about the number of other items and the #. * total size of those items. After the second comma #. * the free space is written. #. #: src/nemo-view.c:3270 #, c-format msgid "%s%s, %s, %s" msgstr "" #: src/nemo-view.c:4758 #, c-format msgid "Open With %s" msgstr "" #: src/nemo-view.c:4760 #, c-format msgid "Use \"%s\" to open the selected item" msgid_plural "Use \"%s\" to open the selected items" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:6125 #, c-format msgid "Run \"%s\" on any selected items" msgstr "" #: src/nemo-view.c:6530 #, c-format msgid "Create a new document from template \"%s\"" msgstr "" #: src/nemo-view.c:6830 #, c-format msgid "The %'d selected item will be moved if you select the Paste command" msgid_plural "" "The %'d selected items will be moved if you select the Paste command" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:6837 #, c-format msgid "The %'d selected item will be copied if you select the Paste command" msgid_plural "" "The %'d selected items will be copied if you select the Paste command" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:7007 msgid "Select Target Folder For Move" msgstr "" #: src/nemo-view.c:7030 msgid "Select Target Folder For Copy" msgstr "" #: src/nemo-view.c:7504 msgid "Unable to unmount location" msgstr "" #: src/nemo-view.c:7524 msgid "Unable to eject location" msgstr "" #: src/nemo-view.c:7539 msgid "Unable to stop drive" msgstr "" #: src/nemo-view.c:8025 #, c-format msgid "Connect to Server %s" msgstr "" #: src/nemo-view.c:8030 src/nemo-view.c:9162 src/nemo-view.c:9249 #: src/nemo-view.c:9353 msgid "_Connect" msgstr "" #: src/nemo-view.c:8044 msgid "Link _name:" msgstr "" #. name, stock id, label #: src/nemo-view.c:8251 msgid "Create New _Document" msgstr "" #. name, stock id, label #: src/nemo-view.c:8252 msgid "Open Wit_h" msgstr "" #: src/nemo-view.c:8253 msgid "Choose a program with which to open the selected item" msgstr "" #. tooltip #: src/nemo-view.c:8256 src/nemo-view.c:9920 msgid "View or modify the properties of each selected item" msgstr "" #. tooltip #: src/nemo-view.c:8264 msgid "Create a new empty folder inside this folder" msgstr "" #. name, stock id, label #: src/nemo-view.c:8266 msgid "No templates installed" msgstr "" #. name, stock id #. translators: this is used to indicate that a document doesn't contain anything #. label, accelerator #: src/nemo-view.c:8269 msgid "_Empty Document" msgstr "" #. tooltip #: src/nemo-view.c:8270 msgid "Create a new empty document inside this folder" msgstr "" #. tooltip #: src/nemo-view.c:8274 msgid "Open the selected item in this window" msgstr "" #. name, stock id #. label, accelerator #. Location-specific actions #. name, stock id #. label, accelerator #: src/nemo-view.c:8281 src/nemo-view.c:8462 msgid "Open in Navigation Window" msgstr "" #. tooltip #: src/nemo-view.c:8282 msgid "Open each selected item in a navigation window" msgstr "" #. tooltip #: src/nemo-view.c:8286 msgid "Open each selected item in a new tab" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8289 src/nemo-window-menus.c:1625 #: gresources/nemo-file-management-properties.glade:3623 #: gresources/nemo-file-management-properties.glade:3790 msgid "Open in Terminal" msgstr "" #. tooltip #: src/nemo-view.c:8290 msgid "Open terminal in the selected folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8293 gresources/nemo-file-management-properties.glade:3641 #: gresources/nemo-file-management-properties.glade:3808 msgid "Open as Root" msgstr "" #. tooltip #: src/nemo-view.c:8294 msgid "Open the folder with administration privileges" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8298 msgid "Follow link to original file" msgstr "" #. tooltip #: src/nemo-view.c:8299 msgid "Navigate to the original file that this symbolic link points to" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8302 msgid "Open containing folder" msgstr "" #. tooltip #: src/nemo-view.c:8303 msgid "Navigate to the folder that the selected item is stored in" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8306 msgid "Other _Application..." msgstr "" #. tooltip #: src/nemo-view.c:8307 src/nemo-view.c:8311 msgid "Choose another application with which to open the selected item" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8310 msgid "Open With Other _Application..." msgstr "" #. tooltip #: src/nemo-view.c:8319 msgid "Prepare the selected files to be moved with a Paste command" msgstr "" #. tooltip #: src/nemo-view.c:8323 msgid "Prepare the selected files to be copied with a Paste command" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8326 gresources/nemo-file-management-properties.glade:3490 #: gresources/nemo-file-management-properties.glade:3845 msgid "_Paste" msgstr "" #. tooltip #: src/nemo-view.c:8327 msgid "Move or copy files previously selected by a Cut or Copy command" msgstr "" #. tooltip #: src/nemo-view.c:8333 msgid "" "Move or copy files previously selected by a Cut or Copy command into the " "selected folder" msgstr "" #. name, stock id, label #: src/nemo-view.c:8335 gresources/nemo-file-management-properties.glade:3585 msgid "Cop_y to" msgstr "" #. name, stock id, label #: src/nemo-view.c:8336 gresources/nemo-file-management-properties.glade:3604 msgid "M_ove to" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8338 libnemo-private/nemo-clipboard.c:444 msgid "Select _All" msgstr "" #. tooltip #: src/nemo-view.c:8339 msgid "Select all items in this window" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8342 msgid "Select I_tems Matching..." msgstr "" #. tooltip #: src/nemo-view.c:8343 msgid "Select items in this window matching a given pattern" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8346 msgid "_Invert Selection" msgstr "" #. tooltip #: src/nemo-view.c:8347 msgid "Select all and only the items that are not currently selected" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8350 gresources/nemo-file-management-properties.glade:3509 msgid "D_uplicate" msgstr "" #. tooltip #: src/nemo-view.c:8351 msgid "Duplicate each selected item" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8354 src/nemo-view.c:9905 #: gresources/nemo-file-management-properties.glade:3547 msgid "Ma_ke Link" msgid_plural "Ma_ke Links" msgstr[0] "" msgstr[1] "" #. tooltip #: src/nemo-view.c:8355 msgid "Create a symbolic link for each selected item" msgstr "" #. tooltip #: src/nemo-view.c:8359 msgid "Rename selected item" msgstr "" #. tooltip #: src/nemo-view.c:8367 src/nemo-view.c:9857 msgid "Move each selected item to the Trash" msgstr "" #. tooltip #: src/nemo-view.c:8371 src/nemo-view.c:9880 msgid "Delete each selected item, without moving to the Trash" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8374 src/nemo-view.c:8492 msgid "_Restore" msgstr "" #. name, stock id #. label, accelerator #. name, stock id, label #: src/nemo-view.c:8378 src/nemo-window-menus.c:1291 msgid "_Undo" msgstr "" #. tooltip #: src/nemo-view.c:8379 msgid "Undo the last action" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8382 msgid "_Redo" msgstr "" #. tooltip #: src/nemo-view.c:8383 msgid "Redo the last undone action" msgstr "" #. #. * multiview-TODO: decide whether "Reset to Defaults" should #. * be window-wide, and not just view-wide. #. * Since this also resets the "Show hidden files" mode, #. * it is a mixture of both ATM. #. #. name, stock id #. label, accelerator #: src/nemo-view.c:8392 msgid "Reset View to _Defaults" msgstr "" #. tooltip #: src/nemo-view.c:8393 msgid "Reset sorting order and zoom level to match preferences for this view" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8396 msgid "Connect To This Server" msgstr "" #. tooltip #: src/nemo-view.c:8397 msgid "Make a permanent connection to this server" msgstr "" #. tooltip #: src/nemo-view.c:8401 msgid "Mount the selected volume" msgstr "" #. tooltip #: src/nemo-view.c:8405 msgid "Unmount the selected volume" msgstr "" #. tooltip #: src/nemo-view.c:8409 msgid "Eject the selected volume" msgstr "" #. tooltip #: src/nemo-view.c:8413 msgid "Start the selected volume" msgstr "" #. tooltip #: src/nemo-view.c:8417 src/nemo-view.c:9375 msgid "Stop the selected volume" msgstr "" #. tooltip #: src/nemo-view.c:8421 src/nemo-view.c:8445 src/nemo-view.c:8517 msgid "Detect media in the selected drive" msgstr "" #. tooltip #: src/nemo-view.c:8425 msgid "Mount the volume associated with the open folder" msgstr "" #. tooltip #: src/nemo-view.c:8429 msgid "Unmount the volume associated with the open folder" msgstr "" #. tooltip #: src/nemo-view.c:8433 msgid "Eject the volume associated with the open folder" msgstr "" #. tooltip #: src/nemo-view.c:8437 msgid "Start the volume associated with the open folder" msgstr "" #. tooltip #: src/nemo-view.c:8441 msgid "Stop the volume associated with the open folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8448 msgid "Open File and Close window" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8452 msgid "Sa_ve Search" msgstr "" #. tooltip #: src/nemo-view.c:8453 msgid "Save the edited search" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-view.c:8456 msgid "Sa_ve Search As..." msgstr "" #. tooltip #: src/nemo-view.c:8457 msgid "Save the current search as a file" msgstr "" #. tooltip #: src/nemo-view.c:8463 msgid "Open this folder in a navigation window" msgstr "" #. tooltip #: src/nemo-view.c:8467 msgid "Open this folder in a new tab" msgstr "" #. tooltip #: src/nemo-view.c:8472 msgid "Prepare this folder to be moved with a Paste command" msgstr "" #. tooltip #: src/nemo-view.c:8476 msgid "Prepare this folder to be copied with a Paste command" msgstr "" #. tooltip #: src/nemo-view.c:8480 msgid "" "Move or copy files previously selected by a Cut or Copy command into this " "folder" msgstr "" #. tooltip #: src/nemo-view.c:8485 msgid "Move this folder to the Trash" msgstr "" #. tooltip #: src/nemo-view.c:8489 msgid "Delete this folder, without moving to the Trash" msgstr "" #. tooltip #: src/nemo-view.c:8497 msgid "Mount the volume associated with this folder" msgstr "" #. tooltip #: src/nemo-view.c:8501 msgid "Unmount the volume associated with this folder" msgstr "" #. tooltip #: src/nemo-view.c:8505 msgid "Eject the volume associated with this folder" msgstr "" #. tooltip #: src/nemo-view.c:8509 msgid "Start the volume associated with this folder" msgstr "" #. tooltip #: src/nemo-view.c:8513 msgid "Stop the volume associated with this folder" msgstr "" #. tooltip #: src/nemo-view.c:8522 msgid "View or modify the properties of this folder" msgstr "" #. name, stock id, label #: src/nemo-view.c:8525 src/nemo-view.c:8528 msgid "_Other pane" msgstr "" #: src/nemo-view.c:8526 msgid "Copy the current selection to the other pane in the window" msgstr "" #: src/nemo-view.c:8529 msgid "Move the current selection to the other pane in the window" msgstr "" #. name, stock id, label #. name, stock id #. label, accelerator #: src/nemo-view.c:8532 src/nemo-view.c:8536 src/nemo-window-menus.c:1366 #: src/nemo-window-menus.c:1575 src/nemo-window-menus.c:1804 msgid "_Home" msgstr "" #: src/nemo-view.c:8533 msgid "Copy the current selection to the home folder" msgstr "" #: src/nemo-view.c:8537 msgid "Move the current selection to the home folder" msgstr "" #. name, stock id, label #: src/nemo-view.c:8540 src/nemo-view.c:8544 msgid "_Desktop" msgstr "" #: src/nemo-view.c:8541 msgid "Copy the current selection to the desktop" msgstr "" #: src/nemo-view.c:8545 msgid "Move the current selection to the desktop" msgstr "" #: src/nemo-view.c:8548 src/nemo-view.c:8552 msgid "Browse..." msgstr "" #: src/nemo-view.c:8549 msgid "Browse for a folder to move the selection to" msgstr "" #: src/nemo-view.c:8553 msgid "Browse for a folder to copy the selection to" msgstr "" #: src/nemo-view.c:8557 msgid "" "Pin the selected file so it always appears at the top of this location's " "file list" msgstr "" #: src/nemo-view.c:8561 msgid "Unpin the selected file from the top of this location's file list" msgstr "" #: src/nemo-view.c:8636 msgid "Run scripts" msgstr "" #. Create a script action here specially because its tooltip is dynamic #: src/nemo-view.c:8638 gresources/nemo-file-management-properties.glade:3433 #: gresources/nemo-file-management-properties.glade:3771 msgid "_Scripts" msgstr "" #: src/nemo-view.c:9011 #, c-format msgid "Move the open folder out of the trash to \"%s\"" msgstr "" #: src/nemo-view.c:9014 #, c-format msgid "Move the selected folder out of the trash to \"%s\"" msgid_plural "Move the selected folders out of the trash to \"%s\"" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9018 msgid "Move the selected folder out of the trash" msgid_plural "Move the selected folders out of the trash" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9024 #, c-format msgid "Move the selected file out of the trash to \"%s\"" msgid_plural "Move the selected files out of the trash to \"%s\"" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9028 msgid "Move the selected file out of the trash" msgid_plural "Move the selected files out of the trash" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9034 #, c-format msgid "Move the selected item out of the trash to \"%s\"" msgid_plural "Move the selected items out of the trash to \"%s\"" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9038 msgid "Move the selected item out of the trash" msgid_plural "Move the selected items out of the trash" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9155 src/nemo-view.c:9159 src/nemo-view.c:9346 #: src/nemo-view.c:9350 msgid "Start the selected drive" msgstr "" #: src/nemo-view.c:9163 src/nemo-view.c:9354 msgid "Connect to the selected drive" msgstr "" #: src/nemo-view.c:9166 src/nemo-view.c:9253 src/nemo-view.c:9357 msgid "_Start Multi-disk Drive" msgstr "" #: src/nemo-view.c:9167 src/nemo-view.c:9358 msgid "Start the selected multi-disk drive" msgstr "" #: src/nemo-view.c:9170 msgid "U_nlock Drive" msgstr "" #: src/nemo-view.c:9171 src/nemo-view.c:9362 msgid "Unlock the selected drive" msgstr "" #: src/nemo-view.c:9184 msgid "Stop the selected drive" msgstr "" #: src/nemo-view.c:9188 src/nemo-view.c:9379 msgid "Safely remove the selected drive" msgstr "" #: src/nemo-view.c:9191 src/nemo-view.c:9278 src/nemo-view.c:9382 msgid "_Disconnect" msgstr "" #: src/nemo-view.c:9192 src/nemo-view.c:9383 msgid "Disconnect the selected drive" msgstr "" #: src/nemo-view.c:9195 src/nemo-view.c:9282 src/nemo-view.c:9386 msgid "_Stop Multi-disk Drive" msgstr "" #: src/nemo-view.c:9196 src/nemo-view.c:9387 msgid "Stop the selected multi-disk drive" msgstr "" #: src/nemo-view.c:9200 src/nemo-view.c:9391 msgid "Lock the selected drive" msgstr "" #: src/nemo-view.c:9242 src/nemo-view.c:9246 msgid "Start the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9250 msgid "Connect to the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9254 msgid "Start the multi-disk drive associated with the open folder" msgstr "" #: src/nemo-view.c:9258 msgid "Unlock the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9271 msgid "_Stop the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9275 msgid "Safely remove the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9279 msgid "Disconnect the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9283 msgid "Stop the multi-disk drive associated with the open folder" msgstr "" #: src/nemo-view.c:9287 msgid "Lock the drive associated with the open folder" msgstr "" #: src/nemo-view.c:9527 src/nemo-view.c:9852 msgid "_Delete Permanently" msgstr "" #: src/nemo-view.c:9528 msgid "Delete the open folder permanently" msgstr "" #: src/nemo-view.c:9532 msgid "Move the open folder to the Trash" msgstr "" #: src/nemo-view.c:9766 #, c-format msgid "_Open With %s" msgstr "" #: src/nemo-view.c:9815 #, c-format msgid "Open in %'d New _Window" msgid_plural "Open in %'d New _Windows" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9835 #, c-format msgid "Open in %'d New _Tab" msgid_plural "Open in %'d New _Tabs" msgstr[0] "" msgstr[1] "" #: src/nemo-view.c:9853 msgid "Delete all selected items permanently" msgstr "" #: src/nemo-view.c:9876 msgid "Remo_ve from Recent" msgstr "" #: src/nemo-view.c:9877 msgid "Remove each selected item from the recently used list" msgstr "" #: src/nemo-view.c:9918 msgid "View or modify the properties of the open folder" msgstr "" #. Note to localizers: convert file type string for file #. * (e.g. "folder", "plain text") to file type for symbolic link #. * to that kind of file (e.g. "link to folder"). #. #. appended to new link file #: src/nemo-view-dnd.c:125 libnemo-private/nemo-file.c:6861 #: libnemo-private/nemo-file-operations.c:393 #, c-format msgid "Link to %s" msgstr "" #: src/nemo-view-dnd.c:171 src/nemo-view-dnd.c:205 src/nemo-view-dnd.c:298 msgid "Drag and drop is not supported." msgstr "" #: src/nemo-view-dnd.c:172 msgid "Drag and drop is only supported on local file systems." msgstr "" #: src/nemo-view-dnd.c:206 src/nemo-view-dnd.c:299 msgid "An invalid drag type was used." msgstr "" #. Translator: This is the filename used for when you dnd text to a directory #: src/nemo-view-dnd.c:376 msgid "dropped text.txt" msgstr "" #. Translator: This is the filename used for when you dnd raw #. * data to a directory, if the source didn't supply a name. #. #: src/nemo-view-dnd.c:421 msgid "dropped data" msgstr "" #: src/nemo-window-bookmarks.c:83 msgid "" "Do you want to remove any bookmarks with the non-existing location from your " "list?" msgstr "" #: src/nemo-window-bookmarks.c:85 #, c-format msgid "The location \"%s\" does not exist." msgstr "" #: src/nemo-window-bookmarks.c:88 msgid "Bookmark for Nonexistent Location" msgstr "" #: src/nemo-window-bookmarks.c:308 msgid "Go to the location specified by this bookmark" msgstr "" #: src/nemo-window.c:1370 #, c-format msgid "%s - File Browser" msgstr "" #. Set initial window title #: src/nemo-window.c:1966 src/nemo-window-menus.c:339 msgid "Nemo" msgstr "" #: src/nemo-window-manage-views.c:1221 msgid "Searching..." msgstr "" #: src/nemo-window-manage-views.c:1705 src/nemo-window-manage-views.c:1711 #: src/nemo-window-manage-views.c:1728 src/nemo-window-manage-views.c:1739 #: src/nemo-window-manage-views.c:1745 src/nemo-window-manage-views.c:1771 #, c-format msgid "Could not display \"%s\"." msgstr "" #: src/nemo-window-manage-views.c:1708 msgid "Nemo has no installed viewer capable of displaying the folder." msgstr "" #: src/nemo-window-manage-views.c:1714 msgid "The location is not a folder." msgstr "" #: src/nemo-window-manage-views.c:1720 #, c-format msgid "Could not find \"%s\"." msgstr "" #: src/nemo-window-manage-views.c:1723 msgid "Please check the spelling and try again." msgstr "" #: src/nemo-window-manage-views.c:1731 #, c-format msgid "Nemo cannot handle \"%s\" locations." msgstr "" #: src/nemo-window-manage-views.c:1734 msgid "Nemo cannot handle this kind of location." msgstr "" #: src/nemo-window-manage-views.c:1741 msgid "Unable to mount the location." msgstr "" #: src/nemo-window-manage-views.c:1747 msgid "Access was denied." msgstr "" #. This case can be hit for user-typed strings like "foo" due to #. * the code that guesses web addresses when there's no initial "/". #. * But this case is also hit for legitimate web addresses when #. * the proxy is set up wrong. #. #: src/nemo-window-manage-views.c:1756 #, c-format msgid "Could not display \"%s\", because the host could not be found." msgstr "" #: src/nemo-window-manage-views.c:1758 msgid "" "Check that the spelling is correct and that your proxy settings are correct." msgstr "" #: src/nemo-window-manage-views.c:1773 #, c-format msgid "" "Error: %s\n" "Please select another viewer and try again." msgstr "" #: src/nemo-window-menus.c:318 msgid "" "Nemo 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." msgstr "" #: src/nemo-window-menus.c:322 msgid "" "Nemo 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." msgstr "" #: src/nemo-window-menus.c:326 msgid "" "You should have received a copy of the GNU General Public License along with " "Nemo; if not, write to the Free Software Foundation, Inc., 51 Franklin " "Street, Fifth Floor, Boston, MA 02110-1301 USA" msgstr "" #: src/nemo-window-menus.c:341 msgid "" "Nemo lets you organize files and folders, both on your computer and online." msgstr "" #: src/nemo-window-menus.c:402 #, c-format msgid "" "There was an error displaying help: \n" "%s" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1274 msgid "_File" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1275 msgid "_Edit" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1276 msgid "_View" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1277 msgid "_Help" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1279 msgid "_Close" msgstr "" #. tooltip #: src/nemo-window-menus.c:1280 msgid "Close this folder" msgstr "" #: src/nemo-window-menus.c:1283 msgid "Prefere_nces" msgstr "" #: src/nemo-window-menus.c:1284 msgid "Edit Nemo preferences" msgstr "" #: src/nemo-window-menus.c:1287 #: gresources/nemo-file-management-properties.glade:4097 msgid "Plugins" msgstr "" #: src/nemo-window-menus.c:1288 msgid "Manage extensions, actions and scripts" msgstr "" #: src/nemo-window-menus.c:1292 msgid "Undo the last text change" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1295 msgid "Open _Parent" msgstr "" #: src/nemo-window-menus.c:1296 msgid "Open the parent folder" msgstr "" #. tooltip #: src/nemo-window-menus.c:1303 msgid "Stop loading the current location" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1306 src/nemo-window-menus.c:1561 msgid "_Reload" msgstr "" #. tooltip #: src/nemo-window-menus.c:1307 src/nemo-window-menus.c:1563 msgid "Reload the current location" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1310 msgid "_All Topics" msgstr "" #. tooltip #: src/nemo-window-menus.c:1311 msgid "Display Nemo help" msgstr "" #: src/nemo-window-menus.c:1314 msgid "_Keyboard Shortcuts" msgstr "" #: src/nemo-window-menus.c:1315 msgid "Display keyboard shortcuts" msgstr "" #. * name, stock id { "NemoHelpSearch", NULL, #. label, accelerator N_("Search for files"), NULL, #. tooltip N_("Locate files based on file name and type. Save your searches for later use."), #. G_CALLBACK (action_nemo_manual_callback) }, #. name, stock id { "NemoHelpSort", NULL, #. label, accelerator N_("Sort files and folders"), NULL, #. tooltip N_("Arrange files by name, size, type, or when they were changed."), #. G_CALLBACK (action_nemo_manual_callback) }, #. name, stock id { "NemoHelpLost", NULL, #. label, accelerator N_("Find a lost file"), NULL, #. tooltip N_("Follow these tips if you can't find a file you created or downloaded."), #. G_CALLBACK (action_nemo_manual_callback) }, #. name, stock id { "NemoHelpShare", NULL, #. label, accelerator N_("Share and transfer files"), NULL, #. tooltip N_("Easily transfer files to your contacts and devices from the file manager."), #. G_CALLBACK (action_nemo_manual_callback) }, * #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1334 msgid "_About" msgstr "" #. tooltip #: src/nemo-window-menus.c:1335 msgid "Display credits for the creators of Nemo" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1338 msgid "Zoom _In" msgstr "" #. tooltip #: src/nemo-window-menus.c:1339 msgid "Increase the view size" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1350 msgid "Zoom _Out" msgstr "" #. tooltip #: src/nemo-window-menus.c:1351 msgid "Decrease the view size" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1358 msgid "Normal Si_ze" msgstr "" #. tooltip #: src/nemo-window-menus.c:1359 msgid "Use the normal view size" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1362 msgid "Connect to _Server..." msgstr "" #. tooltip #: src/nemo-window-menus.c:1363 msgid "Connect to a remote computer or shared disk" msgstr "" #. tooltip #: src/nemo-window-menus.c:1367 msgid "Open your personal folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1370 src/nemo-window-menus.c:1589 msgid "_Computer" msgstr "" #. tooltip #: src/nemo-window-menus.c:1371 msgid "" "Browse all local and remote disks and folders accessible from this computer" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1374 msgid "_Network" msgstr "" #. tooltip #: src/nemo-window-menus.c:1375 msgid "Browse bookmarked and local network locations" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1378 msgid "T_emplates" msgstr "" #. tooltip #: src/nemo-window-menus.c:1379 msgid "Open your personal templates folder" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1382 msgid "_Trash" msgstr "" #. tooltip #: src/nemo-window-menus.c:1383 msgid "Open your personal trash folder" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1385 msgid "_Go" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1386 msgid "_Bookmarks" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1387 msgid "_Tabs" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1388 msgid "New _Window" msgstr "" #: src/nemo-window-menus.c:1389 msgid "Open another Nemo window for the displayed location" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1391 msgid "New _Tab" msgstr "" #: src/nemo-window-menus.c:1392 msgid "Open another tab for the displayed location" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1394 msgid "Close _All Windows" msgstr "" #: src/nemo-window-menus.c:1395 msgid "Close all Navigation windows" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1397 src/nemo-window-menus.c:1511 msgid "_Back" msgstr "" #: src/nemo-window-menus.c:1398 src/nemo-window-menus.c:1513 msgid "Go to the previous visited location" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1400 src/nemo-window-menus.c:1527 msgid "_Forward" msgstr "" #: src/nemo-window-menus.c:1401 src/nemo-window-menus.c:1529 msgid "Go to the next visited location" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1403 msgid "Toggle _Location Entry" msgstr "" #: src/nemo-window-menus.c:1404 msgid "Switch between location entry and breadcrumbs" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1406 msgid "S_witch to Other Pane" msgstr "" #: src/nemo-window-menus.c:1407 msgid "Move focus to the other pane in a split view window" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1409 msgid "Sa_me Location as Other Pane" msgstr "" #: src/nemo-window-menus.c:1410 msgid "Go to the same location as in the extra pane" msgstr "" #: src/nemo-window-menus.c:1413 msgid "Add a bookmark for the current location to this menu" msgstr "" #. name, stock id, label #: src/nemo-window-menus.c:1415 msgid "_Edit Bookmarks..." msgstr "" #: src/nemo-window-menus.c:1416 msgid "Display a window that allows editing the bookmarks in this menu" msgstr "" #: src/nemo-window-menus.c:1418 msgid "_Previous Tab" msgstr "" #: src/nemo-window-menus.c:1419 msgid "Activate previous tab" msgstr "" #: src/nemo-window-menus.c:1421 msgid "_Next Tab" msgstr "" #: src/nemo-window-menus.c:1422 msgid "Activate next tab" msgstr "" #: src/nemo-window-menus.c:1424 src/nemo-window-pane.c:498 msgid "Move Tab _Left" msgstr "" #: src/nemo-window-menus.c:1425 msgid "Move current tab to left" msgstr "" #: src/nemo-window-menus.c:1427 src/nemo-window-pane.c:506 msgid "Move Tab _Right" msgstr "" #: src/nemo-window-menus.c:1428 msgid "Move current tab to right" msgstr "" #: src/nemo-window-menus.c:1430 msgid "Sidebar" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1435 #: gresources/nemo-file-management-properties.glade:3826 msgid "Show _Hidden Files" msgstr "" #. tooltip #: src/nemo-window-menus.c:1436 msgid "Toggle the display of hidden files in the current window" msgstr "" #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1440 msgid "_Main Toolbar" msgstr "" #. tooltip #: src/nemo-window-menus.c:1441 msgid "Change the visibility of this window's main toolbar" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1445 msgid "_Show Sidebar" msgstr "" #. tooltip #: src/nemo-window-menus.c:1446 msgid "Change the visibility of this window's side pane" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1450 msgid "St_atusbar" msgstr "" #. tooltip #: src/nemo-window-menus.c:1451 msgid "Change the visibility of this window's statusbar" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1455 msgid "M_enubar" msgstr "" #. tooltip #: src/nemo-window-menus.c:1456 msgid "Change the default visibility of the menubar" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1460 msgid "_Search for Files..." msgstr "" #. tooltip #: src/nemo-window-menus.c:1461 src/nemo-window-menus.c:1671 msgid "Search documents and folders by name" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1465 msgid "E_xtra Pane" msgstr "" #. tooltip #: src/nemo-window-menus.c:1466 msgid "Open an extra folder view side-by-side" msgstr "" #. is_active #. name, stock id #. label, accelerator #: src/nemo-window-menus.c:1470 msgid "Show _Thumbnails" msgstr "" #. tooltip #: src/nemo-window-menus.c:1471 msgid "Toggle the display of thumbnails in the current directory" msgstr "" #: src/nemo-window-menus.c:1478 msgid "Places" msgstr "" #: src/nemo-window-menus.c:1478 msgid "Select Places as the default sidebar" msgstr "" #: src/nemo-window-menus.c:1481 msgid "Tree" msgstr "" #: src/nemo-window-menus.c:1481 msgid "Select Tree as the default sidebar" msgstr "" #: src/nemo-window-menus.c:1514 msgid "Back history" msgstr "" #: src/nemo-window-menus.c:1530 src/nemo-window-menus.c:1549 msgid "Forward history" msgstr "" #: src/nemo-window-menus.c:1546 src/nemo-window-menus.c:1801 msgid "_Up" msgstr "" #: src/nemo-window-menus.c:1548 msgid "Go to parent folder" msgstr "" #: src/nemo-window-menus.c:1577 msgid "Go to home directory" msgstr "" #: src/nemo-window-menus.c:1591 msgid "Go to Computer" msgstr "" #: src/nemo-window-menus.c:1603 msgid "Toggle Location Entry" msgstr "" #: src/nemo-window-menus.c:1615 #: gresources/nemo-file-management-properties.glade:3079 msgid "New folder" msgstr "" #: src/nemo-window-menus.c:1616 msgid "Create a new folder" msgstr "" #: src/nemo-window-menus.c:1626 msgid "Open a terminal in the active folder" msgstr "" #: src/nemo-window-menus.c:1636 msgid "Icons" msgstr "" #: src/nemo-window-menus.c:1647 msgid "List" msgstr "" #: src/nemo-window-menus.c:1659 msgid "Compact" msgstr "" #: src/nemo-window-menus.c:1671 libnemo-private/nemo-query.c:162 #: libnemo-private/nemo-search-directory-file.c:164 #: libnemo-private/nemo-search-directory-file.c:190 #: libnemo-private/nemo-search-directory-file.c:224 #: gresources/nemo-file-management-properties.glade:3116 msgid "Search" msgstr "" #: src/nemo-window-menus.c:1680 src/nemo-window-menus.c:1681 #: gresources/nemo-file-management-properties.glade:3264 msgid "Show Thumbnails" msgstr "" #: src/nemo-window-menus.c:1807 msgid "_Location" msgstr "" #: src/nemo-window-pane.c:481 msgid "_New Tab" msgstr "" #: src/nemo-window-pane.c:517 msgid "_Close Tab" msgstr "" #: src/nemo-x-content-bar.c:97 msgid "These files are on an Audio CD." msgstr "" #: src/nemo-x-content-bar.c:99 msgid "These files are on an Audio DVD." msgstr "" #: src/nemo-x-content-bar.c:101 msgid "These files are on a Video DVD." msgstr "" #: src/nemo-x-content-bar.c:103 msgid "These files are on a Video CD." msgstr "" #: src/nemo-x-content-bar.c:105 msgid "These files are on a Super Video CD." msgstr "" #: src/nemo-x-content-bar.c:107 msgid "These files are on a Photo CD." msgstr "" #: src/nemo-x-content-bar.c:109 msgid "These files are on a Picture CD." msgstr "" #: src/nemo-x-content-bar.c:111 msgid "The media contains digital photos." msgstr "" #: src/nemo-x-content-bar.c:113 msgid "These files are on a digital audio player." msgstr "" #: src/nemo-x-content-bar.c:115 msgid "The media contains software." msgstr "" #. fallback to generic greeting #: src/nemo-x-content-bar.c:118 #, c-format msgid "The media has been detected as \"%s\"." msgstr "" #: src/nemo-x-content-bar.c:143 #, c-format msgid "Open %s" msgstr "" #. name, stock id #. label, accelerator #. tooltip #: libnemo-private/nemo-clipboard.c:433 msgid "Cut the selected text to the clipboard" msgstr "" #. name, stock id #. label, accelerator #. tooltip #: libnemo-private/nemo-clipboard.c:437 msgid "Copy the selected text to the clipboard" msgstr "" #. name, stock id #. label, accelerator #. tooltip #: libnemo-private/nemo-clipboard.c:441 msgid "Paste the text stored on the clipboard" msgstr "" #. tooltip #: libnemo-private/nemo-clipboard.c:445 msgid "Select all the text in a text field" msgstr "" #: libnemo-private/nemo-column-chooser.c:371 msgid "Move _Up" msgstr "" #: libnemo-private/nemo-column-chooser.c:381 msgid "Move Dow_n" msgstr "" #: libnemo-private/nemo-column-chooser.c:394 msgid "Use De_fault" msgstr "" #: libnemo-private/nemo-column-utilities.c:44 msgid "The name and icon of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:51 msgid "The size of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:59 msgid "The general type of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:65 msgid "Detailed Type" msgstr "" #: libnemo-private/nemo-column-utilities.c:66 msgid "The specific type of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:73 #: libnemo-private/nemo-column-utilities.c:80 msgid "The date the file was modified." msgstr "" #: libnemo-private/nemo-column-utilities.c:79 msgid "Modified - Time" msgstr "" #: libnemo-private/nemo-column-utilities.c:88 msgid "Date Created" msgstr "" #: libnemo-private/nemo-column-utilities.c:89 #: libnemo-private/nemo-column-utilities.c:96 msgid "The date the file was created." msgstr "" #: libnemo-private/nemo-column-utilities.c:95 msgid "Created - Time" msgstr "" #: libnemo-private/nemo-column-utilities.c:103 msgid "Date Accessed" msgstr "" #: libnemo-private/nemo-column-utilities.c:104 msgid "The date the file was accessed." msgstr "" #: libnemo-private/nemo-column-utilities.c:111 msgid "Owner" msgstr "" #: libnemo-private/nemo-column-utilities.c:112 msgid "The owner of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:119 msgid "Group" msgstr "" #: libnemo-private/nemo-column-utilities.c:120 msgid "The group of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:128 msgid "The permissions of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:135 msgid "Octal Permissions" msgstr "" #: libnemo-private/nemo-column-utilities.c:136 msgid "The permissions of the file, in octal notation." msgstr "" #: libnemo-private/nemo-column-utilities.c:143 msgid "MIME Type" msgstr "" #: libnemo-private/nemo-column-utilities.c:144 msgid "The mime type of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:151 msgid "SELinux Context" msgstr "" #: libnemo-private/nemo-column-utilities.c:152 msgid "The SELinux security context of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:160 msgid "The location of the file." msgstr "" #: libnemo-private/nemo-column-utilities.c:201 msgid "Trashed On" msgstr "" #: libnemo-private/nemo-column-utilities.c:202 msgid "Date when file was moved to the Trash" msgstr "" #: libnemo-private/nemo-column-utilities.c:208 msgid "Original Location" msgstr "" #: libnemo-private/nemo-column-utilities.c:209 msgid "Original location of file before moved to the Trash" msgstr "" #: libnemo-private/nemo-desktop-directory-file.c:459 #: libnemo-private/nemo-desktop-icon-file.c:154 msgid "on the desktop" msgstr "" #: libnemo-private/nemo-desktop-link-monitor.c:89 #, c-format msgid "You cannot move the volume \"%s\" to the trash." msgstr "" #: libnemo-private/nemo-desktop-link-monitor.c:99 msgid "" "If you want to eject the volume, please use \"Eject\" in the popup menu of " "the volume." msgstr "" #: libnemo-private/nemo-desktop-link-monitor.c:108 msgid "" "If you want to unmount the volume, please use \"Unmount Volume\" in the " "popup menu of the volume." msgstr "" #: libnemo-private/nemo-dnd.c:854 msgid "_Move Here" msgstr "" #: libnemo-private/nemo-dnd.c:859 msgid "_Copy Here" msgstr "" #: libnemo-private/nemo-dnd.c:864 msgid "_Link Here" msgstr "" #: libnemo-private/nemo-dnd.c:871 msgid "Cancel" msgstr "" #: libnemo-private/nemo-file.c:1251 libnemo-private/nemo-vfs-file.c:416 msgid "This file cannot be mounted" msgstr "" #: libnemo-private/nemo-file.c:1296 msgid "This file cannot be unmounted" msgstr "" #: libnemo-private/nemo-file.c:1330 msgid "This file cannot be ejected" msgstr "" #: libnemo-private/nemo-file.c:1363 libnemo-private/nemo-vfs-file.c:594 msgid "This file cannot be started" msgstr "" #: libnemo-private/nemo-file.c:1415 libnemo-private/nemo-file.c:1446 msgid "This file cannot be stopped" msgstr "" #: libnemo-private/nemo-file.c:1874 msgid "Slashes are not allowed in filenames" msgstr "" #: libnemo-private/nemo-file.c:1892 msgid "File not found" msgstr "" #: libnemo-private/nemo-file.c:1920 msgid "Toplevel files cannot be renamed" msgstr "" #: libnemo-private/nemo-file.c:1943 msgid "Unable to rename desktop icon" msgstr "" #: libnemo-private/nemo-file.c:1972 msgid "Unable to rename desktop file" msgstr "" #. Translators: Time in 24h format #: libnemo-private/nemo-file.c:4943 msgid "%H:%M" msgstr "" #. Translators: Time in 12h format #: libnemo-private/nemo-file.c:4946 msgid "%l:%M %p" msgstr "" #. Translators: this is the word Yesterday followed by #. * a time in 24h format. i.e. "Yesterday 23:04" #: libnemo-private/nemo-file.c:4959 #, no-c-format msgid "Yesterday %H:%M" msgstr "" #. Translators: this is the word Yesterday followed by #. * a time in 12h format. i.e. "Yesterday 9:04 PM" #: libnemo-private/nemo-file.c:4964 #, no-c-format msgid "Yesterday %l:%M %p" msgstr "" #: libnemo-private/nemo-file.c:4972 #, no-c-format msgid "%A" msgstr "" #. Translators: this is the name of the week day followed by #. * a time in 24h format. i.e. "Monday 23:04" #: libnemo-private/nemo-file.c:4978 #, no-c-format msgid "%A %H:%M" msgstr "" #. Translators: this is the week day name followed by #. * a time in 12h format. i.e. "Monday 9:04 PM" #: libnemo-private/nemo-file.c:4983 #, no-c-format msgid "%A %l:%M %p" msgstr "" #. Translators: this is the day of the month followed #. * by the abbreviated month name i.e. "3 February" #: libnemo-private/nemo-file.c:4991 #, no-c-format msgid "%-e %B" msgstr "" #. Translators: this is the day of the month followed #. * by the abbreviated month name followed by a time in #. * 24h format i.e. "3 February 23:04" #: libnemo-private/nemo-file.c:4998 #, no-c-format msgid "%-e %B %H:%M" msgstr "" #. Translators: this is the day of the month followed #. * by the abbreviated month name followed by a time in #. * 12h format i.e. "3 February 9:04" #: libnemo-private/nemo-file.c:5004 #, no-c-format msgid "%-e %B %l:%M %p" msgstr "" #. Translators: this is the day of the month followed by the abbreviated #. * month name followed by the year i.e. "3 Feb 2015" #: libnemo-private/nemo-file.c:5012 #, no-c-format msgid "%-e %b %Y" msgstr "" #. Translators: this is the day number followed #. * by the abbreviated month name followed by the year followed #. * by a time in 24h format i.e. "3 Feb 2015 23:04" #: libnemo-private/nemo-file.c:5019 #, no-c-format msgid "%-e %b %Y %H:%M" msgstr "" #. Translators: this is the day number followed #. * by the abbreviated month name followed by the year followed #. * by a time in 12h format i.e. "3 Feb 2015 9:04 PM" #: libnemo-private/nemo-file.c:5025 #, no-c-format msgid "%-e %b %Y %l:%M %p" msgstr "" #: libnemo-private/nemo-file.c:5035 #, no-c-format msgid "%c" msgstr "" #: libnemo-private/nemo-file.c:5483 msgid "Not allowed to set permissions" msgstr "" #: libnemo-private/nemo-file.c:5778 msgid "Not allowed to set owner" msgstr "" #: libnemo-private/nemo-file.c:5796 #, c-format msgid "Specified owner '%s' doesn't exist" msgstr "" #: libnemo-private/nemo-file.c:6060 msgid "Not allowed to set group" msgstr "" #: libnemo-private/nemo-file.c:6078 #, c-format msgid "Specified group '%s' doesn't exist" msgstr "" #: libnemo-private/nemo-file.c:6236 #, c-format msgid "%'u folder" msgid_plural "%'u folders" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file.c:6237 #, c-format msgid "%'u file" msgid_plural "%'u files" msgstr[0] "" msgstr[1] "" #. This means no contents at all were readable #: libnemo-private/nemo-file.c:6682 libnemo-private/nemo-file.c:6698 msgid "? items" msgstr "" #. This means no contents at all were readable #: libnemo-private/nemo-file.c:6688 msgid "? bytes" msgstr "" #: libnemo-private/nemo-file.c:6705 libnemo-private/nemo-file.c:6794 msgid "Unknown" msgstr "" #: libnemo-private/nemo-file.c:6758 libnemo-private/nemo-file.c:6766 #: libnemo-private/nemo-file.c:6818 msgid "Program" msgstr "" #: libnemo-private/nemo-file.c:6759 msgid "Audio" msgstr "" #: libnemo-private/nemo-file.c:6760 msgid "Font" msgstr "" #: libnemo-private/nemo-file.c:6762 msgid "Archive" msgstr "" #: libnemo-private/nemo-file.c:6763 msgid "Markup" msgstr "" #: libnemo-private/nemo-file.c:6764 libnemo-private/nemo-file.c:6765 #: eel/eel-editable-label.c:317 msgid "Text" msgstr "" #: libnemo-private/nemo-file.c:6767 msgid "Video" msgstr "" #: libnemo-private/nemo-file.c:6768 msgid "Contacts" msgstr "" #: libnemo-private/nemo-file.c:6769 msgid "Calendar" msgstr "" #: libnemo-private/nemo-file.c:6770 msgid "Document" msgstr "" #: libnemo-private/nemo-file.c:6771 msgid "Presentation" msgstr "" #: libnemo-private/nemo-file.c:6772 msgid "Spreadsheet" msgstr "" #: libnemo-private/nemo-file.c:6820 #: gresources/nemo-file-management-properties.glade:150 msgid "Binary" msgstr "" #: libnemo-private/nemo-file.c:6824 msgid "Folder" msgstr "" #: libnemo-private/nemo-file.c:6855 msgid "link" msgstr "" #: libnemo-private/nemo-file.c:6877 libnemo-private/nemo-file.c:6891 msgid "link (broken)" msgstr "" #: libnemo-private/nemo-file.c:7802 #, c-format msgid "Name: %s" msgstr "" #: libnemo-private/nemo-file.c:7809 #, c-format msgid "Type: %s" msgstr "" #: libnemo-private/nemo-file.c:7819 #, c-format msgid "%s item" msgid_plural "%s items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file.c:7821 #, c-format msgid "Contains: %s" msgstr "" #: libnemo-private/nemo-file.c:7831 #, c-format msgid "Size: %s" msgstr "" #: libnemo-private/nemo-file.c:7839 #, c-format msgid "Accessed: %s" msgstr "" #: libnemo-private/nemo-file.c:7847 #, c-format msgid "Modified: %s" msgstr "" #: libnemo-private/nemo-file.c:7855 #, c-format msgid "Created: %s" msgstr "" #: libnemo-private/nemo-file.c:7864 #, c-format msgid "Location: %s" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:142 #, c-format msgid "Merge folder \"%s\"?" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:146 msgid "" "Merging will ask for confirmation before replacing any files in the folder " "that conflict with the files being copied." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:151 #, c-format msgid "An older folder with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:155 #, c-format msgid "A newer folder with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:159 #, c-format msgid "Another folder with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:164 msgid "Replacing it will remove all files in the folder." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:166 #, c-format msgid "Replace folder \"%s\"?" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:168 #, c-format msgid "A folder with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:173 #, c-format msgid "Replace file \"%s\"?" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:175 msgid "Replacing it will overwrite its content." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:179 #, c-format msgid "An older file with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:183 #, c-format msgid "A newer file with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:187 #, c-format msgid "Another file with the same name already exists in \"%s\"." msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:255 msgid "Original file" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:262 #: libnemo-private/nemo-file-conflict-dialog.c:294 msgid "Last modified:" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:287 msgid "Replace with" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:316 msgid "Merge" msgstr "" #. Setup the expander for the rename action #: libnemo-private/nemo-file-conflict-dialog.c:509 msgid "_Select a new name for the destination" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:523 msgid "Reset" msgstr "" #. Setup the checkbox to apply the action to all files #: libnemo-private/nemo-file-conflict-dialog.c:535 msgid "Apply this action to all files" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:546 #: libnemo-private/nemo-file-operations.c:195 msgid "_Skip" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:551 msgid "Re_name" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:557 msgid "Replace" msgstr "" #: libnemo-private/nemo-file-conflict-dialog.c:629 msgid "File conflict" msgstr "" #: libnemo-private/nemo-file-operations.c:196 msgid "S_kip All" msgstr "" #: libnemo-private/nemo-file-operations.c:197 msgid "_Retry" msgstr "" #: libnemo-private/nemo-file-operations.c:198 msgid "Delete _All" msgstr "" #: libnemo-private/nemo-file-operations.c:199 msgid "_Replace" msgstr "" #: libnemo-private/nemo-file-operations.c:200 msgid "Replace _All" msgstr "" #: libnemo-private/nemo-file-operations.c:201 msgid "_Merge" msgstr "" #: libnemo-private/nemo-file-operations.c:202 msgid "Merge _All" msgstr "" #: libnemo-private/nemo-file-operations.c:203 msgid "Copy _Anyway" msgstr "" #: libnemo-private/nemo-file-operations.c:294 #, c-format msgid "%'d second" msgid_plural "%'d seconds" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:299 #: libnemo-private/nemo-file-operations.c:310 #, c-format msgid "%'d minute" msgid_plural "%'d minutes" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:309 #, c-format msgid "%'d hour" msgid_plural "%'d hours" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:317 #, c-format msgid "approximately %'d hour" msgid_plural "approximately %'d hours" msgstr[0] "" msgstr[1] "" #. appended to new link file #: libnemo-private/nemo-file-operations.c:397 #, c-format msgid "Another link to %s" msgstr "" #. Localizers: Feel free to leave out the "st" suffix #. * if there's no way to do that nicely for a #. * particular language. #. #: libnemo-private/nemo-file-operations.c:413 #, c-format msgid "%'dst link to %s" msgstr "" #. appended to new link file #: libnemo-private/nemo-file-operations.c:417 #, c-format msgid "%'dnd link to %s" msgstr "" #. appended to new link file #: libnemo-private/nemo-file-operations.c:421 #, c-format msgid "%'drd link to %s" msgstr "" #. appended to new link file #: libnemo-private/nemo-file-operations.c:425 #, c-format msgid "%'dth link to %s" msgstr "" #. Localizers: #. * Feel free to leave out the st, nd, rd and th suffix or #. * make some or all of them match. #. #. localizers: tag used to detect the first copy of a file #: libnemo-private/nemo-file-operations.c:464 msgid " (copy)" msgstr "" #. localizers: tag used to detect the second copy of a file #: libnemo-private/nemo-file-operations.c:466 msgid " (another copy)" msgstr "" #. localizers: tag used to detect the x11th copy of a file #. localizers: tag used to detect the x12th copy of a file #. localizers: tag used to detect the x13th copy of a file #. localizers: tag used to detect the xxth copy of a file #: libnemo-private/nemo-file-operations.c:469 #: libnemo-private/nemo-file-operations.c:471 #: libnemo-private/nemo-file-operations.c:473 #: libnemo-private/nemo-file-operations.c:483 msgid "th copy)" msgstr "" #. localizers: tag used to detect the x1st copy of a file #: libnemo-private/nemo-file-operations.c:476 msgid "st copy)" msgstr "" #. localizers: tag used to detect the x2nd copy of a file #: libnemo-private/nemo-file-operations.c:478 msgid "nd copy)" msgstr "" #. localizers: tag used to detect the x3rd copy of a file #: libnemo-private/nemo-file-operations.c:480 msgid "rd copy)" msgstr "" #. localizers: appended to first file copy #: libnemo-private/nemo-file-operations.c:497 #, c-format msgid "%s (copy)%s" msgstr "" #. localizers: appended to second file copy #: libnemo-private/nemo-file-operations.c:499 #, c-format msgid "%s (another copy)%s" msgstr "" #. localizers: appended to x11th file copy #. localizers: appended to x12th file copy #. localizers: appended to x13th file copy #. localizers: appended to xxth file copy #: libnemo-private/nemo-file-operations.c:502 #: libnemo-private/nemo-file-operations.c:504 #: libnemo-private/nemo-file-operations.c:506 #: libnemo-private/nemo-file-operations.c:520 #, c-format msgid "%s (%'dth copy)%s" msgstr "" #. localizers: if in your language there's no difference between 1st, 2nd, 3rd and nth #. * plurals, you can leave the st, nd, rd suffixes out and just make all the translated #. * strings look like "%s (copy %'d)%s". #. #. localizers: appended to x1st file copy #: libnemo-private/nemo-file-operations.c:514 #, c-format msgid "%s (%'dst copy)%s" msgstr "" #. localizers: appended to x2nd file copy #: libnemo-private/nemo-file-operations.c:516 #, c-format msgid "%s (%'dnd copy)%s" msgstr "" #. localizers: appended to x3rd file copy #: libnemo-private/nemo-file-operations.c:518 #, c-format msgid "%s (%'drd copy)%s" msgstr "" #. localizers: opening parentheses to match the "th copy)" string #: libnemo-private/nemo-file-operations.c:619 msgid " (" msgstr "" #. localizers: opening parentheses of the "th copy)" string #: libnemo-private/nemo-file-operations.c:627 #, c-format msgid " (%'d" msgstr "" #: libnemo-private/nemo-file-operations.c:997 #, c-format msgid "Error removing file: %s" msgstr "" #: libnemo-private/nemo-file-operations.c:1047 #, c-format msgid "Waiting to copy a file from '%1$s' to '%2$s'" msgid_plural "Waiting to copy files from '%1$s' to '%2$s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1056 #, c-format msgid "Waiting to move a file from '%1$s' to '%2$s'" msgid_plural "Waiting to move files from '%1$s' to '%2$s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1064 #, c-format msgid "Waiting to permanently delete a file from '%s'" msgid_plural "Waiting to permanently delete files from '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1072 #, c-format msgid "Waiting to trash a file in '%s'" msgid_plural "Waiting to trash files in '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1078 msgid "Waiting to empty the trash" msgstr "" #: libnemo-private/nemo-file-operations.c:1084 #, c-format msgid "Waiting to duplicate a file in '%s'" msgid_plural "Waiting to duplicate files in '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1092 #, c-format msgid "Waiting to change permissions of files in '%s'" msgstr "" #: libnemo-private/nemo-file-operations.c:1098 #, c-format msgid "Waiting to link a file from '%1$s' to '%2$s'" msgid_plural "Waiting to link files from '%1$s' to '%2$s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1522 msgid "Are you sure you want to move \"%B\" to the trash?" msgstr "" #. translators: the singular form here can be skipped. #: libnemo-private/nemo-file-operations.c:1526 #, c-format msgid "unused %'d" msgid_plural "" "Are you sure you want to move the %'d selected items to the trash?" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1535 msgid "You can restore an item from the trash, if you later change your mind." msgstr "" #: libnemo-private/nemo-file-operations.c:1538 msgid "Move to _Trash" msgstr "" #: libnemo-private/nemo-file-operations.c:1571 msgid "Are you sure you want to permanently delete \"%B\" from the trash?" msgstr "" #: libnemo-private/nemo-file-operations.c:1574 #, c-format msgid "" "Are you sure you want to permanently delete the %'d selected item from the " "trash?" msgid_plural "" "Are you sure you want to permanently delete the %'d selected items from the " "trash?" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1584 #: libnemo-private/nemo-file-operations.c:1650 msgid "If you delete an item, it will be permanently lost." msgstr "" #: libnemo-private/nemo-file-operations.c:1604 msgid "Empty all items from Trash?" msgstr "" #: libnemo-private/nemo-file-operations.c:1608 msgid "All items in the Trash will be permanently deleted." msgstr "" #: libnemo-private/nemo-file-operations.c:1638 msgid "Are you sure you want to permanently delete \"%B\"?" msgstr "" #: libnemo-private/nemo-file-operations.c:1641 #, c-format msgid "Are you sure you want to permanently delete the %'d selected item?" msgid_plural "" "Are you sure you want to permanently delete the %'d selected items?" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1684 #, c-format msgid "%'d file left to delete" msgid_plural "%'d files left to delete" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1690 msgid "Deleting files" msgstr "" #. To translators: %T will expand to a time like "2 minutes". #. * The singular/plural form will be used depending on the remaining time (i.e. the %T argument). #. #: libnemo-private/nemo-file-operations.c:1704 msgid "%T left" msgid_plural "%T left" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:1771 #: libnemo-private/nemo-file-operations.c:1805 #: libnemo-private/nemo-file-operations.c:1844 #: libnemo-private/nemo-file-operations.c:1921 #: libnemo-private/nemo-file-operations.c:2764 msgid "Error while deleting." msgstr "" #: libnemo-private/nemo-file-operations.c:1775 msgid "" "Files in the folder \"%B\" cannot be deleted because you do not have " "permissions to see them." msgstr "" #: libnemo-private/nemo-file-operations.c:1778 #: libnemo-private/nemo-file-operations.c:2824 #: libnemo-private/nemo-file-operations.c:3825 msgid "" "There was an error getting information about the files in the folder \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:1787 #: libnemo-private/nemo-file-operations.c:3834 msgid "_Skip files" msgstr "" #: libnemo-private/nemo-file-operations.c:1808 msgid "" "The folder \"%B\" cannot be deleted because you do not have permissions to " "read it." msgstr "" #: libnemo-private/nemo-file-operations.c:1811 #: libnemo-private/nemo-file-operations.c:2863 #: libnemo-private/nemo-file-operations.c:3870 msgid "There was an error reading the folder \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:1845 msgid "Could not remove the folder %B." msgstr "" #: libnemo-private/nemo-file-operations.c:1922 msgid "There was an error deleting %B." msgstr "" #: libnemo-private/nemo-file-operations.c:2002 msgid "Moving files to trash" msgstr "" #: libnemo-private/nemo-file-operations.c:2004 #, c-format msgid "%'d file left to trash" msgid_plural "%'d files left to trash" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:2055 msgid "Cannot move file to trash, do you want to delete immediately?" msgstr "" #: libnemo-private/nemo-file-operations.c:2056 msgid "The file \"%B\" cannot be moved to the trash." msgstr "" #: libnemo-private/nemo-file-operations.c:2241 msgid "Trashing Files" msgstr "" #: libnemo-private/nemo-file-operations.c:2243 msgid "Deleting Files" msgstr "" #: libnemo-private/nemo-file-operations.c:2326 msgid "Unable to eject %V" msgstr "" #: libnemo-private/nemo-file-operations.c:2328 msgid "Unable to unmount %V" msgstr "" #: libnemo-private/nemo-file-operations.c:2485 msgid "Do you want to empty the trash before you unmount?" msgstr "" #: libnemo-private/nemo-file-operations.c:2487 msgid "" "In order to regain the free space on this volume the trash must be emptied. " "All trashed items on the volume will be permanently lost." msgstr "" #: libnemo-private/nemo-file-operations.c:2493 msgid "Do _not Empty Trash" msgstr "" #: libnemo-private/nemo-file-operations.c:2623 #, c-format msgid "Unable to mount %s" msgstr "" #: libnemo-private/nemo-file-operations.c:2705 #, c-format msgid "Preparing to copy %'d file (%S)" msgid_plural "Preparing to copy %'d files (%S)" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:2711 #, c-format msgid "Preparing to move %'d file (%S)" msgid_plural "Preparing to move %'d files (%S)" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:2717 #, c-format msgid "Preparing to delete %'d file (%S)" msgid_plural "Preparing to delete %'d files (%S)" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:2724 #, c-format msgid "Preparing to trash %'d file" msgid_plural "Preparing to trash %'d files" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:2760 #: libnemo-private/nemo-file-operations.c:3685 #: libnemo-private/nemo-file-operations.c:3817 #: libnemo-private/nemo-file-operations.c:3862 msgid "Error while copying." msgstr "" #: libnemo-private/nemo-file-operations.c:2762 #: libnemo-private/nemo-file-operations.c:3815 #: libnemo-private/nemo-file-operations.c:3860 msgid "Error while moving." msgstr "" #: libnemo-private/nemo-file-operations.c:2767 msgid "Error while moving files to trash." msgstr "" #: libnemo-private/nemo-file-operations.c:2821 msgid "" "Files in the folder \"%B\" cannot be handled because you do not have " "permissions to see them." msgstr "" #: libnemo-private/nemo-file-operations.c:2860 msgid "" "The folder \"%B\" cannot be handled because you do not have permissions to " "read it." msgstr "" #: libnemo-private/nemo-file-operations.c:2940 msgid "" "The file \"%B\" cannot be handled because you do not have permissions to " "read it." msgstr "" #: libnemo-private/nemo-file-operations.c:2943 msgid "There was an error getting information about \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:3044 #: libnemo-private/nemo-file-operations.c:3086 #: libnemo-private/nemo-file-operations.c:3120 #: libnemo-private/nemo-file-operations.c:3150 msgid "Error while copying to \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:3048 msgid "You do not have permissions to access the destination folder." msgstr "" #: libnemo-private/nemo-file-operations.c:3050 msgid "There was an error getting information about the destination." msgstr "" #: libnemo-private/nemo-file-operations.c:3087 msgid "The destination is not a folder." msgstr "" #: libnemo-private/nemo-file-operations.c:3121 msgid "" "There is not enough space on the destination. Try to remove files to make " "space." msgstr "" #: libnemo-private/nemo-file-operations.c:3123 #, c-format msgid "%S more space is required to copy to the destination." msgstr "" #: libnemo-private/nemo-file-operations.c:3151 msgid "The destination is read-only." msgstr "" #: libnemo-private/nemo-file-operations.c:3210 msgid "Moving \"%B\" to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3211 msgid "Copying \"%B\" to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3218 msgid "Duplicating \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3226 msgid "Moving file %'d of %'d (in \"%B\") to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3228 msgid "Copying file %'d of %'d (in \"%B\") to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3235 msgid "Duplicating file %'d of %'d (in \"%B\")" msgstr "" #: libnemo-private/nemo-file-operations.c:3244 msgid "Moving file %'d of %'d to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3246 msgid "Copying file %'d of %'d to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:3252 #, c-format msgid "Duplicating file %'d of %'d" msgstr "" #. To translators: %S will expand to a size like "2 bytes" or "3 MB", so something like "4 kb of 4 MB" #: libnemo-private/nemo-file-operations.c:3271 #, c-format msgid "%S of %S" msgstr "" #. To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration like #. * "2 minutes". So the whole thing will be something like "2 kb of 4 MB -- 2 hours left (4kb/sec)" #. * #. * The singular/plural form will be used depending on the remaining time (i.e. the %T argument). #. #: libnemo-private/nemo-file-operations.c:3282 msgid "%S of %S — %T left (%S/sec)" msgid_plural "%S of %S — %T left (%S/sec)" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:3689 msgid "" "The folder \"%B\" cannot be copied because you do not have permissions to " "create it in the destination." msgstr "" #: libnemo-private/nemo-file-operations.c:3692 msgid "There was an error creating the folder \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:3822 msgid "" "Files in the folder \"%B\" cannot be copied because you do not have " "permissions to see them." msgstr "" #: libnemo-private/nemo-file-operations.c:3867 msgid "" "The folder \"%B\" cannot be copied because you do not have permissions to " "read it." msgstr "" #: libnemo-private/nemo-file-operations.c:3912 #: libnemo-private/nemo-file-operations.c:4621 #: libnemo-private/nemo-file-operations.c:5245 msgid "Error while moving \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:3913 msgid "Could not remove the source folder." msgstr "" #: libnemo-private/nemo-file-operations.c:3998 #: libnemo-private/nemo-file-operations.c:4039 #: libnemo-private/nemo-file-operations.c:4623 #: libnemo-private/nemo-file-operations.c:4694 msgid "Error while copying \"%B\"." msgstr "" #: libnemo-private/nemo-file-operations.c:3999 #, c-format msgid "Could not remove files from the already existing folder %F." msgstr "" #: libnemo-private/nemo-file-operations.c:4040 #, c-format msgid "Could not remove the already existing file %F." msgstr "" #. the run_warning() frees all strings passed in automatically #: libnemo-private/nemo-file-operations.c:4375 #: libnemo-private/nemo-file-operations.c:5090 msgid "You cannot move a folder into itself." msgstr "" #: libnemo-private/nemo-file-operations.c:4376 #: libnemo-private/nemo-file-operations.c:5091 msgid "You cannot copy a folder into itself." msgstr "" #: libnemo-private/nemo-file-operations.c:4377 #: libnemo-private/nemo-file-operations.c:5092 msgid "The destination folder is inside the source folder." msgstr "" #. the run_warning() frees all strings passed in automatically #: libnemo-private/nemo-file-operations.c:4408 msgid "You cannot move a file over itself." msgstr "" #: libnemo-private/nemo-file-operations.c:4409 msgid "You cannot copy a file over itself." msgstr "" #: libnemo-private/nemo-file-operations.c:4410 msgid "The source file would be overwritten by the destination." msgstr "" #: libnemo-private/nemo-file-operations.c:4625 #, c-format msgid "Could not remove the already existing file with the same name in %F." msgstr "" #: libnemo-private/nemo-file-operations.c:4695 #, c-format msgid "There was an error copying the file into %F." msgstr "" #: libnemo-private/nemo-file-operations.c:4927 #: libnemo-private/nemo-file-operations.c:4959 msgid "Copying Files" msgstr "" #: libnemo-private/nemo-file-operations.c:4985 msgid "Preparing to Move to \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:4989 #, c-format msgid "Preparing to move %'d file" msgid_plural "Preparing to move %'d files" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:5246 #, c-format msgid "There was an error moving the file into %F." msgstr "" #: libnemo-private/nemo-file-operations.c:5509 msgid "Moving Files" msgstr "" #: libnemo-private/nemo-file-operations.c:5542 msgid "Creating links in \"%B\"" msgstr "" #: libnemo-private/nemo-file-operations.c:5546 #, c-format msgid "Making link to %'d file" msgid_plural "Making links to %'d files" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-operations.c:5684 msgid "Error while creating link to %B." msgstr "" #: libnemo-private/nemo-file-operations.c:5686 msgid "Symbolic links only supported for local files" msgstr "" #: libnemo-private/nemo-file-operations.c:5689 msgid "The target doesn't support symbolic links." msgstr "" #: libnemo-private/nemo-file-operations.c:5692 #, c-format msgid "There was an error creating the symlink in %F." msgstr "" #: libnemo-private/nemo-file-operations.c:6010 msgid "Setting permissions" msgstr "" #. localizers: the initial name of a new folder #: libnemo-private/nemo-file-operations.c:6273 msgid "Untitled Folder" msgstr "" #. localizers: the initial name of a new empty document #: libnemo-private/nemo-file-operations.c:6285 msgid "Untitled Document" msgstr "" #: libnemo-private/nemo-file-operations.c:6461 msgid "Error while creating directory %B." msgstr "" #: libnemo-private/nemo-file-operations.c:6463 msgid "Error while creating file %B." msgstr "" #: libnemo-private/nemo-file-operations.c:6465 #, c-format msgid "There was an error creating the directory in %F." msgstr "" #: libnemo-private/nemo-file-operations.c:6695 #: libnemo-private/nemo-file-operations.c:6696 #: libnemo-private/nemo-file-operations.c:6729 msgid "Emptying Trash" msgstr "" #: libnemo-private/nemo-file-operations.c:6775 #: libnemo-private/nemo-file-operations.c:6816 #: libnemo-private/nemo-file-operations.c:6851 #: libnemo-private/nemo-file-operations.c:6886 msgid "Unable to mark launcher trusted (executable)" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:378 #, c-format msgid "Move %d item back to '%s'" msgid_plural "Move %d items back to '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:381 #, c-format msgid "Move %d item to '%s'" msgid_plural "Move %d items to '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:385 #, c-format msgid "_Undo Move %d item" msgid_plural "_Undo Move %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:388 #, c-format msgid "_Redo Move %d item" msgid_plural "_Redo Move %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:392 #, c-format msgid "Move '%s' back to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:393 #, c-format msgid "Move '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:395 msgid "_Undo Move" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:396 msgid "_Redo Move" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:399 msgid "_Undo Restore from Trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:400 msgid "_Redo Restore from Trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:403 #, c-format msgid "Move %d item back to trash" msgid_plural "Move %d items back to trash" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:406 #: libnemo-private/nemo-file-undo-operations.c:999 #, c-format msgid "Restore %d item from trash" msgid_plural "Restore %d items from trash" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:410 #, c-format msgid "Move '%s' back to trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:411 #, c-format msgid "Restore '%s' from trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:415 #, c-format msgid "Delete %d copied item" msgid_plural "Delete %d copied items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:418 #, c-format msgid "Copy %d item to '%s'" msgid_plural "Copy %d items to '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:422 #, c-format msgid "_Undo Copy %d item" msgid_plural "_Undo Copy %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:425 #, c-format msgid "_Redo Copy %d item" msgid_plural "_Redo Copy %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:429 #: libnemo-private/nemo-file-undo-operations.c:451 #: libnemo-private/nemo-file-undo-operations.c:684 #, c-format msgid "Delete '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:430 #, c-format msgid "Copy '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:432 msgid "_Undo Copy" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:433 msgid "_Redo Copy" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:437 #, c-format msgid "Delete %d duplicated item" msgid_plural "Delete %d duplicated items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:440 #, c-format msgid "Duplicate %d item in '%s'" msgid_plural "Duplicate %d items in '%s'" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:444 #, c-format msgid "_Undo Duplicate %d item" msgid_plural "_Undo Duplicate %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:447 #, c-format msgid "_Redo Duplicate %d item" msgid_plural "_Redo Duplicate %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:452 #, c-format msgid "Duplicate '%s' in '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:455 msgid "_Undo Duplicate" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:456 msgid "_Redo Duplicate" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:460 #, c-format msgid "Delete links to %d item" msgid_plural "Delete links to %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:463 #, c-format msgid "Create links to %d item" msgid_plural "Create links to %d items" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:467 #, c-format msgid "Delete link to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:468 #, c-format msgid "Create link to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:470 msgid "_Undo Create Link" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:471 msgid "_Redo Create Link" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:687 #, c-format msgid "Create an empty file '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:689 msgid "_Undo Create Empty File" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:690 msgid "_Redo Create Empty File" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:692 #, c-format msgid "Create a new folder '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:694 msgid "_Undo Create Folder" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:695 msgid "_Redo Create Folder" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:697 #, c-format msgid "Create new file '%s' from template " msgstr "" #: libnemo-private/nemo-file-undo-operations.c:699 msgid "_Undo Create from Template" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:700 msgid "_Redo Create from Template" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:882 #: libnemo-private/nemo-file-undo-operations.c:883 #, c-format msgid "Rename '%s' as '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:885 msgid "_Undo Rename" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:886 msgid "_Redo Rename" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1002 #, c-format msgid "Move %d item to trash" msgid_plural "Move %d items to trash" msgstr[0] "" msgstr[1] "" #: libnemo-private/nemo-file-undo-operations.c:1014 #, c-format msgid "Restore '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1021 #, c-format msgid "Move '%s' to trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1025 msgid "_Undo Trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1026 msgid "_Redo Trash" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1318 #, c-format msgid "Restore original permissions of items enclosed in '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1319 #, c-format msgid "Set permissions of items enclosed in '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1321 #: libnemo-private/nemo-file-undo-operations.c:1476 msgid "_Undo Change Permissions" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1322 #: libnemo-private/nemo-file-undo-operations.c:1477 msgid "_Redo Change Permissions" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1473 #, c-format msgid "Restore original permissions of '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1474 #, c-format msgid "Set permissions of '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1584 #, c-format msgid "Restore group of '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1586 #, c-format msgid "Set group of '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1589 msgid "_Undo Change Group" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1590 msgid "_Redo Change Group" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1592 #, c-format msgid "Restore owner of '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1594 #, c-format msgid "Set owner of '%s' to '%s'" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1597 msgid "_Undo Change Owner" msgstr "" #: libnemo-private/nemo-file-undo-operations.c:1598 msgid "_Redo Change Owner" msgstr "" #: libnemo-private/nemo-file-utilities.c:1380 #, c-format msgid "Could not determine original location of \"%s\" " msgstr "" #: libnemo-private/nemo-file-utilities.c:1384 msgid "The item cannot be restored from trash" msgstr "" #: libnemo-private/nemo-icon-container.c:1408 msgid "The selection rectangle" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:113 msgid "Could not forget association" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:137 msgid "Forget association" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:277 msgid "Valid executable." msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:284 msgid "" "Not a valid executable. Spaces in the file path must be escaped with " "backslash (\\)." msgstr "" #. the %s here is a file extension #: libnemo-private/nemo-mime-application-chooser.c:419 #: libnemo-private/nemo-mime-application-chooser.c:437 #, c-format msgid "%s document" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:424 #, c-format msgid "Open all files of type \"%s\" with" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:444 #, c-format msgid "" "Select an application in the list to open %s and other files of type \"%s\"" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:478 msgid "Custom application" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:481 msgid "_Cancel" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:498 msgid "Executables" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:544 msgid "" "You can also type or select a custom executable file to use to open this " "file type. You can use this command just once, or set it as default for all " "files of this type." msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:558 msgid "Enter a custom command..." msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:584 msgid "Add to list" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:592 msgid "Set as default" msgstr "" #: libnemo-private/nemo-mime-application-chooser.c:601 msgid "Reset to system defaults" msgstr "" #: libnemo-private/nemo-program-choosing.c:324 msgid "Sorry, but you cannot execute commands from a remote site." msgstr "" #: libnemo-private/nemo-program-choosing.c:326 msgid "This is disabled due to security considerations." msgstr "" #: libnemo-private/nemo-program-choosing.c:337 #: libnemo-private/nemo-program-choosing.c:398 msgid "There was an error launching the application." msgstr "" #: libnemo-private/nemo-program-choosing.c:362 #: libnemo-private/nemo-program-choosing.c:373 msgid "This drop target only supports local files." msgstr "" #: libnemo-private/nemo-program-choosing.c:363 msgid "" "To open non-local files copy them to a local folder and then drop them again." msgstr "" #: libnemo-private/nemo-program-choosing.c:374 msgid "" "To open non-local files copy them to a local folder and then drop them " "again. The local files you dropped have already been opened." msgstr "" #: libnemo-private/nemo-program-choosing.c:396 msgid "Details: " msgstr "" #: libnemo-private/nemo-progress-info.c:205 #: libnemo-private/nemo-progress-info.c:223 #: libnemo-private/nemo-progress-info.c:241 msgid "Preparing" msgstr "" #: libnemo-private/nemo-query.c:170 #, c-format msgid "Search for \"%s\" in \"%s\"" msgstr "" #: libnemo-private/nemo-undo-signal-handlers.c:173 msgid "Edit" msgstr "" #: libnemo-private/nemo-undo-signal-handlers.c:174 msgid "Undo Edit" msgstr "" #: libnemo-private/nemo-undo-signal-handlers.c:175 msgid "Undo the edit" msgstr "" #: libnemo-private/nemo-undo-signal-handlers.c:176 msgid "Redo Edit" msgstr "" #: libnemo-private/nemo-undo-signal-handlers.c:177 msgid "Redo the edit" msgstr "" #: eel/eel-canvas.c:1255 eel/eel-canvas.c:1256 msgid "X" msgstr "" #: eel/eel-canvas.c:1262 eel/eel-canvas.c:1263 msgid "Y" msgstr "" #: eel/eel-editable-label.c:318 msgid "The text of the label." msgstr "" #: eel/eel-editable-label.c:324 msgid "Justification" msgstr "" #: eel/eel-editable-label.c:325 msgid "" "The alignment of the lines in the text of the label relative to each other. " "This does NOT affect the alignment of the label within its allocation. See " "GtkMisc::xalign for that." msgstr "" #: eel/eel-editable-label.c:333 msgid "Line wrap" msgstr "" #: eel/eel-editable-label.c:334 msgid "If set, wrap lines if the text becomes too wide." msgstr "" #: eel/eel-editable-label.c:341 msgid "Cursor Position" msgstr "" #: eel/eel-editable-label.c:342 msgid "The current position of the insertion cursor in chars." msgstr "" #: eel/eel-editable-label.c:351 msgid "Selection Bound" msgstr "" #: eel/eel-editable-label.c:352 msgid "" "The position of the opposite end of the selection from the cursor in chars." msgstr "" #: eel/eel-editable-label.c:3101 msgid "Select All" msgstr "" #: eel/eel-editable-label.c:3112 msgid "Input Methods" msgstr "" #: eel/eel-gtk-extensions.c:329 msgid "Show more _details" msgstr "" #: eel/eel-stock-dialogs.c:205 msgid "You can stop this operation by clicking cancel." msgstr "" #: eel/eel-vfs-extensions.c:105 msgid " (invalid Unicode)" msgstr "" #: data/nemo-actions/action_i18n_strings.py:8 msgid "Manage workspaces (Expo)" msgstr "" #: data/nemo-actions/action_i18n_strings.py:9 msgid "Open Expo to add, remove, or organize workspaces" msgstr "" #: data/nemo-actions/action_i18n_strings.py:10 msgid "Remove workspace" msgstr "" #: data/nemo-actions/action_i18n_strings.py:11 msgid "Remove the currently active workspace" msgstr "" #: data/nemo-actions/action_i18n_strings.py:12 msgid "Mount archive" msgstr "" #: data/nemo-actions/action_i18n_strings.py:13 #, python-format msgid "Mount %f to browse its contents" msgstr "" #: data/nemo-actions/action_i18n_strings.py:14 msgid "Add Desklets" msgstr "" #: data/nemo-actions/action_i18n_strings.py:15 msgid "Add Cinamon desklets" msgstr "" #: data/nemo-actions/action_i18n_strings.py:16 msgid "Change Desktop _Background" msgstr "" #: data/nemo-actions/action_i18n_strings.py:17 msgid "Change the Cinnamon desktop background" msgstr "" #: data/nemo-actions/action_i18n_strings.py:18 msgid "Set as Wallpaper..." msgstr "" #: data/nemo-actions/action_i18n_strings.py:19 msgid "Set the selected image as your Cinnamon desktop wallpaper" msgstr "" #: data/nemo-actions/action_i18n_strings.py:20 msgid "Create a new l_auncher here..." msgstr "" #: data/nemo-actions/action_i18n_strings.py:21 msgid "Create a new launcher in this folder" msgstr "" #: data/nemo-actions/action_i18n_strings.py:22 msgid "Jump to new workspace" msgstr "" #: data/nemo-actions/action_i18n_strings.py:23 msgid "Create a new workspace and activate it" msgstr "" #: generate_additional_file:33 msgid "Files" msgstr "" #: generate_additional_file:33 msgid "Access and organize files" msgstr "" #: gresources/nemo-bookmarks-window.glade:8 msgid "Edit Bookmarks" msgstr "" #: gresources/nemo-bookmarks-window.glade:116 msgid "_Bookmarks" msgstr "" #: gresources/nemo-bookmarks-window.glade:205 msgid "_Name" msgstr "" #: gresources/nemo-bookmarks-window.glade:272 msgid "_Location" msgstr "" #: gresources/nemo-desktop-overlay.glade:61 msgctxt "Desktop icon size" msgid "Smaller" msgstr "" #: gresources/nemo-desktop-overlay.glade:66 msgctxt "Desktop icon size" msgid "Small" msgstr "" #: gresources/nemo-desktop-overlay.glade:76 msgctxt "Desktop icon size" msgid "Large" msgstr "" #: gresources/nemo-desktop-overlay.glade:81 msgctxt "Desktop icon size" msgid "Larger" msgstr "" #: gresources/nemo-desktop-overlay.glade:95 msgid "Vertical" msgstr "" #: gresources/nemo-desktop-overlay.glade:99 msgid "Horizontal" msgstr "" #: gresources/nemo-desktop-overlay.glade:138 msgid "Current Monitor Layout" msgstr "" #: gresources/nemo-desktop-overlay.glade:197 msgid "Icon Size" msgstr "" #: gresources/nemo-desktop-overlay.glade:240 msgid "Layout" msgstr "" #: gresources/nemo-desktop-overlay.glade:369 msgid "Direction" msgstr "" #: gresources/nemo-desktop-overlay.glade:454 msgid "Sort items by" msgstr "" #: gresources/nemo-desktop-overlay.glade:613 msgid "Reset grid spacing" msgstr "" #: gresources/nemo-desktop-overlay.glade:680 #: gresources/nemo-desktop-overlay.glade:870 msgid "button" msgstr "" #: gresources/nemo-desktop-overlay.glade:746 msgid "Adjust horizontal grid spacing" msgstr "" #: gresources/nemo-desktop-overlay.glade:801 msgid "Adjust vertical grid spacing" msgstr "" #: gresources/nemo-desktop-overlay.glade:845 msgid "page0" msgstr "" #: gresources/nemo-desktop-overlay.glade:859 msgid "" "Desktop icons are not currently enabled for this monitor." msgstr "" #: gresources/nemo-desktop-overlay.glade:887 msgid "page1" msgstr "" #: gresources/nemo-desktop-preferences.glade:36 msgid "Desktop Layout" msgstr "" #: gresources/nemo-desktop-preferences.glade:54 msgid "No desktop icons" msgstr "" #: gresources/nemo-desktop-preferences.glade:55 msgid "Show desktop icons on primary monitor only" msgstr "" #: gresources/nemo-desktop-preferences.glade:56 msgid "Show desktop icons on non-primary monitor(s) only" msgstr "" #: gresources/nemo-desktop-preferences.glade:57 msgid "Show desktop icons on all monitors" msgstr "" #: gresources/nemo-desktop-preferences.glade:77 msgid "Desktop Icons" msgstr "" #: gresources/nemo-desktop-preferences.glade:367 msgid "Mounted Drives" msgstr "" #: gresources/nemo-desktop-preferences.glade:503 msgid "Options" msgstr "" #: gresources/nemo-desktop-preferences.glade:559 msgid "Show icons from missing monitors" msgstr "" #: gresources/nemo-file-management-properties.glade:127 #: gresources/nemo-file-management-properties.glade:327 #: gresources/nemo-file-management-properties.glade:4126 msgid "Always" msgstr "" #: gresources/nemo-file-management-properties.glade:130 #: gresources/nemo-file-management-properties.glade:330 #: gresources/nemo-file-management-properties.glade:347 #: gresources/nemo-file-management-properties.glade:4129 msgid "Local Files Only" msgstr "" #: gresources/nemo-file-management-properties.glade:133 #: gresources/nemo-file-management-properties.glade:333 #: gresources/nemo-file-management-properties.glade:4132 msgid "Never" msgstr "" #: gresources/nemo-file-management-properties.glade:144 msgid "Decimal" msgstr "" #: gresources/nemo-file-management-properties.glade:147 msgid "Decimal (long format)" msgstr "" #: gresources/nemo-file-management-properties.glade:153 msgid "Binary (long format)" msgstr "" #: gresources/nemo-file-management-properties.glade:164 msgid "By Name" msgstr "" #: gresources/nemo-file-management-properties.glade:167 msgid "By Size" msgstr "" #: gresources/nemo-file-management-properties.glade:170 msgid "By Type" msgstr "" #: gresources/nemo-file-management-properties.glade:173 msgid "By Detailed Type" msgstr "" #: gresources/nemo-file-management-properties.glade:176 msgid "By Modification Date" msgstr "" #: gresources/nemo-file-management-properties.glade:179 msgid "By Access Date" msgstr "" #: gresources/nemo-file-management-properties.glade:182 msgid "By Trashed Date" msgstr "" #: gresources/nemo-file-management-properties.glade:193 #: gresources/nemo-file-management-properties.glade:269 #: gresources/nemo-file-management-properties.glade:298 msgid "33%" msgstr "" #: gresources/nemo-file-management-properties.glade:196 #: gresources/nemo-file-management-properties.glade:272 #: gresources/nemo-file-management-properties.glade:301 msgid "50%" msgstr "" #: gresources/nemo-file-management-properties.glade:199 #: gresources/nemo-file-management-properties.glade:275 #: gresources/nemo-file-management-properties.glade:304 msgid "66%" msgstr "" #: gresources/nemo-file-management-properties.glade:202 #: gresources/nemo-file-management-properties.glade:278 #: gresources/nemo-file-management-properties.glade:307 msgid "100%" msgstr "" #: gresources/nemo-file-management-properties.glade:205 #: gresources/nemo-file-management-properties.glade:281 #: gresources/nemo-file-management-properties.glade:310 msgid "150%" msgstr "" #: gresources/nemo-file-management-properties.glade:208 #: gresources/nemo-file-management-properties.glade:284 #: gresources/nemo-file-management-properties.glade:313 msgid "200%" msgstr "" #: gresources/nemo-file-management-properties.glade:211 #: gresources/nemo-file-management-properties.glade:287 #: gresources/nemo-file-management-properties.glade:316 msgid "400%" msgstr "" #: gresources/nemo-file-management-properties.glade:222 msgid "100 KB" msgstr "" #: gresources/nemo-file-management-properties.glade:225 msgid "500 KB" msgstr "" #: gresources/nemo-file-management-properties.glade:228 msgid "1 MB" msgstr "" #: gresources/nemo-file-management-properties.glade:231 msgid "3 MB" msgstr "" #: gresources/nemo-file-management-properties.glade:234 msgid "5 MB" msgstr "" #: gresources/nemo-file-management-properties.glade:237 msgid "10 MB" msgstr "" #: gresources/nemo-file-management-properties.glade:240 msgid "100 MB" msgstr "" #: gresources/nemo-file-management-properties.glade:243 msgid "1 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:246 msgid "2 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:249 msgid "4 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:252 msgid "8 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:255 msgid "16 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:258 msgid "32 GB" msgstr "" #: gresources/nemo-file-management-properties.glade:344 msgid "Yes" msgstr "" #: gresources/nemo-file-management-properties.glade:350 msgid "No" msgstr "" #: gresources/nemo-file-management-properties.glade:356 msgid "File Management Preferences" msgstr "" #: gresources/nemo-file-management-properties.glade:414 msgid "Default View" msgstr "" #: gresources/nemo-file-management-properties.glade:444 msgid "View _new folders using:" msgstr "" #: gresources/nemo-file-management-properties.glade:482 msgid "_Inherit view type from parent" msgstr "" #: gresources/nemo-file-management-properties.glade:505 msgid "_Arrange items:" msgstr "" #: gresources/nemo-file-management-properties.glade:559 msgid "Sort _folders before files" msgstr "" #: gresources/nemo-file-management-properties.glade:600 msgid "Icon View Defaults" msgstr "" #: gresources/nemo-file-management-properties.glade:630 msgid "Default _zoom level:" msgstr "" #: gresources/nemo-file-management-properties.glade:668 msgid "_Text beside icons" msgstr "" #: gresources/nemo-file-management-properties.glade:709 msgid "Compact View Defaults" msgstr "" #: gresources/nemo-file-management-properties.glade:739 msgid "_Default zoom level:" msgstr "" #: gresources/nemo-file-management-properties.glade:777 msgid "A_ll columns have the same width" msgstr "" #: gresources/nemo-file-management-properties.glade:818 msgid "List View Defaults" msgstr "" #: gresources/nemo-file-management-properties.glade:848 msgid "D_efault zoom level:" msgstr "" #: gresources/nemo-file-management-properties.glade:911 msgid "Tree View Defaults" msgstr "" #: gresources/nemo-file-management-properties.glade:934 msgid "Show _only folders" msgstr "" #: gresources/nemo-file-management-properties.glade:971 msgid "Views" msgstr "" #: gresources/nemo-file-management-properties.glade:999 msgid "Behavior" msgstr "" #: gresources/nemo-file-management-properties.glade:1021 msgid "_Single click to open items" msgstr "" #: gresources/nemo-file-management-properties.glade:1038 msgid "_Double click to open items" msgstr "" #: gresources/nemo-file-management-properties.glade:1056 msgid "Click on a file's name twice to rename it" msgstr "" #: gresources/nemo-file-management-properties.glade:1073 msgid "Open each _folder in its own window" msgstr "" #: gresources/nemo-file-management-properties.glade:1090 msgid "Always start in dual-pane view" msgstr "" #: gresources/nemo-file-management-properties.glade:1107 msgid "Ignore per-folder view preferences" msgstr "" #: gresources/nemo-file-management-properties.glade:1124 msgid "Disable file operation queueing" msgstr "" #: gresources/nemo-file-management-properties.glade:1141 msgid "Double-click on a blank area to go to the parent folder" msgstr "" #: gresources/nemo-file-management-properties.glade:1183 msgid "Executable Text Files" msgstr "" #: gresources/nemo-file-management-properties.glade:1206 msgid "_Run executable text files when they are opened" msgstr "" #: gresources/nemo-file-management-properties.glade:1223 msgid "_View executable text files when they are opened" msgstr "" #: gresources/nemo-file-management-properties.glade:1240 msgid "_Ask each time" msgstr "" #: gresources/nemo-file-management-properties.glade:1282 msgid "Trash" msgstr "" #: gresources/nemo-file-management-properties.glade:1305 msgid "Ask before moving files to the Trash" msgstr "" #: gresources/nemo-file-management-properties.glade:1321 msgid "Ask before _emptying the Trash or deleting files" msgstr "" #: gresources/nemo-file-management-properties.glade:1337 msgid "I_nclude a Delete command that bypasses Trash" msgstr "" #: gresources/nemo-file-management-properties.glade:1353 msgid "Bypass the Trash when the Delete key is pressed" msgstr "" #: gresources/nemo-file-management-properties.glade:1393 msgid "Media Handling" msgstr "" #: gresources/nemo-file-management-properties.glade:1416 msgid "Automatically mount removeable media when inserted and on startup" msgstr "" #: gresources/nemo-file-management-properties.glade:1432 msgid "Automatically open a folder for automounted media" msgstr "" #: gresources/nemo-file-management-properties.glade:1448 msgid "Prompt or autorun/autostart programs when media are inserted" msgstr "" #: gresources/nemo-file-management-properties.glade:1464 msgid "" "Automatically close the device's tab, pane, or window when a device is " "unmounted or ejected" msgstr "" #: gresources/nemo-file-management-properties.glade:1505 msgid "Bulk Rename" msgstr "" #: gresources/nemo-file-management-properties.glade:1535 msgid "Command to invoke when renaming multiple items:" msgstr "" #: gresources/nemo-file-management-properties.glade:1588 msgid "Behavior" msgstr "" #: gresources/nemo-file-management-properties.glade:1617 msgid "Icon Captions" msgstr "" #: gresources/nemo-file-management-properties.glade:1642 msgid "" "Choose the order of information to appear beneath icon names. More " "information will appear when zooming in closer." msgstr "" #: gresources/nemo-file-management-properties.glade:1779 msgid "Date" msgstr "" #: gresources/nemo-file-management-properties.glade:1803 msgid "_Format:" msgstr "" #: gresources/nemo-file-management-properties.glade:1851 msgid "Window and Tab Titles" msgstr "" #: gresources/nemo-file-management-properties.glade:1874 msgid "Show the full p_ath in the title bar and tab bars" msgstr "" #: gresources/nemo-file-management-properties.glade:1915 msgid "File Size" msgstr "" #: gresources/nemo-file-management-properties.glade:1939 msgid "_Prefixes:" msgstr "" #: gresources/nemo-file-management-properties.glade:1994 msgid "File Properties" msgstr "" #: gresources/nemo-file-management-properties.glade:2017 msgid "Show advanced permissions in the file property dialog" msgstr "" #: gresources/nemo-file-management-properties.glade:2058 msgid "Move/Copy To Menu" msgstr "" #: gresources/nemo-file-management-properties.glade:2081 msgid "List bookmarks in the menu" msgstr "" #: gresources/nemo-file-management-properties.glade:2097 msgid "List devices and network locations in the menu" msgstr "" #: gresources/nemo-file-management-properties.glade:2134 msgid "Display" msgstr "" #: gresources/nemo-file-management-properties.glade:2163 msgid "List Columns" msgstr "" #: gresources/nemo-file-management-properties.glade:2188 msgid "Choose the order of information to appear in the list view." msgstr "" #: gresources/nemo-file-management-properties.glade:2224 msgid "List Columns" msgstr "" #: gresources/nemo-file-management-properties.glade:2253 msgid "Previewable Files" msgstr "" #: gresources/nemo-file-management-properties.glade:2283 msgid "Show _thumbnails:" msgstr "" #: gresources/nemo-file-management-properties.glade:2321 msgid "_Inherit thumbnail visibility from parent" msgstr "" #: gresources/nemo-file-management-properties.glade:2344 msgid "_Only for files smaller than:" msgstr "" #: gresources/nemo-file-management-properties.glade:2407 msgid "Folders" msgstr "" #: gresources/nemo-file-management-properties.glade:2437 msgid "Count _number of items:" msgstr "" #: gresources/nemo-file-management-properties.glade:2500 msgid "Tooltips" msgstr "" #: gresources/nemo-file-management-properties.glade:2523 msgid "Show tooltips in icon and compact views" msgstr "" #: gresources/nemo-file-management-properties.glade:2540 msgid "Show tooltips in list views" msgstr "" #: gresources/nemo-file-management-properties.glade:2557 msgid "Show tooltips on the desktop" msgstr "" #: gresources/nemo-file-management-properties.glade:2576 msgid "" "By default, a folder tooltip shows the item count, and files display " "their size.\n" " Select additional information to display in the tooltip:" msgstr "" #: gresources/nemo-file-management-properties.glade:2601 msgid "Detailed file type" msgstr "" #: gresources/nemo-file-management-properties.glade:2616 msgid "Modified date" msgstr "" #: gresources/nemo-file-management-properties.glade:2631 msgid "Created date" msgstr "" #: gresources/nemo-file-management-properties.glade:2647 msgid "Accessed date" msgstr "" #: gresources/nemo-file-management-properties.glade:2663 msgid "File or folder location" msgstr "" #: gresources/nemo-file-management-properties.glade:2709 msgid "Preview" msgstr "" #: gresources/nemo-file-management-properties.glade:2738 msgid "Visible Buttons" msgstr "" #: gresources/nemo-file-management-properties.glade:2783 msgid "Previous" msgstr "" #: gresources/nemo-file-management-properties.glade:2820 msgid "Next" msgstr "" #: gresources/nemo-file-management-properties.glade:2857 msgid "Up" msgstr "" #: gresources/nemo-file-management-properties.glade:2894 msgid "Refresh" msgstr "" #: gresources/nemo-file-management-properties.glade:3005 msgid "Location entry toggle" msgstr "" #: gresources/nemo-file-management-properties.glade:3042 msgid "Open in terminal" msgstr "" #: gresources/nemo-file-management-properties.glade:3153 msgid "Icon view" msgstr "" #: gresources/nemo-file-management-properties.glade:3190 msgid "List view" msgstr "" #: gresources/nemo-file-management-properties.glade:3227 msgid "Compact view" msgstr "" #: gresources/nemo-file-management-properties.glade:3299 msgid "Toolbar" msgstr "" #: gresources/nemo-file-management-properties.glade:3322 msgid "Visible Entries" msgstr "" #: gresources/nemo-file-management-properties.glade:3353 msgid "Selection" msgstr "" #: gresources/nemo-file-management-properties.glade:3729 msgid "Background" msgstr "" #: gresources/nemo-file-management-properties.glade:4052 msgid "" "Visible action and extension entries can be configured in the Plugins tab" msgstr "" #: gresources/nemo-file-management-properties.glade:4069 msgid "Context Menus" msgstr "" nemo-4.4.2/po/000077500000000000000000000000001357442400300130775ustar00rootroot00000000000000nemo-4.4.2/po/ChangeLog000066400000000000000000012503031357442400300146550ustar00rootroot000000000000002010-07-04 Funda Wang * zh_CN.po: Updated zh_CN translation from YunQiang Su . 2009-06-10 Manoj Kumar Giri * hi.po: Committed Hindi Translation on behalf of Rajesh Ranjan. === nemo 2.26.2 === 2009-04-13 ReÅŸat SABIQ * crh.po: Updated Crimean Tatar (Crimean Turkish) translation. 2009-04-12 Jorge Gonzalez * es.po: Updated Spanish translation 2009-04-12 Priit Laes * et.po: Translation updated by Mattias Põldaru 2009-04-07 Philip Withnall * en_GB.po: Changes by Bruce Cowan to fix the British English date formats. (Closes: #578189) 2009-04-03 Simos Xenitellis * el.po: Updated Greek translation (Thanos Lefteris). === nemo 2.26.1 === 2009-03-30 Baris Cicek * tr.po: Updated Turkish translation. 2009-03-25 Shankar Prasad * kn.po: Updated few correction to Kannada translations. 2009-03-23 Kenneth Nielsen * da.po: Updated Danish translation by Ask H. Larsen 2009-03-21 Goran Rakic * sr.po, sr@latin.po: Updated Serbian translation by MiloÅ¡ Popović. 2009-03-19 Claude Paroz * LINGUAS: * crh.po: Added Crimean Tatar translation on behalf of ReÅŸat SABIQ. 2009-03-18 Djihed Afifi * ar.po: Updated Arabic translation by Khaled Hosny. 2009-03-17 Nikos Charonitakis * el.po: Updated Greek translation by Pierros Papadeas. 2009-03-17 Ignacio Casal Quinteiro * gl.po: Updated Galician translation by Suso Baleato. 2009-03-17 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-03-16 Hendrik Richter * de.po: Updated German translation, fix #575448. 2009-03-16 Ankitkumar Patel * gu.po: Updated Gujarati Translations. 2009-03-16 Ankitkumar Patel * gu.po: Updated Gujarati Translations. === nemo 2.26.0 === 2009-03-16 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2009-03-16 Amitakhya Phukan * as.po: Updated Assamese translations. 2009-03-16 Amitakhya Phukan * as.po: Updated Assamese translations. 2009-03-16 Petr Kovar * cs.po: Updated Czech translation by Lucas Lommer. 2009-03-15 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2009-03-15 Kostas Papadimas * el.po: Updated Greek Translation by Pierros Papadeas 2009-03-14 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2009-03-14 MiÈ™u Moldovan * ro.po: Updated Romanian translation by Adi Roiban 2009-03-14 Sandeep Shedmake * mr.po: Updated Marathi Translations. 2009-03-14 Krishnababu K * te.po: Updated Telugu Translation. 2009-03-14 Kenneth Nielsen * da.po: Updated Danish translation by Ask H. Larsen 2009-03-13 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2009-03-13 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2009-03-13 Priit Laes * et.po: Translation updated by Mattias Põldaru 2009-03-12 Duarte Loreto * pt.po: Fixed an error on the Portuguese translation. 2009-03-12 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation 2009-03-11 Krishnababu K * te.po: Updated Telugu Translation. === nemo 2.25.93 === 2009-03-11 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2009-03-10 Nickolay V. Shmyrev * ru.po: Updated Russian translation by Yuriy Penkin. 2009-03-10 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2009-03-10 I. Felix * ta.po: Tamil Translation updated 2009-03-10 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2009-03-09 Dwayne Bailey * nso.po: Fixed broken Northern Sotho gconf translations (fixes bug #569493). 2009-03-08 Petr Kovar * cs.po: Fixed Czech translation by Lucas Lommer (fixes bug #568087]. 2009-03-07 Mario Blättermann * de.po: Updated German translation by Wolfgang Stöggl. 2009-03-07 Ilkka Tuohela * fi.po: Updated Finnish translation. 2009-03-06 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2009-03-05 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-03-05 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-03-05 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-03-05 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-03-03 Claude Paroz * fr.po: Updated French translation by Laurent Coudeur and Bruno Brouard. 2009-03-04 Takeshi AIHANA * ja.po: Updated Japanese translation. 2009-03-03 Manoj Kumar Giri * or.po: Upadted Oriya Translation. 2009-03-03 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2009-03-03 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2009-03-02 Milo Casagrande * it.po: Updated Italian translation by Luca Ferretti 2009-03-02 Hendrik Richter * de.po: Updated German translation. 2009-03-02 Hendrik Richter * de.po: Updated German translation. === nemo 2.25.92 === 2009-03-02 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2009-03-02 Shankar Prasad * kn.po: Updated Kannada translations. 2009-03-01 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-02-28 Gabor Kelemen * hu.po: Translation updated. 2009-02-38 Yair Hershkovitz * he.po: Updated Hebrew translation. 2009-02-28 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2009-02-27 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2009-02-27 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2009-02-27 Luca Ferretti * it.po: Updated Italian translation. 2009-02-26 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-02-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2009-02-26 Changwoo Ryu * ko.po: Updated Korean translation. 2009-02-25 Og Maciel * pt_BR.po: Updated Brazilian Portuguese translation by André Gondim and reviewed by myself. 2009-02-25 Duarte Loreto * pt.po: Updated Portuguese translation. 2009-02-24 Wouter Bolsterlee * nl.po: Updated Dutch translation by Wouter Bolsterlee. 2009-02-24 Wadim Dziedzic * pl.po: Updated Polish translation 2009-02-24 Philip Withnall * en_GB.po: Updated British English translation. 2009-02-24 Jorge Gonzalez * es.po: Updated Spanish translation by Juan Jesús Ojeda and me 2009-02-24 Daniel Nylander * sv.po: Updated Swedish translation. 2009-02-23 Og Maciel * pt_BR.po: Updated Brazilian Portuguese translation by André Gondim and reviewed by Vladimir Melo. 2009-02-23 Philip Withnall * en_GB.po: Updated British English translation. 2009-02-23 Gabor Kelemen * hu.po: Translation updated. 2009-02-23 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2009-02-23 Wouter Bolsterlee * nl.po: Updated Dutch translation by Wouter Bolsterlee. 2009-02-23 Priit Laes * et.po: Translation updated by Ivar Smolin 2009-02-21 Christian Kirbach * de.po: Updated German translation. 2009-02-20 Jani Monoses * ro.po: Updated Romanian translation by Adi Roiban 2009-02-20 Daniel Nylander * sv.po: Updated Swedish translation. 2009-02-20 Claude Paroz * fr.po: Updated French translation by Bruno Brouard. 2009-02-20 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-20 Priit Laes * et.po: Translation updated by Mattias Põldaru 2009-02-20 Takeshi AIHANA * ja.po: Updated Japanese translation. 2009-02-19 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2009-02-19 Gabor Kelemen * hu.po: Translation updated. 2009-02-19 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2009-02-18 Andre Klapper * cs.po: Updated Czech translation by Lucas Lommer 2009-02-18 Priit Laes * et.po: Translation updated by Ivar Smolin 2009-02-18 Sandeep Shedmake * mr.po: Bug fix for #571898. 2009-02-18 Changwoo Ryu * ko.po: Updated Korean translation. 2009-02-17 Gabor Kelemen * hu.po: Translation updated. 2009-02-17 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-17 Daniel Nylander * sv.po: Updated Swedish translation. 2009-02-17 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2009-02-16 Ilkka Tuohela * fi.po: Updated Finnish translation. === nemo 2.25.91 === 2009-02-16 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-15 Duarte Loreto * pt.po: Updated Portuguese translation. 2009-02-15 Kenneth Nielsen * da.po: Updated Danish translation by Ask H. Larsen 2009-02-14 Jorge Gonzalez * es.po: Updated Spanish translation, fixes bug #569457 2009-02-14 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation by Ihar Hrachyshka. 2009-02-14 Daniel Nylander * sv.po: Updated Swedish translation. 2009-02-14 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2009-02-14 Wouter Bolsterlee * nl.po: Updated Dutch translation by Wouter Bolsterlee. 2009-02-13 Jorge Gonzalez * es.po: Updated Spanish translation 2009-02-13 Clytie Siddall * vi.po: Updated Vietnamese translation. 2009-02-13 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2009-02-13 Gabor Kelemen * hu.po: Translation updated. 2009-02-12 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2009-02-12 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-11 Jonh Wendell * pt_BR.po: Updated Brazilian Portuguese translation. 2009-02-10 Daniel Nylander * sv.po: Updated Swedish translation. 2009-02-10 Gil Forcada * ast.po: Updated Asturian translation on behalf of Mikel González. 2009-02-10 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-02-09 Takeshi AIHANA * ja.po: Updated Japanese translation. 2009-02-07 Goran Rakić * sr.po, sr@latin.po: Updated Serbian translation wrt bug #570838. 2009-02-07 Clytie Siddall * vi.po: Updated Vietnamese translation. 2008-06-25 Christian Kirbach * de.po: Updated German translation. 2009-02-04 Manoj Kumar Giri * or.po: Updated Oriya Translation. 2009-02-04 Manoj Kumar Giri * or.po: Updated Oriya Translation. 2009-02-04 Runa Bhattachajee * bn_IN.po: Updated the gconf values wrt bug #569497 2009-02-03 Manoj Kumar Giri * or.po: Updated Oriya Translation. 2009-02-02 Jorge Gonzalez * es.po: Updated Spanish translation. === nemo 2.25.4 === 2009-01-31 Daniel Nylander * sv.po: Updated Swedish translation. 2009-01-30 Jorge Gonzalez * es.po: Updated Spanish translation. 2009-01-30 Ilkka Tuohela * fi.po: Updated Finnish translation. 2009-01-29 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-01-29 Changwoo Ryu * ko.po: Updated Korean translation. 2009-01-29 Sandeep Shedmake * mr.po: Bug fix for #569503. 2009-01-29 Jovan Naumovski * mk.po: Bug fix for #569495. 2009-01-29 Funda Wang * zh_CN.po: Updated zh_CN translation. 2009-01-27 Jonh Wendell * pt_BR.po: Brazilian Portuguese translation updated by Fabrício Godoy. 2009-01-25 Andre Klapper * de.po: Updated German translation. 2009-01-24 Raivis DEjus * lv.po: Updated Latvian translation. 2009-01-21 A. Walton * cs.po: * de.po: * es.po: * et.po: * eu.po: * fr.po: * ha.po: * he.po: * hu.po: * ig.po: * it.po: * nb.po: * sk.po: * sl.po: * sr.po: * sr@latin.po: * sv.po: * uz.po: * uz@cyrillic.po: * yo.po: Bug 568503 – Misspelled word "progam"->"program" Fixing message ids. === nemo 2.25.3 === 2009-01-17 Thomas Thurman * ig.po: Added Igbo translation by Sylvester Onye. * yo.po Added Yoruba translation by Sunday Ayo Fajuyitan. * ha.po: Added Hausa translation by Saudat Mohammed. * LINGUAS: added Igbo, Yoruba and Hausa. 2009-01-17 Jorge Gonzalez * es.po: Updated Spanish translation. 2009-01-13 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-01-13 Gabor Kelemen * hu.po: Translation updated. 2009-01-12 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2009-01-08 Daniel Nylander * sv.po: Updated Swedish translation. 2009-01-06 Nurali Abdurahmonov * uz.po: Added uzbek translation * uz@cyrillic.po: Added uzbek cyrillic translation * LINGUAS: added uz and uz@cyrillic 2009-01-06 Luca Ferretti * it.po: Updated Italian translation. 2009-01-03 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-12-29 Hendrik Richter * de.po: Updated German translation. 2008-12-27 Luca Ferretti * it.po: Updated Italian translation. 2008-12-21 Marcel Telka * sk.po: Updated Slovak translation. 2008-12-16 Jorge Gonzalez * es.po: Updated Spanish translation. 2008-12-15 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-12-15 Claude Paroz * fr.po: Updated French translation. === nemo 2.25.2 === 2008-12-15 Alexander Larsson * POTFILES.in: * *.po: Imported eel pofiles 2008-12-08 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-12-07 Mario Blättermann * de.po: Some fixes in German translation 2008-12-03 Goran Rakić * sr.po, sr@latin.po: Fixed Ubuntu bug lp#197224. === nemo 2.25.1 === 2008-12-01 Alexander Larsson * POTFILES.in: * POTFILES.skip: Update 2008-11-11 Mark Krapivner * he.po: Fixed a few errors 2008-11-09 Petr Kovar * cs.po: Fixed Czech translation (thanks to Kamil Paral). 2008-11-09 Leonardo Ferreira Fontenelle * pt_BR.po: Merged from branch gnome-2-24 minor improvements in the Brazilian Portuguese translation. 2008-11-09 Goran Rakić * sr.po, sr@latin.po: Updated Serbian Translation (by MiloÅ¡ Popović). 2008-11-08 Jorge Gonzalez * es.po: Updated Spanish translation. 2008-11-08 Inaki Larranaga Murgoitio * eu.po: Fixed some errors and updated Basque translation. 2008-11-06 Luca Ferretti * it.po: Updated Italian translation. 2008-10-28 Daniel Nylander * sv.po: Updated Swedish translation. 2008-10-27 Cosimo Cecchi * POTFILES.in: update after the move away from libgnome/bonobo/glade. Thanks to Frederic Peters (#558134). 2008-10-25 Leonardo Ferreira Fontenelle * pt_BR.po: Merged from branch gnome-2-24 improvements in Brazilian Portuguese translation by Fabrício Godoy. 2008-10-25 Priit Laes * et.po: Translation updated by Priit Laes 2008-10-23 Andre Klapper * LINGUAS: Added ast. * ast.po: Added Asturian translation on behalf of Mikel González. 2008-10-20 Jordi Mallach * ca@valencia.po: Updated Valencian (Southern Catalan) translation from the Catalan file. 2008-10-12 Leonardo Ferreira Fontenelle * pt_BR.po: Merged from branch gnome-2-24 terminology fixes in Brazilian Portuguese translation by Vladimir Melo. 2008-10-09 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-10-07 Simos Xenitellis * el.po: Updated Greek translation. 2008-10-05 Daniel Nylander * sv.po: Updated Swedish translation. 2008-10-01 Matic Zgur * sl.po: Updated Slovenian translation. 2008-09-27 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-09-27 Laurent Dhima * sq.po: Updated Albanian Translation. 2008-09-25 Jovan Naumovski * mk.po: Updated Macedonian translation. 2008-09-22 Goran Rakić * sr.po, sr@latin.po: Updated Serbian Translation. 2008-09-22 Timo Jyrinki * fi.po: Updated Finnish translation. 2008-09-22 Nikos Charonitakis * el.po: Updated Greek translation. 2008-09-22 Kenneth Nielsen * da.po: Updated Danish translation by Kenneth Nielsen 2008-09-22 Goran Rakić * sr.po, sr@latin.po: Updated Serbian Translation (by MiloÅ¡ Popović). 2008-09-22 Mugurel Tudor * ro.po: Updated Romanian translation by MiÅŸu Moldovan 2008-09-21 Wadim Dziedzic * pl.po: Updated Polish translation 2008-09-21 Alexandre Prokoudine * ru.po: Updated Russian translation by Yuri Penkin 2008-09-20 Kenneth Nielsen * da.po: Updated Danish translation by Ask H. Larsen 2008-09-20 Laurent Dhima * sq.po: Updated Albanian Translation. 2008-09-20 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-09-20 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-09-20 Goran Rakić * sr.po, sr@latin.po: Updated Serbian translation (by MiloÅ¡ Popović). 2008-09-19 Og Maciel * pt_BR.po: Updated Brazilian Portuguese translation by Vladimir Melo. 2008-09-19 Gabor Kelemen * hu.po: Translation updated. 2008-09-18 Kostas Papadimas * el.po: Updated Greek Translation by Athanasios Lefteris 2008-09-18 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2008-09-18 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Afif Emad. 2008-09-15 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2008-09-15 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Afif Emad. 2008-09-15 I. Felix * ta.po: Tamil Translation error corrected. 2008-09-14 Praveen Arimbrathodiyil * ml.po: Malayalam translation updated. 2008-09-14 Robert-André Mauchin * af.po: Updated Afrikaans translation by Friedel Wolff. 2008-09-14 Luca Ferretti * it.po: Updated Italian translation. 2008-09-14 Petr Kovar * cs.po: Updated Czech translation by Kamil Paral (bug #551977). 2008-09-14 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-09-12 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-09-12 Reinout van Schouwen * nl.po: Translation updated by Reinout van Schouwen. 2008-09-11 Hendrik Richter * de.po: Updated German translation. 2008-09-10 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-09-09 Og Maciel * pt_BR.po: Revision of Brazilian Portuguese translation by Vladimir Melo. 2008-09-09 Robert Sedak * hr.po: Updated Croatian translation. 2008-09-09 Sandeep Shedmake * mr.po: Updated Marathi Translations 2008-09-09 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-09-09 Laurent Dhima * sq.po: Updated Albanian Translation. 2008-09-09 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2008-09-09 Baris Cicek * tr.po: Updated Turkish translation 2008-09-08 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2008-09-07 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-09-07 Reinout van Schouwen * nl.po: Translation updated by Reinout van Schouwen. 2008-09-06 Luca Ferretti * it.po: Updated Italian translation. 2008-09-06 Philip Withnall * en_GB.po: Updated British English translation. 2008-09-06 Claude Paroz * fr.po: Updated French translation. 2008-09-06 Funda Wang * zh_CN.po: Updated zh_CN translation. 2008-09-05 Gil Forcada * ca.po: Minor fix by Joan Duran. 2008-09-05 Tomasz Dominikowski * pl.po: Updated Polish translation 2008-09-04 Robert-André Mauchin * LINGUAS: * ps.po: Added Pashto translations by Zabeeh Khan. 2008-09-04 Daniel Nylander * sv.po: Updated Swedish translation. 2008-09-03 Hendrik Richter * de.po: Updated German translation. 2008-09-02 Og Maciel * pt_BR.po: Updated Brazilian Portuguese translation by Og Maciel. 2008-09-02 Nguyá»…n Thái Ngá»c Duy * vi.po: Updated Vietnamese translation 2008-09-02 Jorge Gonzalez * es.po: Updated Spanish translation 2008-09-02 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-09-01 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2008-09-01 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-09-01 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2008-09-01 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-09-01 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-09-01 Hendrik Richter * de.po: Updated German translation. 2008-09-01 Hendrik Richter * de.po: Updated German translation. 2008-08-31 Seán de Búrca * ga.po: Updated Irish translation. 2008-08-30 Og Maciel * pt_BR.po: Fixes Bug #549897. 2008-08-30 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-08-30 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-08-29 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-29 Hendrik Richter * de.po: Updated German translation. 2008-08-29 Rajesh Ranjan * mai.po: Added Maithili translation. 2008-08-28 Daniel Nylander * sv.po: Updated Swedish translation. 2008-08-28 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-08-28 Hendrik Richter * de.po: Updated German translation. 2008-08-28 Petr Kovar * cs.po: Updated Czech translation. 2008-08-27 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-08-27 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-08-26 Yair Hershkovitz * he.po: Updated Hebrew translation by Mark Krapivner. 2008-08-25 Og Maciel * pt_BR.po: Updated Brazilian Portuguese translation by Vladimir Melo. 2008-08-26 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-25 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-08-25 Goran Rakic * LINGUAS, sr@latin.po, sr@Latn.po: Conversion from sr@Latn to sr@latin. 2008-08-25 Jovan Naumovski * mk.po: Updated Macedonian translation. 2008-08-24 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-08-24 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-08-21 Shankar Prasad * kn.po: Updated Kannada translations. 2008-08-20 Shankar Prasad * kn.po: Updated Kannada translations. 2008-08-20 Shankar Prasad * kn.po: Updated Kannada translations. 2008-08-19 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-08-19 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-19 Shankar Prasad * kn.po: Updated Kannada translations. 2008-08-19 Luca Ferretti * it.po: Updated Italian translation. 2008-08-18 Claude Paroz * fr.po: Updated French translation by Robert-André Mauchin and Claude Paroz. 2008-08-17 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-17 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-08-16 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-08-16 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-08-16 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-08-15 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-08-14 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-08-14 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2008-08-14 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-08-13 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-13 Petr Kovar * cs.po: Updated Czech translation by Lucas Lommer. 2008-08-13 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-08-12 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-08-09 Luca Ferretti * it.po: Updated Italian translation. 2008-08-09 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-08-08 Petr Kovar * cs.po: Updated Czech translation by Lucas Lommer. 2008-08-08 Hendrik Richter * de.po: Updated German translation. 2008-08-07 Wadim Dziedzic * pl.po: Updated Polish translation 2008-08-07 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-08-06 Ignacio Casal Quinteiro * gl.po: Updated Galician translation 2008-08-06 Daniel Nylander * sv.po: Updated Swedish translation. 2008-08-6 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-08-05 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-05 Daniel Nylander * sv.po: Updated Swedish translation. 2008-08-04 Jorge Gonzalez * es.po: Updated Spanish translation 2008-08-03 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-07-29 Colin Walters * oc.po: Revert last commit, it broke the build. 2008-07-29 Funda Wang * zh_CN.po: Updated zh_CN translation. 2008-07-29 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-07-28 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-07-28 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-07-25 Daniel Nylander * sv.po: Updated Swedish translation. 2008-07-25 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-07-24 Leonardo Ferreira Fontenelle * pt_BR.po: Terminology improvements by Vladimir Melo. 2008-07-24 Jorge Gonzalez * es.po: Updated Spanish translation 2008-07-22 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-07-21 Hendrik Richter * de.po: Fixed German translation by Jens Seidel . 2008-07-21 Hendrik Richter * de.po: Updated German translation, fix #543972. 2008-07-21 Hendrik Richter * de.po: Updated German translation, fix #543973. 2008-07-17 Hendrik Richter * de.po: Fixed German translation by Jens Seidel . 2008-07-16 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-07-16 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-07-13 Jorge Gonzalez * es.po: Updated Spanish translation 2008-07-12 Daniel Nylander * sv.po: Updated Swedish translation. 2008-07-12 Claude Paroz * fr.po: Updated French translation by Bruno Brouard and Claude Paroz. 2008-07-10 Gabor Kelemen * hu.po: Translation updated by Máté Åry. 2008-07-10 Matej UrbanÄiÄ * sl.po: Updated Slovenian Translation. 2008-07-10 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-07-09 Kjartan Maraas * POTFILES.in: Add missing files. * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-07-04 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-07-02 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-06-27 Changwoo Ryu * ko.po: Updated Korean translation. 2008-06-25 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-06-24 Daniel Nylander * sv.po: Updated Swedish translation. 2008-06-19 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-06-18 Gabor Kelemen * hu.po: Translation updated by Máté Åry. 2008-06-17 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-06-15 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-06-14 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-06-14 Jorge Gonzalez * es.po: Updated Spanish translation 2008-06-11 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-06-11 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-06-10 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-06-08 Funda Wang * zh_CN.po: Updated zh_CN translation. 2008-06-07 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-06-05 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-06-05 Roozbeh Pournader * fa.po: Fixed a bad message in Persian translation (fixes bug #511623, reported by Hedayat Vatankhah, patch by Elnaz Sarbar) ==================== 2.23.3 ==================== 2008-06-01 Jovan Naumovski * mk.po: Updated Macedonian translation. 2008-06-02 Clytie Siddall * vi.po: Updated Vietnamese translation. 2008-05-25 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-05-24 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2008-05-24 Jorge Gonzalez * es.po: Updated Spanish translation 2008-05-23 Jorge Gonzalez * es.po: Updated Spanish translation 2008-05-23 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-05-19 Djihed Afifi * ar.po: Updated Arabic Translation by Djihed Afifi. 2008-05-14 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. === nemo 2.23.2 === 2008-05-10 Jorge Gonzalez * es.po: Updated Spanish translation 2008-05-06 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-05-03 Jorge Gonzalez * es.po: Updated Spanish translation 2008-05-02 Cosimo Cecchi * oc.po: Reverted last update of Occitan translation, it was breaking the build. (#530970). 2008-04-30 Jorge Gonzalez * es.po: Updated Spanish translation 2008-04-30 Andre Klapper * LINGUAS: * fur.po: Added Friulian translation on behalf of the Friulian team. Fixes bug #530509. 2008-04-30 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-04-29 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-04-29 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-04-24 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2008-04-23 Jorge Gonzalez * es.po: Updated Spanish translation by Alberto Caso, fixes LP bug #197224 2008-04-22 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-04-21 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-04-19 Daniel Nylander * sv.po: Updated Swedish translation. 2008-04-14 Michael Terry * io.po: Added partial Ido translation. 2008-04-13 Jorge Gonzalez * es.po: Updated Spanish translation, fixes bug #526626 2008-04-11 Marcel Telka * POTFILES.in: Updated. 2008-04-11 Jorge Gonzalez * es.po: Updated Spanish translation 2008-04-10 Jordi Mallach * ca@valencia.po: New Valencian-Catalan translation, based on the current Catalan file. 2008-04-10 Jordi Mallach * ca.po: Fix typo in Catalan translation. 2008-04-07 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-04-01 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2008-04-01 Claude Paroz * fr.po: Removed fuzzy generated by commit 14017. 2008-03-31 Eskild Hustvedt * nn.po: Updated Norwegian Nynorsk translation 2008-03-30 Jorge Gonzalez * es.po: Updated Spanish translation === nemo 2.22.1 === 2008-03-23 Nguyá»…n Thái Ngá»c Duy * vi.po: Update Vietnamese translation 2008-03-22 Nikos Charonitakis * el.po: Updated Greek translation. 2008-03-20 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2008-03-15 Alexander Nyakhaychyk * be.po: Updated Belarusian Translation. 2008-03-14 Andre Klapper * de.po: Added missing mnemonic to German version. 2008-03-12 Stéphane Raimbault * fr.po: Fixed French translation. 2008-03-12 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-03-11 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-03-10 Ani Peter * it.po: Fixed (maybe) duplicate shortcuts. 2008-03-10 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-03-09 Vasiliy Faronov * ru.po: Updated Russian translation. 2008-03-09 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-03-09 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2008-03-09 Kostas Papadimas * el.po: Updated Greek translation 2008-03-09 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2008-03-09 Kenneth Nielsen * da.po: Updated Danish translation 2008-03-08 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2008-03-08 Wadim Dziedzic * pl.po: Updated polish translation 2008-03-08 Baris Cicek * tr.po: Updated Turkish translation. 2008-03-08 Djihed Afifi * ar.po: Updated Arabic Translation by Djihed Afifi. 2008-03-08 Guntupalli Karunakar * hi.po: Fix plural errors. 2008-03-08 Daniel Nylander * sv.po: Updated Swedish translation. 2008-03-08 Runa Bhattacharjee * bn_IN.po: Corrected errors related to plural forms 2008-03-07 Andre Klapper * cs.po: Updated Czech translation on behalf of Lucas Lommer. 2008-03-07 Sunil Mohan Adapa * te.po: Updated Telugu translation done by Krishna Babu K . 2008-03-07 Gabor Kelemen * hu.po: Translation updated 2008-03-06 Wadim Dziedzic * pl.po: Updated polish translation 2008-03-05 Ani Peter * ml.po: Updated Malayalam Translation 2008-03-05 Wouter Bolsterlee * nl.po: Updated Dutch translation by Tino Meinen. 2008-03-05 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2008-03-04 Petr Kovar * cs.po: Fixed Czech translation by Lucas Lommer, thanks to Kamil Paral (bug #520256). 2008-03-04 Hendrik Richter * de.po: Updated German translation. 2008-03-03 Jorge Gonzalez * es.po: Updated Spanish translation 2008-03-03 Rahul Bhalerao * mr.po: Updated Marathi translations from Sandeep Shedmake. 2008-03-03 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-03-03 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-03-03 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-03-03 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-03-03 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-03-03 Reinout van Schouwen * nl.po: Translation updated by Reinout van Schouwen. 2008-03-03 Philip Withnall * en_GB.po: Updated British English translation. 2008-03-02 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2008-03-02 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-03-02 Petr Kovar * cs.po: Updated Czech translation by Lucas Lommer. 2008-03-01 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2008-03-01 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2008-02-29 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-02-29 Daniel Nylander * sv.po: Updated Swedish translation. 2008-02-29 Luca Ferretti * it.po: Updated Italian translation. 2008-02-28 Jorge Gonzalez * es.po: Updated Spanish translation 2008-02-28 Hendrik Richter * de.po: Updated German translation. 2008-02-28 Luca Ferretti * it.po: Updated Italian translation. 2008-02-27 Luca Ferretti * it.po: Updated Italian translation. 2008-02-27 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-02-27 Claude Paroz * fr.po: Updated French translation. 2008-02-27 Jorge Gonzalez * es.po: Updated Spanish translation 2008-02-27 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2008-02-27 Djihed Afifi * ar.po: Updated Arabic Translation by Abdelmonam Kouka. 2008-02-27 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-02-27 Arangel Angov * mk.po: Updated Macedonian translation. 2008-02-26 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated by Vladimir Melo. 2008-02-26 Djihed Afifi * ar.po: Updated Arabic Translation by Abdelmonam Kouka. 2008-02-26 Changwoo Ryu * ko.po: Updated Korean translation. 2008-02-26 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-02-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-02-26 Luca Ferretti * POTFILES.in: * POTFILES.skip: Restore the removed connect to server files 2008-02-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-02-26 Daniel Nylander * sv.po: Updated Swedish translation. === nemo 2.21.92 === 2008-02-25 Gil Forcada * ca.po: Updated Catalan translation by Joan Duran. 2008-02-24 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated by Vladimir Melo and myself. 2008-02-22 Petr Kovar * cs.po: Updated Czech translation by Kamil Paral. 2008-02-22 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2008-02-22 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-02-22 Arangel Angov * mk.po: Updated Macedonian translation. 2008-02-21 Stéphane Raimbault * fr.po: Updated French translation by Robert-André Mauchin, Bruno Brouad et Claude Paroz. 2008-02-21 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-02-21 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-02-21 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-02-21 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-02-21 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-02-21 Funda Wang * zh_CN.po: Update Simplified Chinese translation. 2008-02-20 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-02-20 Hendrik Richter * de.po: Updated German translation. 2008-02-20 Daniel Nylander * sv.po: Updated Swedish translation. 2008-02-20 Jorge Gonzalez * es.po: Updated Spanish translation 2008-02-20 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2008-02-19 Djihed Afifi * ar.po: Updated Arabic Translation by Abdelmonam Kouka. 2008-02-19 Daniel Nylander * sv.po: Updated Swedish translation. 2008-02-19 Alexander Larsson * POTFILES.in: Removed nemo-file-operations-progress.c 2008-02-18 Hendrik Richter * de.po: Updated German translation. 2008-02-18 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-02-18 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-02-17 Nguyá»…n Thái Ngá»c Duy * vi.po: Updated Vietnamese translation 2008-02-17 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-02-16 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-02-16 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-02-16 Arangel Angov * mk.po: Updated Macedonian translation. 2008-02-14 Jorge Gonzalez * es.po: Updated Spanish translation 2008-02-14 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-02-14 Runa Bhattacharjee * kn.po: Updated Translation for Kannada by Shankar Prasad 2008-02-14 Pawan Chitrakar * ne.po: Updated Nepali Translation. 2008-02-14 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-02-14 Arangel Angov * mk.po: Updated Macedonian Translation. 2008-02-13 Jonh Wendell * pt_BR.po: Updated Brazilian Portuguese translation by Vladimir Melo and Pedro de Medeiros. 2008-02-13 Luca Ferretti * it.po: Updated Italian translation. 2008-02-13 Yannig Marchegay * oc.po: Updated Occitan translation. === nemo 2.21.91 === 2008-02-11 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-02-10 Vasiliy Faronov * ru.po: Updated Russian translation. 2008-02-10 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-02-08 Hendrik Richter * de.po: Updated German translation. 2008-02-08 Hendrik Richter * de.po: Updated German translation. 2008-02-08 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-02-08 Jorge Gonzalez * es.po: Updated Spanish translation 2008-02-07 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2008-02-07 Nikos Charonitakis * el.po: Updated Greek translation. 2008-02-06 Alexander Larsson * it.po: Fix mistranslation (#510308) 2008-02-05 Yair Hershkovitz * he.po: Updated Hebrew translation by Mark Krapviner. 2008-02-04 Luca Ferretti * it.po: Updated Italian translation. 2008-02-04 Danishka Navin * si.po: Updated Sinhala translation. 2008-02-03 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-02-03 Yair Hershkovitz * he.po: Updated Hebrew translation by Mark Krapviner. 2008-02-02 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-02-02 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2008-02-01 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-02-01 Runa Bhattacharjee * kn.po: Updated Kannada Translations by Shankar Prasad. 2008-01-31 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-01-30 Funda Wang * zh_CN.po: Update Simplified Chinese translation. 2008-01-29 Daniel Nylander * sv.po: Updated Swedish translation. 2008-01-29 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-01-29 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-29 Jonh Wendell * pt_BR.po: Brazilian Portuguese translation updated by Vladimir Melo. 2008-01-28 Daniel Nylander * sv.po: Updated Swedish translation. === nemo 2.21.90 === 2008-01-28 Luca Ferretti * it.po: Updated Italian translation. 2008-01-28 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-27 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-01-27 Jovan Naumovski * mk.po: Updated Macedonian translation. 2008-01-26 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-01-26 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-26 Jovan Naumovski * mk.po: Updated Macedonian translation. 2008-01-25 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-01-24 Daniel Nylander * sv.po: Updated Swedish translation. 2008-01-23 Luca Ferretti * it.po: Updated Italian translation. 2008-01-22 Jorge Gonzalez * es.po: Updated Spanish translation. 2008-01-22 Yair Hershkovitz * he.po: Updated Hebrew translation. === nemo 2.21.6 === 2008-01-21 Alexander Larsson * POTFILES.in: * POTFILES.skip: Add new files 2008-01-21 Changwoo Ryu * ko.po: Updated Korean translation. 2008-01-20 Luca Ferretti * it.po: Updated Italian translation. 2008-01-19 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-18 Gil Forcada * tr.po: Updated Turkish translation to pass msgfmt -cv. 2008-01-17 Gabor Kelemen * hu.po: Translation updated 2008-01-16 Sunil Mohan Adapa * te.po: Updated Telugu translation done by Krishna Babu K . 2008-01-15 Luca Ferretti * it.po: Updated Italian translation. 2008-01-15 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-01-15 Daniel Nylander * sv.po: Updated Swedish translation. 2008-01-14 Jorge Gonzalez * es.po: Updated Spanish translation === nemo 2.21.5 === 2008-01-14 Alexander Larsson * POTFILES.in: Add nemo-autorun.c 2008-01-14 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2008-01-14 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-01-11 Changwoo Ryu * ko.po: Updated Korean translation by Namhyung Kim. 2008-01-10 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2008-01-10 Luca Ferretti * it.po: Updated Italian translation. 2008-01-09 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-01-09 Alexander Larsson * POTFILES.skip: Add the removed connect to server files to skip instead === nemo 2.21.2 === 2008-01-07 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2008-01-06 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-01-05 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-01-04 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-03 Daniel Nylander * sv.po: Updated Swedish translation. 2007-12-31 Yannig Marchegay * oc.po: Updated Occitan translation. 2007-12-26 Seán de Búrca * ga.po: Updated Irish translation. * POTFILES.in: Add missing files. 2007-12-26 Djihed Afifi * ar.po: Updated Arabic Translation by Djihed Afifi. 2007-12-24 Djihed Afifi * ar.po: Updated Arabic Translation by Abou Manal. 2007-12-22 Seán de Búrca * ga.po: Updated Irish translation. === nemo 2.20.1 === 2007-12-20 Alexander Larsson * POTFILES.in: Remove removed files 2007-12-17 Daniel Nylander * sv.po: Updated Swedish translation. 2007-12-16 Jorge Gonzalez * es.po: Updated Spanish translation 2007-12-11 Jorge Gonzalez * es.po: Updated Spanish translation 2007-12-11 Rahul Balerao * mr.po: Added Marathi translations given by Sandeep Shedmake * LINGUAS: Added an entry for mr. 2007-12-11 Kostas Papadimas * el.po: Updated Greek translation 2007-12-10 Matej UrbanÄiÄ * sl.po: Updated Slovenian Translation. 2007-12-09 Jorge Gonzalez * es.po: Updated Spanish translation 2007-12-08 Leonardo Ferreira Fontenelle * pt_BR.po: Translation of "delete" fixed by Rodrigo Flores. 2007-11-27 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-12-06 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-12-04 Andre Klapper * de.po: Updated German translation. 2007-12-03 Andre Klapper * de.po: Updated German translation. 2007-12-03 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2007-12-01 Jorge Gonzalez * es.po: Updated Spanish translation 2007-12-01 UrbanÄiÄ Matej * sl.po: Updated Slovenian translation. 2007-11-30 Andre Klapper * POTFILES.in: Update list of files. 2007-11-27 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-11-25 Nickolay V. Shmyrev * ru.po: Updated Russian translation by Vasiliy Faronov 2007-11-21 Gil Forcada * ca.po: Updated Catalan translation by David Planella. 2007-11-15 Priit Laes * et.po: Translation updated by Ivar Smolin. 2007-11-12 Matej UrbanÄiÄ * sl.po: Updated Slovenian translation. 2007-11-07 Daniel Nylander * sv.po: Updated Swedish translation. 2007-11-06 Jorge Gonzalez * es.po: Updated Spanish translation 2007-11-06 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-10-31 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-10-29 Gabor Kelemen * hu.po: Translation updated 2007-10-28 Mohammad DAMT * id.po: Updated Indonesian translation by Huda Toriq 2007-10-27 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-10-23 Djihed Afifi * ar.po: Updated Arabic Translation by Sohaib Afifi. 2007-10-21 Djihed Afifi * ar.po: Updated Arabic Translation by Sohaib Afifi. 2007-10-19 Matej UrbanÄiÄ * sl.po: Updated Slovenian translation. 2007-10-15 Yair Hershkovitz * he.po: Updated Hebrew translation. 2007-10-06 Jovan Naumovski * mk.po: Minor fixes in Macedonian translation. 2007-10-04 Danishka Navin * si.po: Updated Sinhala translation by Danishka Navin. 2007-10-02 Thierry Randrianiriana * mg.po: Updated Malagasy translation. 2007-09-22 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-09-19 Danilo Å egan * sr.po, sr@Latn.po: Minor updates. === nemo 2.20.0 === 2007-09-17 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-09-17 Djihed Afifi * ar.po: Updated Arabic Translation by Sohaib Afifi. 2007-09-17 Amitakhya Phukan * LINGUAS: Added as to LINGUAS. * as.po: Added and updated assamese translations. 2007-09-16 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2007-09-16 Daniel Nylander * sv.po: Updated Swedish translation. 2007-09-16 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2007-09-15 Nickolay V. Shmyrev * ru.po: Updated Russian translation. 2007-09-15 Kostas Papadimas * el.po: Updated Greek Translation. 2007-09-15 Mugurel Tudor * ro.po: Updated Romanian translation. 2007-09-15 Andre Klapper * sk.po: Updated Slovak translation on behalf of Peter Tuharsky . 2007-09-15 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2007-09-14 Takeshi AIHANA * ja.po: Translation improved. 2007-09-13 Djihed Afifi * ar.po: Updated Arabic Translation by Sohaib Afifi. 2007-09-13 Pramod Raghavendra * kn.po: Updated Kannada translation. * LINGUAS: Added Kannada (kn) to the list of languages. 2007-09-12 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2007-09-10 Danilo Å egan * sr.po, sr@Latn.po: Updated Serbian translation. 2007-09-10 Ani Peter * ml.po: Updated Malayalam Translation 2007-09-08 Duarte Loreto * pt.po: Updated Portuguese translation. 2007-09-07 Gabor Kelemen * hu.po: Translation updated. 2007-09-07 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-09-03 Andre Klapper * de.po: fixing a typo. 2007-09-03 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2007-09-03 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-09-02 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-08-29 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan === nemo 2.19.91 === 2007-08-26 Gabor Kelemen * hu.po: Translation updated. 2007-08-24 Kenneth Nielsen * da.po: Updated Danish translation 2007-08-23 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-08-20 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation by Vladimir Melo . 2007-08-20 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-08-20 Daniel Nylander * sv.po: Updated Swedish translation. 2007-08-20 Luca Ferretti * it.po: Updated Italian translation. 2007-08-16 Priit Laes * et.po: Estonian translation updates by Ivar Smolin 2007-08-17 Stéphane Raimbault * fr.po: Updated French translation. 2007-08-16 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-08-16 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-08-16 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-08-15 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2007-08-15 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-08-15 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-08-15 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-08-15 Hendrik Richter * de.po: Updated German translation. 2007-08-15 Hendrik Richter * de.po: intltool-update de 2007-08-15 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2007-08-15 Daniel Nylander * sv.po: Updated Swedish translation. 2007-08-15 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-08-14 Jorge Gonzalez * es.po: Updated Spanish translation 2007-08-13 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-08-13 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-08-12 Hendrik Richter * de.po: Updated German translation. 2007-08-12 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-08-09 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-08-09 Kjartan Maraas * nb.po: Updated translation from Espen Stefansen. 2007-08-08 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-08-08 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2007-08-08 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-08-07 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2007-08-06 Daniel Nylander * sv.po: Updated Swedish translation. 2007-08-05 Leonardo Ferreira Fontenelle * pt_BR.po: s/_Conteúdo/S_umário; see bug #461308. 2007-08-05 Inaki Laranaga Murgoitio * eu.po: Updated Basque translation. 2007-08-05 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated and reviewed by Og Maciel and me. 2007-08-05 Jorge Gonzalez * es.po: Updated Spanish translation 2007-08-04 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-08-04 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-08-03 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-08-03 Ani Peter * ml.po: Updated Malayalam Translation 2007-08-02 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-07-30 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-07-30 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-07-26 Funda Wang * zh_CN.po: Updated Simplified Chinese translation 2007-07-25 Daniel Nylander * sv.po: Updated Swedish translation. 2007-07-25 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-07-24 Jorge Gonzalez * es.po: Updated Spanish translation 2007-07-24 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-07-24 Luca Ferretti * it.po: Updated Italian translation. 2007-07-21 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated by Og Maciel . 2007-07-21 Nguyá»…n Thái Ngá»c Duy * vi.po: Updated Vietnamese translation. 2007-07-21 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-07-18 Gabor Kelemen * hu.po: Translation updated - this time really :). 2007-07-18 Gabor Kelemen * hu.po: Translation updated. 2007-07-17 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2007-07-16 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-07-12 Changwoo Ryu * ko.po: Updated Korean translation by Eunju Kim. 2007-07-08 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-07-06 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. 2007-07-04 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. 2007-07-03 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-07-02 Nguyá»…n Thái Ngá»c Duy * vi.po: Updated Vietnamese translation. 2007-07-02 Nikos Charonitakis * el.po: Updated el.po to match pot file. 2007-07-02 Nikos Charonitakis * el.po: Updated Greek translation. 2007-07-02 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. >>>>>>> .r13263 2007-06-29 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-06-29 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-06-29 Changwoo Ryu * ko.po: Updated Korean translation. 2007-06-28 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-06-27 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-06-27 Thierry Randrianiriana * mg.po: Updated Malagasy translation. 2007-06-26 Guilherme de S. Pastore * ja.po: Fixed typo (Sitcky -> Sticky) in the Japanese translation, as reported by Kobayashi Noritada on the Debian BTS. 2007-06-23 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-06-23 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-06-22 I. Felix * si.po: Sinhala Translation updated by Danishka Navin * LINGUAS: Added Sinhala (si) to The List of Languages. 2007-06-21 Thierry Randrianiriana * mg.po: Updated Malagasy translation. 2007-06-19 Daniel Nylander * sv.po: Updated Swedish translation. 2007-06-19 Jorge Gonzalez * es.po: Updated Spanish translation 2007-06-18 Jorge Gonzalez * es.po: Updated Spanish translation 2007-06-18 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-06-13 Pema Geyleg * dz.po: Updated dzongkha translation 2007-06-13 Yair Hershkovitz * he.po: Updated Hebrew translation. 2007-06-10 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-06-06 Subhransu Behera * or.po: Updated Oriya Translation. 2007-06-05 Subhransu Behera * or.po: Updated Oriya Translation. 2007-06-02 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2007-05-31 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-05-29 Hendrik Richter * de.po: Updated German translation, by Daniel Schindler 2007-05-28 Ihar Hrachyshka * be@latin.po: Added Belarusian Latin translation by Ales Navicki. 2007-05-18 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-05-18 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-05-15 David Lodge * en_GB.po: Updated British English translation 2007-05-14 Daniel Nylander * sv.po: Updated Swedish translation. === nemo 2.19.2 === 2007-05-12 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2007-05-10 Jorge Gonzalez * es.po: Updated Spanish translation 2007-05-08 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-05-04 Jorge Gonzalez * es.po: Updated Spanish translation 2007-05-03 Daniel Nylander * sv.po: Updated Swedish translation. 2007-05-2 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2007-04-23 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-04-23 David Lodge * en_GB.po: Updated British English translation 2007-04-22 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2007-04-22 Jorge Gonzalez * es.po: Updated Spanish translation. 2007-04-21 Daniel Nylander * sv.po: Updated Swedish translation. 2007-04-15 Christophe Merlet * oc.po: Added Occitan translation from Yannig MARCHEGAY (Kokoyaya) . * LINGUAS: Added "oc". 2007-04-14 Djihed Afifi * ar.po: Updated Arabic Translation by Youssef Chahibi. 2007-04-13 Daniel Nylander * sv.po: Updated Swedish translation. 2007-04-11 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-04-10 Daniel Nylander * sv.po: Updated Swedish translation. 2007-04-08 Leonardo Ferreira Fontenelle * pt_BR.po: Fixes in Brazilian Portuguese translation. Originally sent to branch gnome-2-18. 2007-04-04 Daniel Nylander * sv.po: Updated Swedish translation. 2007-04-02 Jakub Friedl * cs.po: Updated the Czech translation. 2007-03-19 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation from Espen Stefansen. 2007-03-18 Daniel Nylander * sv.po: Updated Swedish translation. 2007-03-17 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-03-17 Stéphane Raimbault * fr.po: Updated French translation. 2007-03-17 Leonardo Ferreira Fontenelle * pt_BR.po: Fix and update in Brazilian Portuguese translation. 2007-03-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-03-16 Duarte Loreto * pt.po: Updated Portuguese translation. 2007-03-16 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. 2007-03-16 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-03-15 Ankit Patel * gu.po: Updated Gujarati Translation. === nemo 2.18.0 === 2007-03-14 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. 2007-03-11 Gabor Kelemen * hu.po: Translation updated. 2007-03-08 Jakub Friedl * cs.po: Updated Czech translation. 2007-03-06 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-03-05 Goran Rakić * sr.po, sr@Latn.po: Updated Serbian translation. 2007-03-05 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2007-03-04 Erdal Ronahi * ku.po: Updated Kurdish translation 2007-03-04 Thierry Randrianiriana * mg.po: Updated Malagasy translation. 2007-03-04 Pema Geyleg * dz.po: Updated Dzongkha Translation. 2007-03-04 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2007-03-03 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2007-03-03 Guillaume Savaton * eo.po: Added Esperanto translation. 2007-02-28 Daniel Nylander * sv.po: Updated Swedish translation. 2007-02-27 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-02-27 Hendrik Richter * de.po: Updated German translation. 2007-02-27 Jakub Friedl * cs.po: Updated Czech translation. 2007-02-26 Stéphane Raimbault * fr.po: Fixed French translation by Christophe Bliard and Stéphane Raimbault. === nemo 2.17.92 === 2007-02-25 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-02-24 Nguyá»…n Thái Ngá»c Duy * vi.po: Updated Vietnamese translation. 2007-02-23 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-02-22 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-02-22 Abel Cheung * zh_CN.po: Updated simplified Chinese translation on behalf of Funda Wang. 2007-02-21 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2007-02-21 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-02-20 Leonid Kanter * ru.po: Updated Russian translation 2007-02-18 Ole Laursen * da.po: Fixed a problem reported by Armijn Hemel, also updated the translation with the few new strings. 2007-02-18 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-02-17 Leonardo Ferreira Fontenelle * pt_BR.po: Updated Brazilian Portuguese translation. 2007-02-16 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-02-15 Duarte Loreto * pt.po: Updated Portuguese translation. 2007-02-12 Gabor Kelemen * hu.po: Translation updated. 2007-02-12 Ilkka Tuohela * fi.po: Updated Finnish translation. === nemo 2.17.91 === 2007-02-11 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2007-02-11 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2007-02-11 Stéphane Raimbault * fr.po: Updated French translation by Jonathan Ernst. 2007-02-09 David Lodge * en_GB.po: Updated English (British) translation 2007-02-8 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2007-02-08 Luca Ferretti * it.po: Updated Italian translation. 2007-02-07 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-02-07 Ihar Hrachyshka * be.po: Updated Belarusian translation. 2007-02-07 Daniel Nylander * sv.po: Updated Swedish translation. 2007-02-07 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-02-06 Stéphane Raimbault * fr.po: Updated French translation by Jonathan Ernst. 2007-02-05 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-02-04 Gabor Kelemen * hu.po: Translation updated. 2007-02-04 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-02-04 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2007-02-03 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-01-31 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-01-31 Ihar Hrachyshka * be.po: Updated Belarusian translation. 2007-01-31 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-01-27 Stéphane Raimbault * fr.po: Updated French translation by Robert-André Mauchin. 2007-01-26 Luca Ferretti * it.po: Updated Italian translation. 2007-01-24 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2007-01-23 David Lodge * en_GB.po: Updated English (British) translation 2007-01-23 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-01-23 Daniel Nylander * sv.po: Updated Swedish translation. 2007-01-15 Yair Hershkovitz * he.po: Updated Hebrew translation. 2007-01-13 Ole Laursen * da.po: Updated Danish translation. 2007-01-10 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-01-07 Priit Laes * et.po: Updated Estonian Translation. 2007-01-06 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2007-01-03 Jakub Friedl * cs.po: Updated Czech Translation. 2007-01-03 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2007-01-01 David Lodge * en_GB.po: Updated English (British) translation 2007-01-01 Daniel Nylander * sv.po: Updated Swedish translation. 2006-12-29 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-12-29 Kjartan Maraas * POTFILES.skip: Add some files. * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-12-29 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-12-27 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-26 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-26 Luca Ferretti * it.po: Updated Italian translation. 2006-12-24 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-24 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2006-12-23 Raivis Dejus * lv.po: Updated Latvian Translation. 2006-12-21 Ales Nyakhaychyk * be.po: Updated Belarusian Translation by Ihar Hrachyshka. 2006-12-20 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-12-20 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-12-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. === nemo 2.17.1 === 2006-12-18 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-15 Luca Ferretti * it.po: Updated Italian translation. 2006-12-15 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-12-14 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-12-13 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-12-11 Lucas Rocha * pt_BR.po: Updated Brazilian Portuguese translation by Leonardo Ferreira Fontenelle 2006-12-11 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-12-07 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-12-04 Luca Ferretti * it.po: Updated Italian translation. 2006-11-28 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-11-28 Daniel Nylander * sv.po: Updated Swedish translation. 2006-11-24 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-11-24 Yair Hershkovitz * he.po: Updated Hebrew translation. 2006-11-24 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-11-24 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-11-23 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-11-23 Yair Hershkovitz * he.po: Updated Hebrew translation. === nemo 2.16.3 === 2006-11-19 Wouter Bolsterlee * pl.po: Translation updated by wadim dziedzic. 2006-11-19 Matic Zgur * sl.po: Updated Slovenian translation. 2006-11-18 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-11-16 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-11-10 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-11-09 Hendrik Richter * de.po: Updated German translation, fix #372962. 2006-11-9 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-11-08 Priit Laes * et.po: Translation updated by Ivar Smolin. === nemo 2.16.2 === 2006-11-07 Alexander Larsson * POTFILES.in: Update for desktop.in.in change. 2006-11-06 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-11-6 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-11-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-11-03 Hendrik Richter * de.po: Updated German translation, fix #369439. 2006-11-03 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-11-01 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-30 Djihed Afifi * ar.po Updated Arabic Translation. 2006-10-30 Satoru SATOH * ja.po: Fixed wrong plural form entries. 2006-10-23 Priit Laes * et.po: Translation updated. 2006-10-23 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-20 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-10-19 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-16 Luca Ferretti * it.po: Updated Italian translation. 2006-10-15 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-10-15 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-15 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-15 Matic Zgur * sl.po: Updated Slovenian translation. 2006-10-12 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-11 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-09 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-10-08 Hendrik Richter * de.po: Updated German translation, fix #331278. 2006-10-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-04 Priit Laes * et.po: Translation updated by Ivar Smolin. === nemo 2.16.1 === 2006-10-02 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-28 Priit Laes * et.po: Translation updated. 2006-09-27 Luca Ferretti * it.po: Updated Italian translation. 2006-09-26 Jordi Mallach * ca.po: Updated Catalan translation. 2006-09-25 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-20 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-16 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-15 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2006-09-12 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-09-09 David Lodge * en_GB.po: Updated British English translation. 2006-09-08 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-06 Simos Xenitellis * el.po: Fixed typo, noted by Konstantinos Togias. 2006-09-05 Lucas Rocha * pt_BR.po: Updated Brazilian Portuguese translation by Evandro Fernandes Giovanini . 2006-09-04 Abel Cheung * zh_HK.po: Updated Chinese (Hong Kong) translation. * zh_TW.po: Updated Chinese (Taiwan) translation. 2006-09-04 Runa Bhattacharjee * bn_IN.po: Fixed Fuzzies and changed accelerator keys to English. 2006-09-04 Kostas Papadimas * el.po: Updated Greek translation. 2006-09-04 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2006-09-04 I. Felix * ta.po: Updated Tamil Translation. 2006-09-01 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2006-09-01 Ani Peter * ml.po: Updated Malayalam translation 2006-09-01 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-31 Duarte Loreto * pt.po: Updated Portuguese translation. 2006-08-31 Ani Peter * ml.po: Updated Malayalam translation 2006-08-31 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-08-31 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-30 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-30 Subhransu Behera * or.po: Updated Oriya Translation. 2006-08-30 Gabor Kelemen * hu.po: Translation updated. 2006-08-29 Subhransu Behera * or.po: Updated Oriya Translation. 2006-08-28 Subhransu Behera * or.po: Updated Oriya Translation. 2006-08-28 Subhransu Behera * or.po: Updated Oriya Translation. 2006-08-28 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-27 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2006-08-27 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-08-26 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-08-26 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-25 Hendrik Richter * de.po: Updated German translation. 2006-08-25 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-08-24 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-23 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-08-22 Jordi Mas * ca.po: Updates Catalan translation === nemo 2.15.92 === 2006-08-20 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2006-08-19 Matic Žgur * sl.po: Updated Slovenian translation. 2006-08-17 Jordi Mas * ca.po: Fixes small mistakes in Catalan translation 2006-08-17 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-08-16 Leonid Kanter * ru.po: Updated Russian translation 2006-08-16 Daniel Nylander * sv.po: Updated Swedish translation. 2006-08-16 Gabor Kelemen * hu.po: Translation updated by Mate ORY. 2006-08-15 Hendrik Richter * de.po: Updated German translation. 2006-08-15 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-15 Satoru SATOH * ja.po: Updated Japanese translation. 2006-08-12 Changwoo Ryu * ko.po: Updated Korean translation. 2006-08-12 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-08-10 Guntupalli Karunakar * dz.po: Updated Dzongkha translation by Dzongkhalinux team, DIT 2006-08-09 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-08-09 Raivis Dejus * lv.po: Updated Latvian translation. 2006-08-08 Baris Cicek * tr.po: Updated Turkish Translation === nemo 2.15.91 === 2006-08-07 Inaki Larranaga * eu.po: Updated Basque translation. 2006-08-06 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-08-06 Bastien Nocera * en_GB.po: Update British English translation, and made sure Trash wasn't left untranslated (Closes: #325088) 2006-08-05 Alexander Shopov * bg.po: Updated Bulgarian translation with bugfixes prompted by Zlatko Popov 2006-08-03 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-03 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-08-02 Ahmad Riza H Nst * id.po: updated. 2006-08-01 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-01 Subhransu Behera * or.po: Updated Oriya Translation. 2006-08-01 Subhransu Behera * or.po: Added New File for Oriya Translation. * LINGUAS: Added Oriya (or) to The List of Languages. 2006-07-31 Hendrik Richter * de.po: Updated German translation. 2006-07-29 Christophe Merlet * fr.po: Updated French translation. 2006-07-29 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-07-28 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-07-27 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-07-27 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2006-07-26 Jakub Friedl * cs.po: Updated Czech translation. 2006-07-25 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-07-25 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-07-23 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2006-07-23 Changwoo Ryu * ko.po: Updated Korean translation. 2006-07-22 Luca Ferretti * it.po: Update Italian translation. 2006-07-22 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-07-21 Kostas Papadimas * el.po: Updated Greek translation 2006-07-18 Guntupalli Karunakar * dz.po: Updated Dzongkha translation by Dzongkhalinux team, DIT 2006-07-17 Hendrik Richter * de.po: Updated German translation. 2006-07-16 Daniel Nylander * sv.po: Updated Swedish translation. 2006-07-14 Priit Laes * et.po: Translation updated. 2006-07-13 Nickolay V. Shmyrev * ru.po: Updated Russian translation 2006-07-09 Jovan Naumovski * mk.po: Updated Macedonian translation 2006-07-08 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2006-07-09 Changwoo Ryu * ko.po: Updated Korean translation. 2006-07-08 Inaki Larranaga * eu.po: Updated Basque translation. 2006-07-06 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-07-03 Runa Bhattacharjee * bn_IN.po: Added Bengali India Translation * LINGUAS: Added Bengali India (bn_IN) to the list of languages. 2006-07-03 Benoît Dejean * fr.po: Updated French translation. 2006-07-01 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-06-26 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-06-26 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-06-25 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-06-22 I. Felix * ta.po: Updated Tamil translation. 2006-06-22 Jakub Friedl * cs.po: Updated Czech translation. 2006-06-22 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-06-22 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-22 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-21 Nickolay V. Shmyrev * ru.po: Updated Russian translation. 2006-06-20 Raivis Dejus * lv.po: Updated Latvian translation. 2006-06-19 Jakub Friedl * cs.po: Updated Czech translation. 2006-06-19 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-18 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-06-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-17 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-06-15 Hendrik Richter * de.po: Updated German translation. === nemo 2.15.2 === 2006-06-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-10 Josep Puigdemont Casamajó * ca.po: Updated Catalan translation. 2006-05-30 Pema Geyleg * dz.po: Updated Dzongkha translation. 2006-05-29 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-05-28 Pema Geyleg * dz.po: updated Dzongkha translation. 2006-05-26 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-05-25 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-05-24 Daniel Nylander * sv.po: Updated Swedish translation. 2006-05-24 Inaki Larranaga * eu.po: Updated Basque translation. 2006-05-23 Jakub Friedl * cs.po: Updated Czech translation. 2006-05-19 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-18 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-05-18 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-05-16 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-13 Jérémy Ar Floc'h * br.po: Updated Breton translation. 2006-05-07 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-06 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-05-05 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-05-02 Øivind Hoel * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-05-02 Øivind Hoel * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-05-02 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-05-02 Alexander Larsson * LINGUAS: * mg.po: Add malagasy translation. from Thierry Randrianiriana 2006-05-02 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-05-02 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-30 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-04-29 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-04-28 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-04-28 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-27 Lukas Novotny * cs.po: Updated Czech translation. 2006-04-27 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-23 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2006-04-22 Yair Hershkovitz * he.po: Updated Hebrew translation. 2006-04-20 Inaki Larranaga * eu.po: Updated Basque translation. 2006-04-18 Vladimer Sichinava * ka.po: Updated Georgian translation. 2006-04-18 Kjartan Maraas * LINGUAS: Remove obsolete entry for no_NO * no.po: And the translation. 2006-04-16 Ã…smund Skjæveland * nn.po: Updated Norwegian Nynorsk translation. 2006-04-16 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-04-15 Jérémy Ar Floc'h * br.po: Added Breton translation. * LINGUAS: Added Breton (br). 2006-04-14 Miloslav Trmac * cs.po: Updated Czech translation by Lukas Novotny. 2006-04-14 Ã…smund Skjæveland * nn.po: Updated Norwegian Nynorsk translation. 2006-04-14 Yair Hershkovitz * he.po: Updated Hebrew translation. 2006-04-12 Hendrik Richter * de.po: Updated German translation. 2006-04-12 Takeshi AIHANA * ja.po: Updated Japanese translation. 2006-04-10 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2006-04-08 Nikos Charonitakis * el.po: Updated Greek translation. 2006-04-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-04-03 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-04-02 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same. 2006-04-02 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-04-01 Yair Hershkovitz * he.po: Updated Hebrew translation. 2006-03-30 Lukas Novotny * cs.po: Updated Czech translation. 2006-03-30 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-03-28 Rhys Jones * cy.po: Updated Welsh translation. 2006-03-28 Ole Laursen * da.po: Fixed a few strings in Danish translation. 2006-03-25 Nikos Charonitakis * el.po: Updated Greek translation. 2006-03-21 Kostas Papadimas * el.po: Updated Greek Translation. 2006-03-21 Gabor Kelemen * hu.po: Hungarian translation updated by Mate ORY. 2006-03-20 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-03-20 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2006-03-20 Laurent Dhima * sq.po: Updated Albanian translation. 2006-03-20 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-03-20 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-03-19 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-03-19 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-03-19 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-19 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2006-03-19 Daniel Nylander * sv.po: Updated Swedish Translation. 2006-03-19 Kostas Papadimas * el.po: Updated Greek Translation. 2006-03-18 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-03-18 Guilherme de S. Pastore * pt_BR.po: Updated Brazilian Portuguese translation. 2006-03-18 Luca Ferretti * it.po: Updated Italian translation. 2006-03-18 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-03-17 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-17 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-17 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-17 Vladimer Sichinava * ka.po: Updated Georgian translation. 2006-03-14 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-03-13 Benoît Dejean * fr.po: Updated French translation. === nemo 2.14.0 === 2006-03-13 Runa Bhattacharjee * bn.po: Updated Bengali Translation. 2006-03-13 Lucas Rocha * pt_BR.po: Updated Brazilian Portuguese translation. 2006-03-12 Miloslav Trmac * cs.po: Updated Czech translation by Petr TomeÅ¡. 2006-03-11 Guilherme de S. Pastore * pt_BR.po: Updated Brazilian Portuguese translation. 2006-03-08 Luca Ferretti * it.po: Updated Italian translation. 2006-03-08 Kjartan Maraas * nn.po: Updated Norwegian nynorsk translation. 2006-03-06 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-03-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-06 Daniel Nylander * sv.po: Updated Swedish translation 2006-03-05 Mugurel Tudor * ro.po: Updated Romanian translation 2006-03-04 Duarte Loreto * pt.po: Updated Portuguese translation. 2006-03-03 Maxim Dziumanenko * uk.po: Updated Ukrainian translation. 2006-02-03 Øivind Hoel * nb.po: Updated Norwegian bokmÃ¥l translation. 2006-03-02 Hendrik Richter * de.po: Updated German translation. 2006-03-02 Hendrik Richter * de.po: Updated German translation. 2006-03-02 Stanislav Brabec * km.po: Added initial Khmer translation from Keo Sophon and Leang Chumsoben based on SuSE gnome-patch-translation. 2006-02-28 Miloslav Trmac * cs.po: Updated Czech translation by Petr TomeÅ¡. 2006-02-27 Lasse Bang Mikkelsen * da.po: Updated Danish translation. === nemo 2.13.92 === 2006-02-27 Inaki Larranaga * eu.po: Fixed some typos. 2006-02-26 Lasse Bang Mikkelsen * da.po: Updated Danish translation. 2006-02-26 Ales Nyakhaychyk * be.po: Updated Belarusian translation by Ihar Hrachyshka 2006-02-25 Chao-Hsiung Liao * zh_TW.po: Updated Traditional Chinese translation(Taiwan). * zh_HK.po: Added Traditional Chinese translation(Hong Kong). 2006-02-23 Leonid Kanter * ru.po: Updated Russian translation 2006-02-23 Clytie Siddall * ka.po: Added Georgian translation by Alexander Didebulidze and Vladimer Sichinava . 2006-02-22 Inaki Larranaga * eu.po: Updated Basque translation. 2006-02-20 Theppitak Karoonboonyanan * th.po: Adjusted Thai translation. 2006-02-20 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2006-02-19 Takeshi AIHANA * ja.po: Updated Japanese translation. 2006-02-17 Kostas Papadimas * el.po: Updated Greek Translation. 2006-02-16 Rhys Jones * cy.po: Updated Welsh translation. 2006-02-16 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-02-16 Hendrik Richter * de.po: Updated German translation. 2006-02-15 Gabor Kelemen * hu.po: Hungarian translation updated by Mate ORY. 2006-02-13 Jakub Friedl * cs.po: Updated Czech translation === nemo 2.13.91 === 2006-02-11 Luca Ferretti * ut.po: Updated Italian translation 2006-02-10 Priit Laes * et.po: Translation updated. 2006-02-06 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2006-02-06 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-02-04 Laurent Dhima * sq.po: Updated Albanian translation. 2006-02-03 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same. 2002-02-02 Leonid Kanter * ru.po: fixed Russian translation 2006-02-02 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-02-01 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-02-01 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-02-01 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-02-01 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-01-31 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2006-01-31 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2006-01-31 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-01-31 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-01-31 Slobodan D. Sredojevic * sr.po, sr@Latn.po: Updated Serbian translation 2006-01-30 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-30 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-01-29 Erdal Ronahi * ku.po: Updated Kurdish translations. 2006-01-29 Gabor Kelemen * hu.po: Hungarian translation updated. 2006-01-29 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-01-29 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-01-29 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-01-26 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2006-01-25 Nickolay V. Shmyrev * ru.po: Update Russian translation by Artem Tuchinsky . 2006-01-23 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-01-22 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same. 2006-01-22 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-01-21 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-01-21 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2006-01-19 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-19 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-01-19 Satoru SATOH * ja.po: Updated Japanese translation 2006-01-18 Luca Ferretti * it.po: Updated Italian translation 2006-01-18 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-01-18 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-01-17 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2006-01-16 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-01-16 Adam Weinberger * en_CA.po: Updated Canadian English translation. === nemo 2.13.4 === 2006-01-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-01-14 Gabor Kelemen * hu.po: Hungarian translation updated. 2006-01-14 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-01-14 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-01-12 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-11 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2006-01-09 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-08 Nikos Charonitakis * el.po: Updated Greek translation. 2006-01-06 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation * no.po: Updated Norwegian bokmÃ¥l translation 2006-01-03 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2006-01-02 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2006-01-02 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-01-02 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same. 2005-12-31 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-30 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-12-28 Marcel Telka * sk.po: Updated Slovak translation. 2005-12-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2005-12-25 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-21 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-12-21 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-12-20 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-12-21 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-20 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-12-20 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-20 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-12-19 Alexander Larsson * POTFILES.in: Add missing files. 2005-12-19 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-12-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-12-17 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-12-17 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-16 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-12-15 Ilkka Tuohela * fi.po: Updated Finnish translation. 2005-12-14 Marcel Telka * sk.po: Updated Slovak translation. 2005-12-14 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-12-14 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-12-14 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-12-13 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-12-13 Theppitak Karoonboonyanan * th.po: Updated Thai translation. === nemo 2.13.3 === 2005-12-12 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-12-12 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-11 Miloslav Trmac * cs.po: Updated Czech translation. 2005-12-11 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-12-11 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-11 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same 2005-12-10 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-12-10 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-09 Ignacio Casal Quinteiro * gl.po: Updated Galician Translations. 2005-12-09 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-06 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-12-06 Ales Nyakhaychyk * be.po: Updated Belarusian translation by Vital Khilko. 2005-12-04 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-12-03 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-12-03 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same 2005-12-02 Miloslav Trmac * cs.po: Updated Czech translation. 2005-11-25 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-11-25 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-11-25 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-11-24 Marcel Telka * sk.po: Updated Slovak translation. 2005-11-24 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-11-21 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-11-21 Francisco Javier F. Serrador * es.po: #321973 Bug fix. 2005-11-20 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-11-19 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-11-17 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-11-17 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-11-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-11-17 Priit Laes * et.po: Translation updated. 2005-11-15 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-11-14 Marcel Telka * sk.po: Updated Slovak translation. 2005-11-14 Francisco Javier F. Serrador * es.po: Updated Spanish translation === nemo 2.13.2 === 2005-11-14 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-11-14 Ales Nyakhaychyk * be.po: Updated Belarusian translation by Vital Khilko. 2005-11-14 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-11-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-11-03 Miloslav Trmac * cs.po: Updated Czech translation. 2005-10-30 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-10-28 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-10-26 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-10-25 Marcel Telka * sk.po: Updated Slovak translation. === nemo 2.13.1 === 2005-10-23 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-21 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2005-10-15 Vincent van Adrighem * nl.po: Translation updated. 2005-10-13 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-10-13 Funda Wang * zh_CN.po: Corrected a typo of Simplified Chinese translation. 2005-10-05 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-10-04 Priit Laes * et.po: Translation updated by Ivar Smolin. === nemo 2.12.1 === 2005-09-29 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-09-25 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2005-09-24 Erdal Ronahi * ku.po: Updated Kurdish translation. 2005-09-18 Christian Rose * sv.po: Updated Swedish translation. 2005-09-16 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-09-14 Runa Bhattacharjee * bn.po: Updated Bengali (bn) Translation by Progga 2005-09-10 Erdal Ronahi * ku.po: Added Kurdish translation 2005-09-07 Inaki Larranaga * eu.po: Updated Basque translation. === nemo 2.12.0 === 2005-09-04 Hendrik Richter * de.po: Updated German translation. 2005-09-03 Danilo Å egan * sr.po, sr@Latn.po: Updated. 2005-09-02 Choe Hwanjin * ko.po: Updated Korean translation by Young-Ho Cha. 2005-09-01 Baris Cicek * tr.po: Updated Turkish Translation 2005-09-01 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-09-01 Francisco Javier F. Serrador * es.po: UPdated Spanish translation. 2005-08-31 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2005-08-31 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-08-31 Hendrik Richter * de.po: Updated German translation. 2005-08-30 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-08-30 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2005-08-28 Mohammad DAMT * id.po: Updated Indonesian translation. 2005-08-28 Christophe Merlet * fr.po: Updated French translation. 2005-08-27 Josep Puigdemont * ca.po: Updated Catalan translation by Jordi Mallach 2005-08-27 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-08-27 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2005-08-24 Chao-Hsiung Liao * zh_TW.po: Updated Traditional Chinese translation. 2005-08-24 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-08-22 Mugurel Tudor * ro.po: Updated Romanian translation 2005-08-22 Changwoo Ryu * ko.po: Updated Korean translation. 2005-08-20 Maxim Dziumanenko * uk.po: Updated Ukrainian translataion. 2005-08-20 Roozbeh Pournader * fa.po: Upldated Persian translation by Elnaz Sarbar and myself. 2005-08-19 Rhys Jones * cy.po: Updated Welsh translation. 2005-08-19 Jens Seidel * de.po: Various typo fixes. 2005-08-19 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-08-17 Mugurel Tudor * ro.po: Updated Romanian translation 2005-08-17 Laurent Dhima * sq.po: Updated Albanian translation. 2005-08-16 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-08-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-08-14 Terance Sola * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same. 2005-08-11 Duarte Loreto * pt.po: Updated Portuguese translation. 2005-08-10 Sigurd Gartmann * nn.po: Updated Norwegian Nynorsk translation. 2005-08-09 Leonid Kanter * ru.po: Updated Russian translation 2005-08-09 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-08-08 Sunil Mohan Adapa * te.po: Updated Telugu translation done by M.A.Kaleem Shyam Kalakoti 2005-08-07 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-08-07 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2005-08-06 Mohammad DAMT * id.po: Updated Indonesian translation 2005-08-06 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2005-08-06 Kostas Papadimas * el.po Updated Greek Translation 2005-08-05 Miloslav Trmac * cs.po: Updated Czech translation. 2005-08-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-08-05 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2005-08-05 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-08-04 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-08-04 Sunil Mohan Adapa * te.po: Added Telugu translation done by Prajasakti Localisation Team 2005-08-04 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-08-04 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-08-04 Marcel Telka * sk.po: Updated Slovak translation. 2005-08-04 Ilkka Tuohela *fi.po: Updated Finnish translation. 2005-08-03 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same 2005-08-03 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-08-02 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-08-01 Vincent van Adrighem * nl.po: Translation updated. 2005-07-31 Ilkka Tuohela * fi.po: Bulk updates to Finnish translation for new gnome.fi website. 2005-07-31 Pawan Chitrakar * ne.po: Updated Nepali Translation 2005-07-30 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2005-07-29 Ilkka Tuohela * fi.po: Updated Finnish translation. 2005-07-28 Ilkka Tuohela * fi.po: Bulk change to some Finnish translations. 2005-07-26 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-07-24 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same 2005-07-23 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-07-23 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-07-21 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation by Justina KlingaitÄ— and me. 2005-07-21 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-07-21 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-07-18 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-18 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-07-18 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-07-17 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-07-17 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-07-16 Yair Hershkovitz *he.po: Updated Hebrew translation. 2005-07-16 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. * no.po: Same 2005-07-14 Miloslav Trmac * cs.po: Updated Czech translation. 2005-07-14 Priit Laes * et.po: Translation updated. 2005-07-13 Marcel Telka * sk.po: Updated Slovak translation. 2005-07-12 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-07-12 Marcel Telka * sk.po: Updated Slovak translation. 2005-07-12 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-07-11 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-07-11 Theppitak Karoonboonyanan * th.po: Updated Thai translation. === nemo 2.11.4 === 2005-07-10 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-10 Danilo Å egan * sr.po, sr@Latn.po: Updated Serbian translation. 2005-07-10 Miloslav Trmac * cs.po: Updated Czech translation. 2005-07-10 Yair Hershkovitz * he.po: Updated Hebrew translation. 2005-07-10 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-07-09 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-07-08 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-08 Alexander Larsson * POTFILES.in: Added src/nemo-pathbar.c 2005-07-08 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-07-07 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2005-07-06 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-06 Marcel Telka * sk.po: Updated Slovak translation. 2005-07-06 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-07-04 Hendrik Richter * de.po: Fixed German translation by Jens Seidel . 2005-07-04 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-07-04 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-07-03 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-03 Priit Laes * et.po: Translation updated. 2005-07-02 Takeshi AIHANA * ja.po: Updated Japanese translation. === nemo 2.11.3 === 2005-07-01 Alexander Larsson * POTFILES.in: Add places sidebar. 2005-07-01 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-06-30 Terance Sola * nb.po: Updated Norwegian bokml translation. * no.po: Same. 2005-06-27 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-06-27 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-06-27 Alexander Larsson * POTFILES.in: Add new files. 2005-06-26 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-06-24 Kjartan Maraas * nb.po: Updated Norwegian translation. * no.po: Same 2005-06-22 Abel Cheung * zh_TW.po: Fix language team reference. 2005-06-23 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-06-22 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-06-20 Alexander Larsson * POTFILES.in: Added fm-list-model.c 2005-06-17 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-06-14 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-06-12 Kjartan Maraas * nb.po: Update Norwegian bokml translation. * no.po: Same 2005-06-12 Priit Laes * et.po: Translation updated. 2005-06-12 Miloslav Trmac * cs.po: Updated Czech translation. 2005-06-12 Ignacio Casal Quinteiro * gl.po: Updated Galician translation. 2005-06-11 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-06-10 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2005-06-08 Adam Weinberger * en_CA.po: Updated Canadian English translation. === nemo 2.11.2 === 2005-06-07 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-06-07 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-06-07 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-06-06 Ignacio Casal Quinteiro * gl.po: Updated Galician translation from Jess Bravo lvarez. 2005-06-07 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-06-06 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-06-06 Priit Laes * et.po: Translation updated. 2005-06-05 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-06-03 Christian Neumair * POTFILES.in: * POTFILES.skip: Remove libbackground/applier.c from POTFILES.in. 2005-06-02 Pawan Chitrakar * ne.po: Updated Nepali Translation 2005-06-01 Priit Laes * et.po: Translation updated. 2005-06-01 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-05-31 Terance Sola * nb.po: Updated * no.po: Updated 2005-05-29 Miloslav Trmac * cs.po: Updated Czech translation. 2005-05-27 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-27 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-05-26 Rhys Jones * cy.po: Merged minor updates from gnome-2-10 branch. 2005-05-25 Kjartan Maraas * nb.po: Update * no.po: Update 2005-05-23 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-05-22 Miloslav Trmac * cs.po: Updated Czech translation. 2005-05-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-05-18 Takeshi AIHANA * ja.po: Updated Japanese translation. === nemo 2.11.1 === 2005-05-15 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-05-14 Hendrik Richter * de.po: Updated German translation. 2005-05-13 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2005-05-13 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2005-05-12 David Zeuthen * zh_TW.po: Revert default font to "Sans 10" * gu.po: Revert default font to "Sans 10" 2005-05-12 Miloslav Trmac * cs.po: Updated Czech translation. 2005-05-11 Rajesh Ranjan *hi.po Updated Hindi Translation 2005-05-11 Kostas Papadimas *el.po Updated Greek Translation 2005-05-09 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-04-30 Miloslav Trmac * cs.po: Updated Czech translation. 2005-04-29 Priit Laes * et.po: Translation updated by Sven Sapelson. 2005-04-28 Kostas Papadimas * el.po: Updated Greek translation 2005-04-24 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-04-22 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-04-19 David Lodge * en_GB.po: Updated British English translation. 2005-04-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-04-18 Gareth Owen * en_GB.po: Updated British English translation 2005-04-18 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-04-11 Vincent van Adrighem * nl.po: Translation updated by Maarten Grachten. 2005-04-09 Miloslav Trmac * cs.po: Updated Czech translation. 2005-04-05 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-03-31 Steve Murphy * rw.po: Added Kinyarwanda translation. 2005-03-30 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-03-30 Josep Puigdemont * ca.po: Updated Catalan translation. 2005-03-29 Adi Attar * xh.po: Updated Xhosa translation. 2005-03-28 Abel Cheung * zh_TW.po: Updated traditional Chinese translation from GNOME HK Team 2005-03-26 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-03-26 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-03-25 Josep Puigdemont * ca.po: Updated Catalan translation. 2005-03-22 Duarte Loreto * pt.po: Updated Portuguese translation. 2005-03-22 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-03-22 Laurent Dhima * sq.po: Updated Albanian translation. 2005-03-22 Christian Rose * POTFILES.in: Added missing file entry. * sv.po: Updated Swedish translation. 2005-03-21 Takeshi AIHANA * ja.po: Fixed wrong translations. 2005-03-17 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-03-16 Roozbeh Pournader * fa.po: Updated Persian translation by Behnam Pournader . 2005-03-14 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-03-12 Baris Cicek * tr.po: Updated Turkish Translation 2005-03-10 Adi Attar * xh.po: Added Xhosa translation. 2005-03-07 Theppitak Karoonboonyanan * th.po: Updated Thai translation by Supranee Thirawatthanasuk. 2005-03-07 Martin Willemoes Hansen * da.po: Updated Danish translation. === nemo 2.10.0 === 2005-03-07 Mugurel Tudor * ro.po: Updated Romanian translation 2005-03-04 Dafydd Harries * cy.po: Updated Welsh translation. 2005-03-04 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation by Gintautas Miliauskas. 2005-03-03 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-03-02 Danilo Å egan * sr.po, sr@Latn.po: Updated Serbian translation. 2005-03-01 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2005-03-01 Alexander Larsson * POTFILES.skip: * POTFILES.in: Move some old unused files to .skip for now === nemo 2.9.92 === 2005-03-01 Alexander Larsson * POTFILES.in: Remove old files 2005-03-01 Abel Cheung * zh_TW.po: Updated traditional Chinese translation from GNOME HK Team 2005-02-28 Kostas Papadimas * el.po: Updated Greek translation. 2005-02-27 Nikos Charonitakis * el.po: Updated Greek translation. 2005-02-15 Jordi Mallach * ca.po: Updated Catalan translation. 2005-02-25 Ankit Patel * gu.po: Updated Gujarati Translation. 2005-02-24 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2005-02-24 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2005-02-24 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-02-22 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-02-22 Martin Willemoes Hansen * da.po: Updated Danish translation. 2005-02-20 Kjartan Maraas * nb.po: Spellcheck a bit * no.po: same 2005-02-20 Christophe Merlet * fr.po: Updated French translation from Vincent Carriere . 2005-02-18 Pauli Virtanen * fi.po: Updated Finnish translation. 2005-02-18 Kostas Papadimas * el.po: Updated Greek translation. 2005-02-18 Duarte Loreto * pt.po: Updated Portuguese translation. 2005-02-18 Changwoo Ryu * ko.po: Updated Korean translation. 2005-02-17 Laurent Dhima * sq.po: Updated Albanian translation. 2005-02-16 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2005-02-15 Jordi Mallach * ca.po: Updated Catalan translation. 2005-02-15 Kjartan Maraas * nb.po: Fix typo. * no.po: Same 2005-02-14 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-02-14 Hendrik Richter * de.po: Updated German translation. 2005-02-14 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-02-12 Laszlo Dvornik * hu.po: Hungarian translation updated by Gabor Kelemen. 2005-02-12 Maxim Dziumanenko * uk.po: Updated Ukrainian translation. 2005-02-12 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-02-10 Priit Laes * et.po: Translation updated. 2005-02-10 Priit Laes * et.po: Translation updated by Ivar Smolin. === nemo 2.9.91 === 2005-02-10 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-02-09 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-02-08 Leonid Kanter * ru.po: Updated Russian translation 2005-02-08 Hendrik Richter * de.po: Updated German translation. 2005-02-08 Kjartan Maraas * nb.po: Update * no.po: Update 2005-02-07 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-02-07 David Lodge * en_GB.po: Updated British translation. 2005-02-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-02-06 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-02-06 Nikos Charonitakis * el.po: Updated Greek translation. 2005-02-06 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-02-06 Miloslav Trmac * cs.po: Updated Czech translation. 2005-02-06 Christian Rose * sv.po: Updated Swedish translation. 2005-02-06 Pauli Virtanen * fi.po: Updated Finnish translation. 2005-02-05 Kostas Papadimas * el.po: Updated Greek translation. 2005-02-04 Gil Osher * he.po: Updated Hebrew translation. 2005-02-03 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-02-03 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-02-02 Priit Laes * et.po: Translation updated by Ivar Smolin. 2005-02-02 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2005-02-01 Jordi Mallach * ca.po: Updated Catalan translation. 2005-02-01 Kjartan Maraas * nb.po: Update * no.po: Update 2005-02-01 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-02-01 Changwoo Ryu * ko.po: Updated Korean translation. 2005-01-31 Miloslav Trmac * cs.po: Updated Czech translation. 2005-01-31 Christian Rose * sv.po: Updated Swedish translation. 2005-01-31 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-01-30 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-01-29 Priit Laes * et.po: Translation updated. 2005-01-29 Miloslav Trmac * cs.po: Updated Czech translation. 2005-01-28 Kjartan Maraas * nb.po: Update 2005-01-26 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-26 Marcel Telka * sk.po: Updated Slovak translation. 2005-01-26 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-26 Leonid Kanter * ru.po: Updated Russian translation 2005-01-26 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-01-25 Francisco Javier Fernandez * es.po: Updated Spanish translation. 2005-01-25 Adam Weinberger * en_CA.po: Updated Canadian English translation. === nemo 2.9.90 === 2005-01-25 Hendrik Richter * de.po: Updated German translation. 2005-01-24 Duarte Loreto * pt.po: Updated Portuguese translation. 2005-01-24 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-24 Hendrik Richter * de.po: Updated German translation. 2005-01-23 Ch4ristian Rose * POTFILES.in: Sorted. * sv.po: Updated Swedish translation. 2005-01-23 Hendrik Richter * de.po: Updated German translation. 2005-01-22 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-01-21 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-21 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-21 Kjartan Maraas * nn.po: Update this. 2005-01-21 Rhys Jones * cy.po: Corrected further minor typos in Welsh translation. 2005-01-20 Frank Arnold * de.po: Updated German translation. 2005-01-20 Miloslav Trmac * cs.po: Updated Czech translation. 2005-01-20 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-20 Christian Rose * sv.po: Updated Swedish translation. 2005-01-20 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2005-01-20 Rhys Jones * cy.po: Updated Welsh translation with new strings + many fixes. 2005-01-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-19 Kjartan Maraas * POTFILES.in: Add [endcoding: UTF-8] * nb.po: Update * no.po: Update 2005-01-17 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-17 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2005-01-16 Hendrik Richter * de.po: Updated German translation. 2005-01-16 Priit Laes * et.po: Translation updated. 2005-01-15 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-15 Christian Rose * sv.po: Updated Swedish translation. 2005-01-15 Kjartan Maraas * POTFILES.in: Add nemo-connect-to-server-dialog-main.c * nb.po: Update * no.po: Update 2005-01-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-13 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-13 Christian Rose * sv.po: Updated Swedish translation. 2005-01-13 Christian Rose * sv.po: Updated Swedish translation. 2005-01-12 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-01-10 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2005-01-12 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-01-11 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-01-11 Adam Weinberger * en_CA.po: Updated Canadian English translation. === nemo 2.9.2 === 2005-01-07 Kjartan Maraas * nb.po: Fixety fix * no.po: Fixfixety fix 2005-01-04 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-12-21 Christian Rose * sv.po: Updated Swedish translation. 2004-12-20 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2004-12-17 Laurent Dhima * sq.po: Updated Albanian translation. 2004-12-13 David Lodge * en_GB.po: Updated British translation. 2004-12-13 Dwayne Bailey * zu.po: Added Zulu translation by Zuza Software Foundation . 2004-12-11 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-12-08 Christian Rose * tr.po: Reverted broken tr.po update that broke the nemo build. 2004-12-05 Baris Cicek * tr.po: Fixed typo in Turkish Translation 2004-12-03 Žygimantas BeruÄka * lt.po: Updated Lithuanian translation. 2004-11-29 Dwayne Bailey * nso.po: Added Northern Sotho translation by Zuza Software Foundation . 2004-11-28 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-11-25 Kjartan Maraas * nb.po: Updated Norwegian bokmÃ¥l translation. 2004-11-25 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-11-24 Adam Weinberger * en_CA.po: Updated Canadian English translation. === nemo 2.9.1 === 2004-11-24 Miloslav Trmac * cs.po: Updated Czech translation. 2004-11-23 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-11-22 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-11-22 Alexander Larsson * POTFILES.in: * POTFILES.skip: Update after merge 2004-11-20 Marcel Telka * sk.po: Fixed typos. 2004-11-19 Hendrik Richter * de.po: Updated German translation. 2004-11-15 Meelad Zakaria * fa.po: Updated Persian translation. 2004-11-14 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2004-11-13 Meelad Zakaria * fa.po: Updated Persian translation. 2004-11-11 Alessio Frusciante * it.po: Updated translation by Luca Ferretti . 2004-11-09 Gustavo Noronha Silva * pt_BR.po: fixed strings which had mnemonics but should not (fix up-ported from gnome-2-8 branch) - Fixes http://bugzilla.gnome.org/show_bug.cgi?id=157252 === nemo 2.8.2 === 2004-10-25 Mohammad DAMT * id.po: Updated Indonesian translation 2004-10-22 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-10-19 Laszlo Dvornik * hu.po: Hungarian translation updated. 2004-10-19 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-10-17 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2004-10-17 Christophe Merlet * fr.po: Updated French translation. 2004-10-17 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-10-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-10-14 Miloslav Trmac * cs.po: Updated Czech translation. 2004-10-14 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-10-14 Laurent Dhima * sq.po: Updated Albanian translation. 2004-10-13 David Lodge * en_GB.po: Updated British English translation. 2004-10-13 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. === nemo 2.8.1 === 2004-10-05 Leonid Kanter * ru.po: More fixes 2004-10-03 Leonid Kanter * ru.po: Fixed Russian translation 2004-10-03 Christophe Merlet * fr.po: Updated French translation. Close #154290. 2004-09-29 Sebastien Bacher * fr.po: Fix in the French translation. 2004-09-26 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-09-24 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2004-09-15 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-09-15 Arafat Medini * ar.po: Updated Arabic translation. 2004-09-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-09-14 Alexander Larsson * ar.po: Fix up spaces. 2004-09-13 Kjartan Maraas * nb.po: Updated after getting comments from Sigurd Gartmann. * no.po: Same. === nemo 2.8.0 === 2004-09-12 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-09-12 Akagic Amila * bs.po: Updated Bosnian translation. 2004-09-12 Laszlo Dvornik * hu.po: Updated Hungarian translation by Gabor Kelemen. 2004-09-11 Dafydd Harries * cy.po: Updated Welsh translation. 2004-09-11 Abel Cheung * zh_TW.po: Updated traditional Chinese translation by GNOME HK Team. * ar.po, he.po: Mark wrong entry as fuzzy (msgfmt check failed). 2004-09-11 Christophe Merlet * fr.po: Updated French translation from Sebastien Bacher . 2004-09-09 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-09-08 Abel Cheung * zh_TW.po: Updated traditional Chinese translation by GNOME HK Team. 2004-09-08 Mugurel Tudor * ro.po: Corrected Romanian translation 2004-09-08 Mugurel Tudor * ro.po: Updated Romanian translation 2004-09-07 Alexander Shopov * bg.po: Updated Bulgarian translation 2004-09-07 Laszlo Dvornik * hu.po: Updated Hungarian translation. 2004-09-07 Nikos Charonitakis * el.po: Updated Greek translation. 2004-09-07 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2004-09-07 David Lodge * en_GB.po: Updated British translation. 2004-09-06 Kostas Papadimas * el.po: Updated Greek translation. 2004-09-05 Miloslav Trmac * cs.po: Updated Czech translation. 2004-09-04 MÉ™tin Æmirov * az.po: Translation updated. 2004-09-04 Baris Cicek * tr.po: Updated Turkish Translation 2004-09-04 Miloslav Trmac * cs.po: Updated Czech translation. 2004-09-03 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-09-02 Hendrik Richter * de.po: Updated German translation 2004-09-02 Alessio Frusciante * it.po: Updated Italiant translation by Luca Ferretti . 2004-09-02 Runa Bhattacharjee * bn.po: Updated Bengali(bn) Translation. 2004-08-31 Ã…smund Skjæveland * nn.po: Updated Norwegian Nynorsk translation. 2004-08-30 Jordi Mallach * ca.po: Updated Catalan translation. 2004-08-30 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-08-29 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2004-08-28 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-08-26 Nikos Charonitakis * el.po: Updated Greek translation. 2004-08-26 Gediminas Paulauskas * POTFILES.in: remove libnemo-private/nemo-program-chooser.c * lt.po: Updated Lithuanian translation. 2004-08-25 Maxim Dziumanenko * uk.po: Updated Ukrainian translation. 2004-08-24 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation done by Raphael Higino . 2004-08-23 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-08-23 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-08-22 Laszlo Dvornik * hu.po: Updated Hungarian translation. 2004-08-21 Changwoo Ryu * ko.po: Updated Korean translation. 2004-08-21 Danilo Å egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-08-21 Leonid Kanter * ru.po: Updated Russian translation 2004-08-21 Kjartan Maraas * nb.po: Update * no.po: these 2004-08-20 Laurent Dhima * sq.po: Updated Albanian translation. 2004-08-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-08-18 Pauli Virtanen * fi.po: Updated Finnish translation. 2004-08-18 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-08-18 Miloslav Trmac * cs.po: Updated Czech translation. 2004-08-18 Laurent Dhima * sq.po: Updated Albanian translation. 2004-08-18 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-08-18 Laurent Dhima * sq.po: Updated Albanian translation. 2004-08-17 Ankit Patel * gu.po: Updated Final Gujarati Translation. 2004-08-17 Christian Rose * sv.po: Updated Swedish translation. 2004-08-17 Duarte Loreto * pt.po: Updated Portuguese translation. 2004-08-16 Christian Rose * bs.po: Added Bosnian translation by Kenan Hadžiavdić . 2004-08-16 Kjartan Maraas * nb.po: Add this. 2004-08-17 Metin Amiroff * az.po: Translation updated. 2004-08-16 Francisco Javier F. Serrador * es.po: Updated Spanish translation. === nemo 2.7.4 === 2004-08-16 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-08-16 Laszlo Dvornik * hu.po: Updated Hungarian translation. 2004-08-16 Ankit Patel * gu.po: Updated Final Gujarati Translation. 2004-08-16 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-08-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-08-14 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-08-14 Gediminas Paulauskas * lt.po: Updated Lithuanian translation. 2004-08-13 Duarte Loreto * pt.po: Updated Portuguese translation. 2004-08-13 Tommi Vainikainen * fi.po: Unified some fields in po headers for Finnish team. 2004-08-13 Changwoo Ryu * ko.po: Updated Korean translation. 2004-08-13 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-08-13 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-08-13 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-08-12 Jayaradna * ta.po: Added tamil translation 2004-08-10 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2004-08-09 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-08-09 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-08-09 Martin Willemoes Hansen * da.po: Updated Danish translation 2004-08-09 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-08-09 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-08-08 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-08-07 Danilo Å egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-08-06 Laszlo Dvornik * hu.po: Updated Hungarian translation. 2004-08-04 Christian Rose * sv.po: Updated Swedish translation. 2004-08-04 Martin Willemoes Hansen * da.po: Updated Danish translation. 2004-08-02 Duarte Loreto * pt.po: Updated Portuguese translation. 2004-08-02 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-08-02 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-08-01 David Lodge * en_GB.po: Corrected British translation. 2004-08-01 Changwoo Ryu * ko.po: Updated Korean translation. 2004-07-31 Gareth Owen * en_GB.po: Corrected British English translation 2004-07-31 David Lodge * en_GB.po: Updated British translation. 2004-07-31 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-31 Francisco Javier F. Serrador * es.po: Updated Spanih translation. 2004-07-30 Miloslav Trmac * cs.po: Updated Czech translation. 2004-07-29 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-07-29 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-07-29 Gareth Owen * en_GB.po: Updated British English translation 2004-07-28 David Lodge * en_GB.po: Updated British translation. 2004-07-29 Changwoo Ryu * ko.po: Updated Korean translation. 2004-07-28 Gil Osher * he.po: Updated Hebrew translation. 2004-07-28 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-27 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-07-27 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-25 Christian Rose * sv.po: Updated Swedish translation. 2004-07-25 Miloslav Trmac * cs.po: Updated Czech translation. 2004-07-25 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation done by Raphael Higino . 2004-07-24 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-07-24 Christian Neumair * de.po: Updated German translation. 2004-07-23 Miloslav Trmac * cs.po: Updated Czech translation. 2004-07-23 Takeshi AIHANA * ja.po: Updated Japanese translation. === nemo 2.7.2 === 2004-07-21 Guntupalli Karunakar * hi.po: Updated Hindi translation. 2004-07-19 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-19 Miloslav Trmac * cs.po: Updated Czech translation. 2004-07-18 Christian Neumair * POTFILES.in: Updated (#147787, thanks to Alex Winston). * de.po: Updated German translation. 2004-07-16 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-07-14 Christian Rose * sv.po: Updated Swedish translation. 2004-07-14 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation done by Raphael Higino . 2004-07-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-07-10 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-08 Gustavo Noronha Silva * pt_BR.po: translation update by "Raphael Higino" 2004-07-08 Miloslav Trmac * cs.po: Updated Czech translation. 2004-07-08 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-08 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-07-07 Laurent Dhima * sq.po: Updated Albanian translation. 2004-07-07 Laszlo Dvornik * hu.po: Updated Hungarian translation. 2004-07-06 Ole Laursen * da.po: Updated Danish translation. 2004-07-05 Pawan Chitrakar * ne.po: Updated Nepali Translation 2004-07-02 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-07-02 Christian Rose * sv.po: Added links to bug reports. 2004-07-01 Laurent Dhima * sq.po: Translation updated. 2004-06-29 Christian Rose * POTFILES.skip: Removed nonexisting files. * sv.po: Updated Swedish translation. 2004-06-29 Ivan Stojmirov * mk.po: Updated Macedonian translation. 2004-06-29 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-06-28 Laurent Dhima * sq.po: Translation updated. 2004-06-28 Nikos Charonitakis * el.po Updated Greek translation. 2004-06-25 Gareth Owen * en_GB.po: Updated British English translation 2004-06-25 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-06-25 Nikos Charonitakis * el.po: Updated Greek translation. 2004-06-24 Andras Timar * hu.po: Updated Hungarian translation. 2004-06-23 Miloslav Trmac * cs.po: Updated Czech translation. 2004-06-20 Andras Timar * hu.po: Updated Hungarian translation. 2004-06-18 Andras Timar * hu.po: Updated Hungarian translation. 2004-06-17 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-06-10 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-06-09 Gareth Owen * en_GB.po: Updated British English translation 2004-06-08 Miloslav Trmac * cs.po: Updated Czech translation. 2004-06-06 Nikos Charonitakis * el.po: Updated Greek translation. 2004-06-05 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-06-05 Laurent Dhima * sq.po: Updated Albanian translation. 2004-06-04 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-06-04 Jordi Mallach * ca.po: Updated Catalan translation. 2004-06-02 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-06-02 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-06-02 Gareth Owen * en_GB.po: Updated British English translation 2004-06-02 Miloslav Trmac * cs.po: Updated Czech translation. 2004-06-01 Francisco Javier F. Serrador * es.po: Updated Spanish translation. === nemo 2.7.1 === 2004-05-31 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir Petkov 2004-05-29 Miloslav Trmac * cs.po: Updated Czech translation. 2004-05-29 Christian Rose * tk.po: Added Turkmen translation by Gurban Mühemmet Tewekgeli . 2004-05-27 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-05-27 Miloslav Trmac * cs.po: Updated Czech translation. 2004-05-25 Gareth Owen * en_GB.po: Updated British English translation 2004-05-25 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-05-25 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-05-24 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-05-24 Alexander Larsson * POTFILES.in: Add src/file-manager/fm-ditem-page.c 2004-05-18 Gareth Owen * en_GB.po: Updated British English translation 2004-05-17 Francisco Javier F. Serrador * es.po: Updated Spasnih translation. 2004-05-17 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-05-15 Alexander Winston * en_CA.po: Updated Canadian English translation. 2004-05-15 Miloslav Trmac * cs.po: Updated Czech translation. 2004-05-14 Miloslav Trmac * cs.po: Updated Czech translation. 2004-05-14 Andras Timar * hu.po: Updated Hungarian translation. === nemo 2.6.2 === 2004-05-13 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-05-08 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-05-06 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-05-04 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-05-02 Christophe Merlet * fr.po: Updated French translation. 2004-04-28 Gil Osher * he.po: Updated Hebrew translation. 2004-04-28 Jordi Mallach * ca.po: Updated Catalan translation. 2004-04-23 Gil Osher * he.po: Updated Hebrew translation. 2004-04-21 Christophe Merlet * fr.po: Updated French translation. 2004-04-21 Changwoo Ryu * ko.po: Replaced %-d with %e and %-I with %l. `-' modifier is a GNU extension. === nemo 2.6.1 === 2004-04-19 ?ygimantas Beru?ka * lt.po: Updated Lithuanian translation. 2004-04-16 I?aki Larra?aga * eu.po: Updated Basque translatiion. 2004-04-15 Andras Timar * hu.po: Updated Hungarian translation. 2004-04-12 Gareth Owen * en_GB.po: Updated British English translation 2004-04-11 ?ygimantas Beru?ka * lt.po: Updated Lithuanian translation by Mantas Kriau?i?nas. 2004-04-11 John C Barstow * mi.po: Updated M?ori translation. 2004-04-09 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-04-09 Guntupalli Karunakar * gu.po: Added Gujurati translation by Gujarati Team . 2004-04-08 Gareth Owen * en_GB.po: Updated British English tranlsation (bug 138758) 2004-04-08 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-04-06 Christophe Merlet * fr.po: Updated French translation. 2004-04-03 Sam?el J?n Gunnarsson * is.po: Updated Icelandic translation by Helgi ?ormar ?orbj?rnsson 2004-04-02 Gareth Owen * en_GB.po: Fixed small typo 2004-04-03 Mugurel Tudor * ro.po: Updated Romanian translation 2004-04-02 Christian Rose * sv.po: Fixed bug #138867 in the Swedish translation. 2004-03-31 Christian Rose * af.po: Added Afrikaans translation by Zuza Software Foundation . 2004-03-30 Dafydd Harries * cy.po: Update stupid typo in the Welsh translation. 2004-03-30 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-03-30 Jordi Mallach * ca.po: Updated Catalan translation by Aleix Badia i Bosch and me. 2004-03-28 Andras Timar * hu.po: Updated Hungarian translation. 2004-03-26 Christophe Merlet * fr.po: Updated French translation. 2004-03-24 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2004-03-24 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2004-03-23 Kostas Papadimas * el.po: Updated Greek translation. 2004-03-23 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2004-03-23 Priit Laes * et.po: Translation updated. 2004-03-22 Gareth Owen * en_GB.po: Updated British translation 2004-03-22 Guntupalli Karunakar * pa.po: Updated Punjabi translation by Amanpreet Singh Alam . === nemo 2.6.0 === 2004-03-22 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2004-03-22 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. * ar.po: Mark wrong entry as fuzzy (msgfmt check failed). 2004-03-21 Alastair McKinstry * ga.po: Update Irish translation. 2004-03-21 Mugurel Tudor * ro.po: Updated Romanian translation. 2004-03-20 Robert Sedak * hr.po: Updated Croatian translation. 2004-03-19 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-03-19 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-03-19 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-03-19 Leonid Kanter * ru.po: Fixed typo in Russian translation (missed tag bracket) 2004-03-19 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-03-18 Arafat Medini * ar.po: Updated Arabic translation. 2004-03-18 Christophe Merlet * fr.po: Updated French translation. 2003-03-17 Andras Timar * hu.po: Updated Hungarian translation. 2004-03-16 Kostas Papadimas * el.po: Updated Greek translation. 2004-03-16 Dafydd Harries * cy.po: Updated Welsh translation. === nemo 2.5.91 === 2004-03-14 Maxim Dziumanenko * uk.po: Updated Ukrainian translation 2004-03-13 Vincent van Adrighem * nl.po: Translation updated. 2004-03-13 Christian Neumair * POTFILES.in: Removed medusa/search-related files as discussed on nemo-list. * POTFILES.skip: Added them here. 2004-03-13 Christophe Merlet * fr.po: Updated French translation. 2004-03-13 Alexander Shopov * bg.po: Updated Bulgarian translation by Vladimir "Kaladan" Petkov 2004-03-12 Sayamindu Dasgupta * bn.po: Updated Bengali translation (done by Progga 2004-03-11 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation done by Raphael Higino . 2004-03-11 Christian Rose * sv.po: Updated Swedish translation. 2004-03-10 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-03-10 Vincent van Adrighem * nl.po: Translation updated. 2004-03-09 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-03-09 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-03-09 Danilo ?egan * sr.po, sr@Latn.po: Fixed typos noticed by Bojan Suzi?? 2004-03-09 Francisco Javier F. Serrador * es.po: Updated Spansih translation. 2004-03-08 Alastair McKinstry * ga.po: Updated Irish translation. 2004-03-08 Danilo ?egan * sr@ije.po: Added Serbian Jekavian translation by Bojan Suzi?? . === nemo 2.5.90 === 2004-03-08 Ales Nyakhaychyk * be.po: Updated Belarusian translation. 2004-03-07 Alexander Winston * en_CA.po: Updated Canadian English translation to "1489 translated messages, 5 fuzzy translations." status. 2004-03-07 Pauli Virtanen * fi.po: Improve Finnish translation. 2004-03-06 M?tin ?mirov * az.po: Translation updated. 2004-03-06 Ales Nyakhaychyk * be.po: Updated Belarusian translation. 2004-03-06 Priit Laes * et.po: Translation updated. 2004-03-06 Priit Laes * et.po: Translation updated. 2004-03-05 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-03-04 Christian Rose * sv.po: Updated Swedish translation. 2004-03-03 Arafat Medini * ar.po: Updated faulty Arabic translation. 2004-03-03 Jody Goldberg * ar.po : remove semi-duplicated message that was breaking the build. Was gettext on crack ? or was that really a duplicate. 2004-03-04 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-03-03 Guntupalli Karunakar * pa.po: Added Punjabi translation by Amanpreet Singh Alam . 2004-03-3 Arafat Medini * ar.po: Updated Arabic translation. 2004-03-02 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-02-29 Ole Laursen * da.po: Updated Danish translation. 2004-02-28 Pauli Virtanen * fi.po: Updated Finnish translation. 2004-02-28 Christophe Merlet * fr.po: Updated French translation. 2004-02-28 Duarte Loreto * pt.po: Updated Portuguese translation. 2004-02-28 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-02-27 Christian Neumair * POTFILES.skip: Added a bunch of missing files. * de.po: Updated German translation. 2004-02-27 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-02-27 Priit Laes * et.po: Translation updated by Allan Sims. 2004-02-27 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-02-26 Guntupalli Karunakar * hi.po: Updated Hindi translation. 2004-02-26 Vincent van Adrighem * nl.po: Translation updated by Kees van den Broek. 2004-02-26 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2004-02-26 Dafydd Harries * cy.po: Updated Welsh translation. 2004-02-26 Christian Rose * sv.po: Updated Swedish translation. 2004-02-25 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-02-25 Pablo G. del Campo * es.po: Updated Spanish translation. 2004-02-25 Laurent Dhima * sq.po: Updated Albanian translation. 2004-02-25 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-02-25 Miloslav Trmac * cs.po: Updated Czech translation. 2004-02-24 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-02-24 Alastair McKinstry * ga.po: Updated Irish translation. 2004-02-24 Kostas Papadimas * el.po: Updated Greek translation. 2004-02-24 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-02-25 Changwoo Ryu * ko.po: Updated Korean translation. 2004-02-24 Takeshi AIHANA * ja.po: Updated Japanese translation. === nemo 2.5.8 === 2004-02-24 Miloslav Trmac * cs.po: Updated Czech translation. 2004-02-24 ?smund Skj?veland * nn.po: Updated Norwegian nynorsk translation. 2004-02-24 Laurent Dhima * sq.po: Updated Albanian translation. 2004-02-24 Christian Rose * sv.po: Updated Swedish translation. 2004-02-24 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-02-24 Artur Flinta * pl.po: Updated Polish translation. 2004-02-24 Dafydd Harries * cy.po: Updated translation by Bryn Salisbury and myself. 2004-02-23 Dave Camp * POTFILES.in: Added nemo-column-chooser.c 2004-02-23 Ole Laursen * da.po: Updated Danish translation. 2004-02-23 Danilo ?egan * sr.po, sr@Latn.po: Fix accelerator clash and a typo. 2004-02-23 Kostas Papadimas * el.po: Updated Greek translation. 2004-02-22 Paisa Seeluangsawat * th.po: Updated Thai translation. 2004-02-22 Nikos Charonitakis * el.po: Updated Greek translation. 2004-02-22 M?tin ?mirov * az.po: Updated Azerbaijani translation. 2004-02-22 Danilo ?egan * srr.po, sr@Latn.po: Updated Serbian translation. 2004-02-22 Christian Rose * en_CA.po: Added Canadian English translation by Adam Weinberger . 2004-02-21 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-02-21 Christian Rose * sv.po: Updated Swedish translation. 2004-02-21 Laurent Dhima * sq.po: Updated Albanian translation. 2004-02-21 Christian Neumair * de.po: Updated German translation. 2004-02-21 Miloslav Trmac * cs.po: Updated Czech translation. 2004-02-21 Artur Flinta * pl.po: Updated Polish translation. 2004-02-20 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-02-19 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2004-02-19 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-02-19 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-02-18 Alexander Larsson * POTFILES.in: Remove nemo-connect-server 2004-02-18 Alexander Larsson * POTFILES.in: Remove filesystem-attributes.xml (not used anymore) 2004-02-18 Ole Laursen * da.po: Updated Danish translation. * POTFILES.in: Removed non-existing libbackground/preview-file-selection.c. 2003-02-18 Ales Nyakhaychyk * be.po: Updated Belarusian translation. 2003-02-18 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-02-15 Paisa Seeluangsawat * th.po: Updated Thai (th) translation. 2004-02-15 Christian Rose * sv.po: Updated Swedish translation. 2004-02-15 M?tin ?mirov * az.po: Translation updated. 2004-02-13 Kostas Papadimas * el.po: Updated Greek translation. 2004-02-14 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-02-13 Christophe Merlet * fr.po: Updated French translation. 2004-02-12 Christian Rose * sv.po: Updated Swedish translation. 2004-02-12 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-02-11 Arafat Medini * ar.po: Updated Arabic translation. 2004-02-12 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. === nemo 2.5.7 === 2004-02-10 Pauli Virtanen * fi.po: Updated Finnish translation. 2004-02-10 Christian Rose * sv.po: Updated Swedish translation. 2004-02-09 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-02-09 Christian Rose * mi.po: Added Maori translation by John C Barstow . 2004-02-08 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-02-08 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-02-07 Robert Sedak * hr.po: Updated Croatian translation. 2004-02-08 Changwoo Ryu * ko.po: Updated Korean translation. 2004-02-07 Miloslav Trmac * cs.po: Updated Czech translation. 2004-02-07 Laurent Dhima * sq.po: Updated Albanian translation. 2004-02-07 Nikos Charonitakis * el.po: Updated Greek translation. 2004-02-06 Laurent Dhima * sq.po: Updated Albanian translation. 2004-02-05 Pauli Virtanen * fi.po: Updated Finnish translation. 2004-02-05 Maxim Dziumanenko * uk.po: Updated ukrainian translation. 2004-02-04 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-02-03 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-02-03 Duarte Loreto * pt.po: Updated Portuguese translation. 2004-02-02 Alastair McKinstry * ga.po: Updated Irish translation. 2004-02-01 Ole Laursen * da.po: Updated Danish translation. 2004-02-01 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-01-31 M?tin ?mirov * az.po: Updated Azerbaijani translation. 2004-01-31 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-01-31 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . 2004-01-30 Francisco Javier F. Serrador * es-po: Updated Spanish translation. 2004-01-30 Kjartan Maraas * no.po: Updated Norwegian translation. === nemo 2.5.6 === 2004-01-30 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-29 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-01-28 Miloslav Trmac * cs.po: Fixed Czech translation. 2004-01-27 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-01-27 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2004-01-27 Christophe Merlet * fr.po: Updated French translation. 2004-01-25 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2004-01-25 Christian Neumair * de.po: Updated German translation. 2004-01-24 Changwoo Ryu * ko.po: Updated Korean translation. 2004-01-24 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-01-24 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-01-23 Christophe Merlet * fr.po: Updated French translation. 2004-01-23 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-23 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-01-22 Christian Neumair * de.po: Updated German translation. 2004-01-22 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2004-01-22 Alexander Larsson * cy.po: Hmm? fix parse error 2004-01-22 Nikos Charonitakis * el.po: Updated Greek translation. 2004-01-21 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-21 Nikos Charonitakis * el.po: Updated Greek translation. 2004-01-20 Dafydd Harries * cy.po: Fixes, notably s/symyd/symud/; s/copio/cop?o/. 2004-01-18 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2004-01-18 Kjartan Maraas * no.po: Updated Norwegian translation. 2004-01-17 ?ygimantas Beru?ka * lt.po: Updated Lithuanian translation by Mantas Kriau?i?nas. 2004-01-17 Christophe Merlet * fr.po: Updated French translation. 2004-01-16 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-01-16 Duarte Loreto * pt.po: Updated and revised Portuguese translation. 2004-01-15 Laurent Dhima * sq.po: Updated Albanian translation. 2004-01-13 Christian Neumair * de.po: Updated German translation. 2004-01-13 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-01-13 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2004-01-13 Kostas Papadimas * el.po: Updated Greek translation. 2004-01-13 Vincent van Adrighem * nl.po: Translation updated by Kees van den Broek. 2004-01-13 Takeshi AIHANA * ja.po: Updated Japanese translation. 2004-01-13 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-13 Vincent van Adrighem * nl.po: Translation updated by Reinout van Schouwen. 2004-01-13 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. === nemo 2.5.5 === 2004-01-13 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-01-12 Alexander Larsson * POTFILES.in: Added missing files. 2004-01-12 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2004-01-11 Ross Golder * th.po: Reverted '%Ey' to '%Y' until a working solution has been found for displaying non-Gregorian years. 2004-01-10 Ole Laursen * da.po: Fixed some more strings. 2004-01-10 Christian Neumair * de.po: Updated German translation. 2004-01-10 Changwoo Ryu * ko.po: Updated Korean translation. 2004-01-10 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. * POTFILES.in: Added libnemo-private/nemo-file-utilities.c. 2004-01-09 Ole Laursen * da.po: Fixed some strings in Danish translation. 2004-01-08 Christophe Merlet * fr.po: Updated French translation from Sebastien Bacher . 2004-01-07 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-07 Paul Duffy * ga.po: Updated Irish translation 2004-01-06 Kjartan Maraas * POTFILES.in: Remove missing files and add some new ones. * POTFILES.skip: Remove missing files. * no.po: Update. 2004-01-06 Miloslav Trmac * cs.po: Updated Czech translation. 2004-01-05 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2004-01-04 Jordi Mallach * POTFILES.in: Removed components/text files. * ca.po: Updated Catalan translation. 2004-01-02 Sanlig Badral * mn.po: Updated Mongolian translation. 2004-01-02 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2004-01-02 Francisco Javier F. Serrador * es.po Updated Spanish translation. 2004-01-01 Ole Laursen * da.po: Partial update of Danish translation. 2004-01-01 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. === nemo 2.5.4 === 2003-12-29 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2003-12-27 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2003-12-27 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2003-12-23 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2003-12-22 Gustavo Noronha Silva * pt_BR.po: updated translation and tried to have some translations more standardized. 2003-12-21 Christian Neumair * de.po: Updated German translation. 2003-12-18 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-12-17 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2003-12-16 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. 2003-12-16 Paisa Seeluangsawat * th.po: Updated Thai (th) translation. 2003-12-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2003-12-14 Kjartan Maraas * no.po: Updated Norwegian translation. 2003-12-14 Miloslav Trmac * cs.po: Updated Czech translation. 2003-12-14 Kostas Papadimas * el.po: Updated Greek translation. 2003-12-14 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2003-12-14 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-12-12 Miloslav Trmac * cs.po: Updated Czech translation. 2003-12-12 Christian Neumair * POTFILES.in: Removed obsolete hardware view. 2003-12-10 Francisco Javier F. Serrador * es.po: Updated Spanish translation 2003-12-10 ?smund Skj?veland * nn.po: Updated Norwegian Nynorsk translation. * no.po: Corrected some errors in Norwegian Bokm?l translation. 2003-12-09 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-12-09 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. === nemo 2.5.3 === 2003-12-05 Paisa Seeluangsawat * th.po: Updated Thai (th) translation. 2003-12-04 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-12-03 Miloslav Trmac * cs.po: Updated Czech translation. 2003-12-03 Sanlig Badral * mn.po: Updated Mongolian translation. 2003-12-03 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-11-27 Kjartan Maraas * no.po: Update Norwegian translation. 2003-11-27 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbain translation. 2003-11-26 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . === nemo 2.5.2 === 2003-11-24 Alexander Larsson * POTFILES.in: add fm-icon-container.c 2003-11-20 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. === nemo 2.5.1.1 === 2003-11-12 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2003-11-10 Ole Laursen * da.po: Updated Danish translation. 2003-11-10 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-11-10 Pablo Gonzalo del Campo * es.po: Updated Spanish translation by Francisco Javier F. Serrador . === nemo 2.5.1 === 2003-11-09 Abel Cheung * POTFILES.in: Removed non-existant file and added 2 new .desktop.in. 2003-11-09 Christian Rose * ne.po: Updated Nepali translation by Pawan Chitrakar . 2003-11-02 KAMAGASAKO Masatoshi * ja.po: Updated Japanese translation. 2003-10-30 Kostas Papadimas * el.po: updated Greek Translation 2003-10-28 Andras Timar * hu.po: Updated Hungarian translation. 2003-10-25 Ole Laursen * da.po: Updated Danish translation. 2003-10-21 Stanislav Brabec * cs.po: Typo fix. === nemo 2.5.0 === 2003-10-20 Andras Timar * hu.po: Updated Hungarian translation. 2003-10-17 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-10-15 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. * POTFILES.in: Updated (someone [me?] missed the conflict markers). 2003-10-14 Andras Timar * hu.po: Updated Hungarian translation. 2003-10-08 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-10-07 Andras Timar * hu.po: Updated Hungarian translation. 2003-10-06 Mugurel Tudor * ro.po: Updated Romanian translation 2003-10-06 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-10-06 Danilo ?egan * POTFILES.in: Added new files, removed nonexisting file. 2003-10-01 Gustavo Maciel Dias Vieira * pt_BR.po: Applied revision by Augusta Marques da Silva . 2003-09-28 Christian Rose * sv.po: Fixed an access key conflict. * POTFILES.skip: Removed nonexisting files and added comment. 2003-09-28 Christian Rose * POTFILES.in: Added missing files. 2003-09-15 Christian Neumair * de.po: Fixed stupid wording. 2003-09-15 Artur Flinta * pl.po: Updated Polish translation. 2003-09-11 Artur Flinta * pl.po: Updated Polish translation. 2003-09-10 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-09-10 Andras Timar * hu.po: Fixed a mistranslation. === nemo 2.4.0 === 2003-09-08 Pablo Saratxaga * vi.po: Updated Vietnamese file 2003-09-07 Jordi Mallach * ca.po: Updated Catalan translation. 2003-09-06 Kjartan Maraas * POTFILES.skip: Added missing files. * no.po: Updated Norwegian translation. 2003-09-05 Jordi Mallach * ca.po: Updated Catalan translation. 2003-09-05 Taneem Ahmed * bn.po: Updated Bangla (Bengali) translation. 2002-09-04 Ivan Stojmirov * mk.po: Updated Macedonian translation 2003-09-03 Mugurel Tudor * ro.po: Updated Romanian translation 2003-09-03 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2003-09-03 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-09-02 Christian Rose * sv.po: Fix #121250. === nemo 2.3.90 === 2003-09-01 Paul Duffy * ga.po: Updated Irish translation. 2003-08-31 Kjartan Maraas * no.po: Updated Norwegian translation. 2003-08-28 Nikos Charonitakis * el.po Updated Greek translation. 2003-08-28 Christian Rose * li.po: Updated Limburgish translation by Mathieu van Woerkom . 2003-08-27 Pablo Gonzalo del Campo * es.po: Revision of Spanish translation by Francisco Javier F. Serrador . 2003-08-27 Vincent van Adrighem * nl.po: Dutch translation updated by Kees van den Broek. 2003-08-26 Dafydd Harries * cy.po: Updated Welsh translation. 2003-08-26 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2003-08-25 Duarte Loreto * pt.po: Fixed typos and missing accels in Portuguese translation. 2003-08-26 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . === nemo 2.3.9 === 2003-08-24 Kang Jeong-Hee * ko.po: Updated Korean translation. 2003-08-24 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-08-23 Kjartan Maraas * no.po: Update Norwegian translation. 2003-08-24 Changwoo Ryu * ko.po: Updated Korean translation. 2003-08-23 Danilo ?egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-08-22 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-08-20 Sam?el J?n Gunnarsson * is.po: Updated Icelandic translation 2003-08-19 Kjartan Maraas * no.po: Update Norwegian translation. 2003-08-19 Dafydd Harries * cy.po: Updated Welsh translation. Vast majority of it by Bryn Salisbury, rest by me. 2003-08-18 Metin Amiroff * az.po: Updated Azerbaijani translation. 2003-08-17 Christophe Merlet * fr.po: Updated French translation. 2003-08-17 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-08-16 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-08-15 Kostas Papadimas * el.po: updated Greek Translation 2003-08-14 Pablo Gonzalo del Campo * es.po: Updated Spanish translation by Francisco Javier F. Serrador . 2003-08-14 Christian Rose * ne.po: Added Nepali translation by Pawan Chitrakar . 2003-08-11 Dafydd Harries * cy.po: Updated Welsh translation. 2003-08-12 Danilo ?egan * be.po: Updated Belarusian translation by Ales Nyakhaychyk . 2003-08-12 Christian Neumair * de.po: Updated German translation. 2003-08-11 Dafydd Harries * cy.po: Updated Welsh translation. 2003-08-11 Ole Laursen * da.po: Updated Danish translation. 2003-08-10 Artur Flinta * pl.po: Updated Polish translation. 2003-08-09 Jordi Mallach * ca.po: Updated Catalan translation. 2003-08-09 Miloslav Trmac * cs.po: Updated Czech translation. 2003-08-09 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-08-09 Wang Jian * zh_CN.po: Updated Simplified Chinese translation by Funda Wang . 2003-08-09 Laurent Dhima * sq.po: Updated Albanian translation. 2003-08-09 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-08-09 Christophe Merlet * fr.po: Updated French translation. 2003-08-09 Takeshi AiHANA * ja.po: Updated Japanese translation. 2003-08-08 Danilo ? egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-08-08 Christian Rose * sv.po: Updated Swedish translation. === nemo 2.3.8 === 2003-08-08 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-08-08 Danilo ? egan * sr.po, sr@Latn.po: Updated Serbian translation. 2003-08-07 Miloslav Trmac * cs.po: Updated Czech translation. 2003-08-07 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-08-06 Metin Amiroff * az.po: Updated Azerbaijani translation. 2003-08-06 Wang Jian * zh_CN.po: Updated Simplified Chinese translation by Funda Wang . 2003-08-05 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti 2003-08-05 Jordi Mallach * ca.po: Updated Catalan translation. 2003-08-05 Ole Laursen * da.po: Updated Danish translation. 2003-08-04 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-08-04 Artur Flinta * pl.po: Updated Polish translation. 2003-08-01 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-07-31 Artur Flinta * pl.po: Updated Polish translation. 2003-07-29 Nikos Charonitakis * el.po: Updated Greek translation 2003-07-28 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-07-27 Telsa Gwynne * cy.po: Updated Welsh translation. Again! This from Chris M. Jackson. 2003-07-27 Telsa Gwynne * cy.po: Updated Welsh translation. 2003-07-27 Changwoo Ryu * ko.po: Updated Korean translation. 2003-07-24 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-07-22 Sam?el J?n Gunnarsson * is.po: Updated Icelandic translation 2003-07-21 Christophe Merlet * fr.po: Updated French translation. 2003-07-20 Sam?el J?n Gunnarsson * is.po: Updated Icelandic translation. 2003-07-19 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-07-17 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2003-07-17 Vincent van Adrighem * nl.po: Dutch translation updated by Kees van den Broek. 2003-07-16 Dafydd Harries * cy.po: Updated Welsh translation. 2003-07-14 Dafydd Harries * cy.po: Updated Welsh translation. I think it includes work by Chris Jackson, Telsa Gwynne, Alan Cox and me. Some of us, anyway. 2003-07-13 Kostas Papadimas * el.po: updated Greek Translation. 2003-07-12 Pablo Saratxaga * wa.po: Updated Walloon file 2003-07-10 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-07-09 Fatih Demir * tr.po: Updated Turkish translation by Gorkem. 2003-07-08 Christian Neumair * de.po: Updated German translation. 2003-07-08 Christophe Merlet * fr.po: Updated French translation. 2003-07-07 Artur Flinta * pl.po: Updated Polish translation. 2003-07-07 Miloslav Trmac * cs.po: Updated Czech translation. 2003-07-07 Vincent van Adrighem * nl.po: Dutch translation updated by Kees van den Broek. 2003-07-07 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-07-06 Christian Rose * sv.po: Updated Swedish translation. 2003-07-06 Danilo ? egan * sr.po, sr@Latn.po: Updated Serbian translation by Serbian team (Prevod.org). 2003-07-06 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-07-06 Jordi Mallach * ca.po: Updated Catalan translation. 2003-07-04 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-07-03 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2003-07-03 Artur Flinta * pl.po: Updated Polish translation. 2003-07-02 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-07-02 Artur Flinta * pl.po: Updated Polish translation. 2003-07-01 Laurent Dhima * sq.po: Updated Albanian translation. 2003-06-30 Pauli Virtanen * fi.po: Set translator_credits. 2003-06-30 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-06-29 Ole Laursen * da.po: Updated Danish translation. 2003-06-29 Miloslav Trmac * cs.po: Updated Czech translation. 2003-06-29 Dafydd Harries * cy.po: Added Welsh translation. Credit to Chris Jackson. 2003-06-28 Miloslav Trmac * cs.po: Updated Czech translation. 2003-06-28 Jordi Mallach * ca.po: Updated Catalan translation. 2003-06-28 Christian Rose * POTFILES.in: Added missing file. * sv.po: Updated Swedish translation. 2003-06-28 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-06-28 Miloslav Trmac * cs.po: Updated Czech translation. === nemo 2.3.6 === 2003-06-26 Mohammad DAMT * id.po: Added Indonesian translation by Yohanes Nugroho === nemo 2.3.5 === 2003-06-23 Vincent van Adrighem * nl.po: Dutch translation updated by Kees van den Broek. 2003-06-22 Christian Rose * sv.po: Updated Swedish translation. 2003-06-21 Sam?el J?n Gunnarsson * is.po: Updated Icelandic translation 2003-06-21 Bastien Nocera * en_GB.po: updated, translated the time and dates as well now 2003-06-19 Kostas Papadimas * el.po: updated Greek Translation. 2003-06-17 Mathieu van Woerkom * li.po: Added Limburgish translation 2003-06-16 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti 2003-06-16 Taneem Ahmed * bn.po: Added Bangla translation by Progga of Ankur group . 2003-06-16 Dmitry G. Mastrukov * ru.po: Updated Russian translation from Russian team . 2003-06-14 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-06-12 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-06-12 Jordi Mallach * ca.po: Updated Catalan translation. 2003-06-11 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-06-11 Laurent Dhima * sq.po: Updated Albanian translation. 2003-06-11 Christian Neumair * de.po: Updated German translation. === nemo 2.3.4 === 2003-06-10 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-06-09 Christophe Merlet * fr.po: Updated French translation. 2003-06-08 Christophe Merlet * fr.po: Updated French translation. 2003-06-07 Jordi Mallach * ca.po: Updated Catalan translation. 2003-06-06 Sam?=BAel J?=B3n Gunnarsson * is.po: Added Icelandic translation 2003-06-05 Jordi Mallach * ca.po: Updated Catalan translation. 2003-06-05 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-06-04 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-06-04 Abel Cheung * ta.po: Removed. Completely empty. 2003-05-30 Miloslav Trmac * cs.po: Updated Czech translation. 2003-05-30 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-05-27 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-05-27 Abel Cheung * POTFILES.in: Remove non-existant file(s), add missing files from libnemo-private/. * POTFILES.skip: Remove non-existant file(s). 2003-05-26 Pablo Saratxaga * vi.po: Updated Vietnamese file 2003-05-23 Paul Duffy * ga.po: Updated Irish translation. 2003-05-23 Christian Rose * sv.po: Updated Swedish translation. 2003-05-22 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-05-20 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-05-19 Christophe Merlet * fr.po: None! 2003-05-19 Ole Laursen * da.po: Ported Danish translation from gnome-2-2 branch, not updated yet. === nemo 2.3.2 === 2003-05-19 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-05-18 Michal Bukovjan * cs.po: Updated Czech translation. 2003-05-18 Christophe Merlet * fr.po: Updated French translation. 2003-05-16 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-05-16 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-05-12 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-05-08 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-05-07 Paul Duffy * ga.po: Updated Irish Translation. 2003-05-06 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-05-06 Miloslav Trmac * cs.po: Updated Czech translation. 2003-05-06 Danilo ? egan * sr.po, sr@Latn: Added Serbian translation by http://Prevod.org/. 2003-05-05 Paul Duffy * ga.po:Updated the Irish Translation === nemo 2.3.1 === 2003-05-05 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-05-04 Paul Duffy * ga.po: Updated Irish Translation 2003-05-03 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-04-29 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-04-27 Yanko Kaneti * POTFILES.in: Fixup the schemas.in path. 2003-04-23 Alexander Larsson * POTFILES.in: Add schemas.in file. 2003-04-22 Sanlig Badral * mn.po: Updated Mongolian translation. 2003-04-10 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. === nemo 2.2.3 === 2003-03-31 Laurent Dhima * sq.po: Updated Albanian translation. 2003-03-30 Christophe Merlet * fr.po: Updated French translation. 2003-03-30 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-03-30 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-03-27 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-03-27 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-03-27 Alessio Frusciante * it.po: Updated Italian translation by Luca Ferretti . 2003-03-26 Christian Rose * yi.po: Added Yiddish translation by Raphael Finkel . 2003-03-26 Sanlig Badral * mn.po: Updated Mongolian translation. 2003-03-26 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2003-03-26 Yuriy Syrota * uk.po: Updated Ukrainian translation. 2003-03-25 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-03-25 Ole Laursen * da.po: Updated Danish translation. 2003-03-25 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-03-25 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-03-25 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-03-25 Andras Timar * hu.po: Updated Hungarian translation. 2003-03-25 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-03-25 Jordi Mallach * ca.po: Updated Catalan translation. 2003-03-25 Metin Amiroff * az.po: Updated Azerbaijani translaion. 2003-03-25 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-03-25 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-03-25 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-03-24 Christian Rose * sv.po: Updated Swedish translation. 2003-03-24 Bastien Nocera * en_GB.po: Review the use of trash v. Wastebasket (Closes: #83764) 2003-03-23 Christophe Merlet * fr.po: Updated French translation. 2003-03-22 Christian Neumair * de.po: Updated German translation. 2003-03-22 Pablo Saratxaga * wa.po: Added Walloon file 2003-03-20 Andras Timar * hu.po: Updated Hungarian translation. 2003-03-18 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-03-17 Pablo Saratxaga * vi.po: Updated Vietnamese file 2003-03-17 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-03-17 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-03-17 Artis Trops * lv.po: Updated Latvian translation. 2003-03-17 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-03-17 Kang Jeong-Hee * ko.po: Updated Korean transltaion. 2003-03-17 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2003-03-16 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-03-16 Laurent Dhima * sq.po: Updated Albanian translation. 2003-03-16 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-03-16 Takeshi AIHANA * ja.po: Updated Japanese translation. 2003-03-16 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-03-16 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-03-15 Miloslav Trmac * cs.po: Updated Czech translation. 2003-03-15 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-03-14 Christian Rose * sv.po: Updated Swedish translation. 2003-03-14 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-03-13 Takeshi AIHANA * ja.po: Updated Japanese translation by KAMAGASAKO Masatoshi . 2003-03-13 Christian Rose * ml.po: Added Malayalam translation by FSF-India . 2003-03-13 Sanlig adral * mn.po: Updated Mongolian translation. 2003-03-12 Metin Amiroff * az.po: Updated Azerbaijani translation. === nemo 2.2.2 === 2003-03-10 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-03-10 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2003-03-09 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-03-08 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-03-08 Christian Neumair * de.po: Updated German translation. 2003-03-08 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-03-08 Vincent van Adrighem * nl.po: Dutch translation updated. 2003-03-08 Christian Rose * sv.po: Updated Swedish translation. 2003-03-08 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-03-08 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-03-06 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2003-03-06 Ole Laursen * da.po: Updated Danish translation. 2003-03-05 Kostas Papadimas * el.po: updated Greek Translation. 2003-03-05 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-03-04 Miloslav Trmac * cs.po: Updated Czech translation. 2003-03-03 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-03-03 Jordi Mallach * ca.po: Updated Catalan translation. 2003-03-03 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-03-02 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2003-03-02 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2003-03-02 Christophe Merlet * fr.po: Updated French translation. 2003-03-01 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-03-01 Laurent Dhima * sq.po: Updated Albanian translation. 2003-02-28 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-02-28 Christophe Merlet * fr.po: Updated French translation. 2003-02-28 Christian Rose * sv.po: Updated Swedish translation. 2003-02-26 Miloslav Trmac * cs.po: Updated Czech translation. 2003-02-25 Vincent van Adrighem * nl.po: Dutch translation updated. 2003-02-25 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-02-24 Vincent van Adrighem * nl.po: Dutch translation updated. 2003-02-21 Roozbeh Pournader * fa.po: Added Persian translation. 2003-02-20 Paisa Seeluangsawat * th.po: Updated Thai translation. 2003-02-18 Kostas Papadimas * el.po: updated Greek Translation. 2003-02-18 Vincent van Adrighem * nl.po: Dutch translation updated. 2003-02-16 Kjartan Maraas * no.po: Fix up all date and time formats. 2003-02-16 Christian Neumair * de.po: Updated German translation. 2003-02-15 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-02-15 Christian Rose * sv.po: Some fixes for problems catched in translation review. 2003-02-14 Dmitry G. Mastrukov * be.po: Updated Belarusian translation from Belarusian team . 2003-02-14 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-02-13 Kostas Papadimas * el.po: updated Greek Translation. 2003-02-13 Pablo Gonzalo del Campo * es.po: Fixes in various strings. 2003-02-11 Vincent van Adrighem * nl.po: Dutch translation updated. === nemo 2.2.1 === 2003-02-11 Fatih Demir * tr.po: Committed updated Turkish translation by Arman. 2003-02-10 Christophe Merlet * fr.po: Updated French translation. 2003-02-09 Christian Neumair * de.po: Updated German translation. 2003-02-07 Daniel Yacob * am.po: Updated Amharic translation. 2003-02-04 Paisa Seeluangsawat * th.po: Updated Thai translation. 2003-02-03 Paisa Seeluangsawat * th.po: Updated Thai translation. 2003-02-03 Fatih Demir * tr.po: Committed updated Turkish translation by Gorkem. 2003-02-03 Daniel Yacob * am.po: Updated Amharic translation. 2003-02-02 Duarte Loreto * pt.po: Updated Portuguese translation. 2003-01-31 Paisa Seeluangsawat * th.po: updated Thai translation. 2003-01-30 Pablo Gonzalo del Campo * es.po: Fixed a hotkey mistake. 2003-01-30 Pablo Gonzalo del Campo * es.po: Fixed a string translation mistake. 2003-01-29 Pablo Gonzalo del Campo * es.po: Fixed a string order mistake. 2003-01-29 Pablo Gonzalo del Campo * es.po: Various fixes 2003-01-29 Sanlig Badral * mn.po: updated Mongolian translation. 2003-01-29 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-01-29 Yanko Kaneti * bg.po: Updated Bulgarian translation. 2003-01-28 Pablo Gonzalo del Campo * es.po: Fixed a hotkey mistake in a contextual menu. 2003-01-28 Pablo Saratxaga * vi.po: Updated Vietnamese file 2003-01-28 Kostas Papadimas * el.po: Updated Greek translation. === nemo 2.2.0.2 === 2003-01-26 Kang Jeong-Hee * ko.po: Updated Korean translation. 2003-01-26 Abel Cheung * zh_TW.po: Finished traditional Chinese translation. (Finally!) 2003-01-25 Paisa Seeluangsawat * th.po: Added Thai translation. 2003-01-25 Christophe Fergeau * fr.po: Updated French translation 2003-01-23 Marius Andreiana * ro.po: updated 2003-01-23 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-01-23 Yuriy Syrota * uk.po: Updated Ukrainian translation. 2003-01-23 Gustavo Noronha Silva * pt_BR.po: fix on stuff 2003-01-23 Pablo Saratxaga * vi.po: Updated Vietnamese file === nemo 2.2.0.1 === 2003-01-22 Christian Rose * mn.po: Added Mongolian translation by Ochirbat Batzaya . 2003-01-21 Alessio Frusciante * it.po: Updated Italian translation. 2003-01-21 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . === nemo 2.2.0 === 2003-01-20 Christian Neumair * de.po: Updated German translation. 2003-01-20 Christian Neumair * de.po: Updated German translation. 2003-01-20 Dmitry G. Mastrukov * ru.po: updated Russian translation from Russian team . 2003-01-19 Abel Cheung * zh_TW.po: Updated traditional Chinese translation, and used correct copyright symbol. 2003-01-19 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2003-01-19 He Qiangqiang * zh_CN.po: Fixed some translations. 2003-01-18 T???=82??=B5ivo Leedj???=A2??=82??=ACrv * et.po: Added Estonian translation. 2003-01-18 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-01-17 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-01-17 Jordi Mallach * ca.po: Updated Catalan translation. 2003-01-16 Marius Andreiana * ro.po: updated 2003-01-16 Christian Neumair * de.po: Updated German translation. 2003-01-16 Alessio Frusciante * it.po: Updated Italian translation. 2003-01-16 Daniel Yacob * am.po: Updated Amharic translation. 2003-01-16 Gustavo Noronha Silva * pt_BR.po: updated translation. 2003-01-15 Laurent Dhima * sq.po: Updated Albanian translation. 2003-01-15 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-01-15 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-01-15 Ole Laursen * da.po: Updated Danish translation. 2003-01-15 Andras Timar * hu.po: Updated Hungarian translation. 2003-01-15 Artis Trops * lv.po: Updated Latvian translation. 2003-01-15 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-01-14 Christian Neumair * de.po: Updated German translation. 2003-01-14 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2003-01-14 Daniel Yacob * am.po: Updated Amharic translation. === nemo 2.1.91 === 2003-01-13 He Qiangqiang * zh_CN.po: Updated Simplified Chinese translation by Funda Wang . 2003-01-12 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-01-09 Miloslav Trmac * cs.po: Updated Czech translation. 2003-01-09 Pablo Gonzalo del Campo * es.po: Fixed a couples of shortcut in the Spanish translation. 2003-01-09 Laurent Dhima * sq.po: Updated Albanian translation. 2003-01-08 Daniel Yacob * am.po: Updated Amharic translation. 2003-01-08 Miloslav Trmac * cs.po: Updated Czech translation. 2003-01-08 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-01-08 Kang Jeong-Hee * ko.po: Updated Korean translation by Young-Ho, Cha. 2003-01-08 Ole Laursen * da.po: Updated Danish translation. 2003-01-08 Artis Trops * lv.po: Updated Latvian translation. 2003-01-08 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-01-08 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-01-08 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2003-01-07 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-01-07 Kostas Papadimas * el.po: Updated Greek translation. 2003-01-07 Andras Timar * hu.po: Updated Hungarian translation. 2003-01-02 Pablo Gonzalo del Campo * es.po: Revision and Updated Spanish translation by Francisco Javier Fernandez. 2003-01-07 Christian Rose * sv.po: Updated Swedish translation. 2003-01-07 Daniel Yacob * am.po: Updated Amharic translation. 2003-01-07 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-01-07 Artis Trops * lv.po: Updated Latvian translation. 2003-01-07 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-01-07 Naba Kumar * hi.po: New hindi translation by Bhopal team Guntupalli Karunakar === nemo 2.1.6 === 2003-01-06 Christian Rose * sv.po: Updated Swedish translation. 2003-01-05 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2003-01-05 Pauli Virtanen * fi.po: Updated Finnish translation. 2003-01-04 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2003-01-03 Christian Neumair * de.po: Updated German translation. 2003-01-03 Andras Timar * hu.po: Updated Hungarian translation. 2003-01-02 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2003-01-02 Christian Rose * sv.po: Updated Swedish translation. 2003-01-02 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2003-01-02 Christophe Merlet * fr.po: Updated French translation. 2003-01-02 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2003-01-02 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2003-01-01 Ole Laursen * da.po: Updated Danish translation. 2003-01-01 Artis Trops * lv.po: Updated Latvian translation. 2003-01-01 Hasbullah Bin Pit * ms.po: Updated Malay translation. 2002-12-26 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-12-25 Ole Laursen * da.po: Update Danish translation. 2002-12-25 Artis Trops * lv.po: Updated Latvian translation. 2002-12-23 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2002-12-20 Gil "Dolfin" Osher * he.po: Updated Hebrew translation. 2002-12-19 Yanko Kaneti * bg.po: Fully updated Bulgarian translation from Borislav Aleksandrov . 2002-12-19 Christophe Merlet * fr.po: Updated French translation. 2002-12-19 Andras Timar * hu.po: Updated Hungarian translation. 2002-12-19 Yanko Kaneti * bg.po: Updated Bulgarian translation from Borislav Aleksandrov . 2002-12-19 Christian Rose * sv.po: Updated Swedish translation. 2002-12-18 Christian Rose * sv.po: Updated Swedish translation. 2002-12-18 Alexander Larsson * POTFILES.in: Reverted incorrect change. * POTFILES.skip: Added loser, sample and music components 2002-12-17 Christophe Merlet * fr.po: Updated French translation. 2002-12-17 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-12-16 Christian Neumair * POTFILE.(in/skip): Updated. * de.po: Updated German translation. === nemo 2.1.5 === 2002-12-15 Pablo Saratxaga * vi.po: Updated Vietnamese file * mk.po,ta.po: corrected headers * zh_CN.po: fixed syntax errors 2002-12-12 Ole Laursen * da.po: Updated Danish translation. 2002-12-12 Pablo Gonzalo del Campo * es.po: Updated Spanish translation: replaced (C) with ???=82??=A9. 2002-12-11 Laurent Dhima * sq.po: Updated Albanian translation. 2002-12-11 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-12-10 Daniel Yacob * am.po: Updated Amharic translation. === nemo 2.1.4 === 2002-12-07 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-12-07 Andras Timar * hu.po: Updated Hungarian translation. 2002-12-06 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-12-06 Miloslav Trmac * cs.po: Updated Czech translation. 2002-12-05 Gil Osher * he.po: Updated Hebrew translation. 2002-12-04 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. 2002-12-04 Marius Andreiana * ro.po: updated 2002-12-03 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-12-03 Christian Rose * .cvsignore: Added files. * sv.po: Updated Swedish translation. 2002-12-03 Yuriy Syrota * uk.po: Ukrainian translation updated by Maxim Dzumanenko 2002-12-01 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-11-29 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2002-11-27 Laurent Dhima * sq.po: Added Albanian translation from gnome-2-0 branch. 2002-11-27 Ole Laursen * da.po: Updated Danish translation. === nemo 2.1.3 === 2002-11-25 Vincent van Adrighem * nl.po: Massive copy-paste from stable branch. 2002-11-25 Ole Laursen * da.po: Merged from gnome-2-0 branch. 2002-11-25 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-11-25 Yanko Kaneti * *.po: Convert all to UTF-8. 2002-11-24 Dave Camp * POTFILES.in: Remove sample and loser files. 2002-11-24 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-11-15 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-11-11 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho, Cha . 2002-11-09 Dmitry G. Mastrukov * be.po: Updated Belarusian translation * from Belarusian team . 2002-11-06 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-11-05 Hasbullah Bin Pit * ms.po: Updated Malay Translation (twice). === nemo 2.1.2 === 2002-10-31 Dave Camp * POTFILES.in: Updated. 2002-10-13 Andras Timar * hu.po: Fixed Bugzilla #96578 2002-10-22 Pablo Saratxaga * vi.po: Updated Vietnamese file 2002-10-21 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-10-13 Hasbullah Bin Pit * ms.po: Updated Malay Translation. === nemo 2.1.1 === 2002-10-12 Andras Timar * hu.po: Spellcheck and update. 2002-10-10 Andras Timar * hu.po: Fixed a typo. === nemo-2.1.0 === 2002-09-23 Marius Andreiana * ro.po: updated 2002-09-22 Pablo Saratxaga * vi.po: Updated Vietnamese file 2002-09-21 Dave Camp * az.po: * bg.po: * ca.po: * cs.po: * da.po: * de.po: * el.po: * en_GB.po: * es.po: * eu.po: * fi.po: * fr.po: * ga.po: * gl.po: * hu.po: * it.po: * ja.po: * ko.po: * lt.po: * lv.po: * ms.po: * nl.po: * nn.po: * no.po: * pl.po: * pt.po: * pt_BR.po: * ro.po: * ru.po: * sk.po: * sl.po: * sv.po: * ta.po: * tr.po: * uk.po: * vi.po: * zh_CN.po: * zh_TW.po: 2002-09-21 Dave Camp * POTFILES.in: Added new side pane files. 2002-09-16 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-09-16 Pablo Saratxaga * vi.po: Updated Vietnamese file 2002-09-14 Andras Timar * hu.po: Fixed hotkeys. 2002-09-10 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho, Cha . 2002-09-07 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2002-09-03 Peteris Krisjanis * lv.po: Updated Latvian translation. 2002-08-31 Pablo Saratxaga * vi.po: Updated Vietnamese file 2002-08-29 Jordi Mallach * ca.po: Updated Catalan translation. 2002-08-29 Marius Andreiana * ro.po: updated 2002-08-29 Vincent van Adrighem * nl.po: Dutch translation updated by Reinout van Schouwen. === nemo 2.0.6 === 2002-08-27 Emese Kovacs * hu.po: Updated Hungarian translation. 2002-08-27 Pauli Virtanen * fi.po: Updated Finnish translation. === nemo 2.0.5 === 2002-08-23 Akira TAGOH * ja.po: fix typo. 2002-08-22 Alessio Frusciante * it.po: Updated Italian translation. 2002-08-21 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-08-20 Peteris Krisjanis * lv.po: QA for Latvian translation. 2002-08-20 Yukihiro Nakai * ja.po: Update Japanese translation from Kiyoto Hashida. 2002-08-18 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-08-17 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-08-17 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2002-08-17 Christian Meyer * de.po: Updated German translation. 2002-08-17 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . 2002-08-16 Andras Timar * hu.po: Updated Hungarian translation. 2002-08-16 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-08-16 Peteris Krisjanis * lv.po: Updated Latvian translation by Artis Trops 2002-08-16 Christian Rose * sv.po: Updated Swedish translation. 2002-08-16 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-08-15 Ole Laursen * da.po: Updated Danish translation. 2002-08-15 He Qiangqiang * zh_CN.po: Fixed a typo. 2002-08-14 Christophe Merlet * fr.po: Updated French translation. 2002-08-14 Christian Meyer * de.po: Fixed some more mnemonics. *sigh* 2002-08-14 Christian Meyer * de.po: Fixed some mnemonics. === nemo 2.0.4 === 2002-08-13 Andras Timar * hu.po: Updated Hungarian translation. 2002-08-11 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-08-11 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-08-10 Vincent van Adrighem * nl.po: Reinout van Schouwen updated the Dutch translation. 2002-08-10 Christian Meyer * de.po: Fixed. 2002-08-10 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-08-09 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-08-09 Christian Meyer * de.po: Fixed accelerators, typos and other stuff. 2002-08-07 Evandro Fernandes Giovanini * pt_BR.po: Updated Brazilian Portuguese translation. 2002-08-06 Manuel Borchers * de.po: Updated German translation with mnemonics and converted to utf-8 2002-08-06 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-08-06 jacob berkman * vi.po: fix 2002-08-06 Christophe Merlet * fr.po: Updated French translation. 2002-08-05 Pablo Saratxaga * vi.po: Updated Vietnamese file === nemo 2.0.3 === 2002-08-03 Matthias Warkus * de.po: Small fixes to German translation. 2002-08-01 Christian Rose * sv.po: More fixes in Swedish translation. 2002-08-01 Christian Rose * sv.po: Another fix in Swedish translation. 2002-08-01 Christian Rose * sv.po: Fixed Swedish translation. 2002-07-29 Fatih Demir * tr.po: Committed updated Turkish translation. 2002-07-26 Gustavo Noronha Silva * pt_BR.po: Updated Brazilian translation, by Evandro Fernandes Giovanini . 2002-07-25 Ole Laursen * da.po: Updated Danish translation. === nemo 2.0.2 === 2002-07-23 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-07-23 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-07-23 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-07-23 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 2.0.1 === 2002-07-23 Gustavo Noronha Silva * pt_BR.po: update by Evandro Fernandes Giovanini 2002-07-22 Jordi Mallach * ca.po: Updated Catalan translation. 2002-07-22 Christian Rose * sv.po: Updated Swedish translation. 2002-07-22 Alexander Larsson * POTFILES.skip: Add news sidebar files. 2002-07-22 Christian Rose * sv.po: Updated Swedish translation. 2002-07-22 Jordi Mallach * ca.po: Updated Catalan translation. 2002-07-22 Changwoo Ryu * ko.po: Updated Korean translation from Youngho Cha . 2002-07-21 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-07-20 Matthias Warkus * de.po: Updated German translation. 2002-07-19 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-07-19 Ole Laursen * da.po: Unfuzzified a string. 2002-07-19 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-07-19 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-07-18 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-07-17 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-07-16 Michael Meeks * POTFILES.in: remove news files & update server files. 2002-07-15 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-07-15 Changwoo Ryu * ko.po: Updated Korean translation from Youngho Cha . 2002-07-13 Christian Rose * sv.po: Updated Swedish translation. 2002-07-13 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-07-13 Jordi Mallach * ca.po: Updated Catalan translation. 2002-07-13 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-07-13 Ole Laursen * da.po: Updated Danish translation. 2002-07-12 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-07-12 Jordi Mallach * ca.po: Updated Catalan translation. 2002-07-11 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-07-12 Christian Rose * sv.po: Updated Swedish translation. 2002-07-11 Christian Rose * sv.po: Updated Swedish translation. 2002-06-11 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-07-10 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-07-11 Christian Rose * sv.po: Updated Swedish translation. 2002-07-10 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-07-09 Changwoo Ryu * ko.po: Updated Korean translation from Michelle Kim . 2002-07-09 Christian Rose * sv.po: Updated Swedish translation. 2002-07-08 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-07-07 Christophe Fergeau * fr.po: Updated French translation. 2002-07-06 Christian Rose * sv.po: Updated Swedish translation. 2002-07-04 Peteris Krisjanis * lv.po: Updated Latvian translation. 2002-07-03 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-06-25 Changwoo Ryu * ko.po: Updated Korean translation from Young-Ho Cha . 2002-06-20 Pablo Saratxaga * vi.po: Updated Vietnamese file 2002-06-21 Changwoo Ryu * ko.po: Updated Korean translation from Young-Ho Cha . 2002-06-20 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-06-19 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-06-20 Akira TAGOH * ja.po: Updated Japanese translation. 2002-06-16 Vincent van Adrighem * nl.po: Reinout van Schouwen updated the Dutch translation. Sorry for the delay Reinout... 2002-06-16 Christophe Merlet * fr.po: Updated French translation. 2002-06-16 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-06-14 Changwoo Ryu * ko.po: Updated Korean translation. 2002-06-13 Christophe Merlet * fr.po: Updated French translation. 2002-06-12 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-06-11 Pablo Gonzalo del Campo * es.po: Fix a string in Spanish translation. 2002-06-10 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-06-10 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-06-10 Changwoo Ryu * ko.po: Updated Korean translation from Young-Ho Cha . 2002-06-10 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-06-09 Pablo Gonzalo del Campo * es.po: Fix a string in Spanish translation. 2002-06-09 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-06-09 Carlos Perello Marin * pt_BR.po: Gustavo Noronha Silva 2002-06-09 Jordi Mallach * ca.po: Updated Catalan translation. 2002-06-09 Christian Rose * sv.po: Updated Swedish translation. 2002-06-07 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-06-06 Dmitry G. Mastrukov * ru.po: updated Russian translation. 2002-06-05 Dmitry G. Mastrukov * ru.po: updated Russian translation 2002-06-05 Christian Rose * sv.po: Fix. 2002-06-04 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-06-04 Jordi Mallach * ca.po: Updated Catalan translation. 2002-06-03 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. === nemo 1.1.19 === Mon Jun 03 14:18:51 2002 George Lebl * cs.po: update 2002-06-03 German Poo Caamano * es.po: Updated Spanish translation. 2002-06-03 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-06-03 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-06-03 Christian Rose * sv.po: Small fix. 2002-06-03 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . 2002-06-03 Dmitry G. Mastrukov * ru.po: updated Russian translation 2002-06-02 Christian Rose * sv.po: Small fixes. 2002-06-02 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-06-02 Christian Rose * sv.po: Updated Swedish translation. 2002-06-02 Ole Laursen * da.po: Updated Danish translation. 2002-06-01 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-06-01 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-06-01 Christian Rose * sv.po: Updated Swedish translation. 2002-05-31 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-05-30 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2002-05-31 Ole Laursen * da.po: Updated Danish translation. 2002-05-30 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-28 Vincent van Adrighem * nl.po: Big overhaul. Reinout van Schouwen updated the Dutch translation with some help from his sister. 2002-05-28 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2002-05-28 Duarte Loreto * pt.po: Updated Portuguese translation. === nemo 1.1.18 === 2002-05-27 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-05-27 Dmitry G. Mastrukov * ru.po: updated Russian translation 2002-05-26 Ole Laursen * da.po: Updated Danish translation. 2002-05-25 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-25 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2002-05-23 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2002-05-23 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2002-05-23 Yanko Kaneti * bg.po: Added Bulgarian translation from Borislav Aleksandrov . 2002-05-21 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-05-21 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-05-21 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . 2002-05-20 Alessio Frusciante * it.po: Updated Italian translation. 2002-05-20 Vlad Harchev * ru.po: updated russian translation from Dmitry G. Mastrukov . === nemo 1.1.17 === 2002-05-16 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-05-15 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-15 Gediminas Paulauskas * lt.po: Updated Lithuanian translation. 2002-05-14 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2002-05-14 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-05-14 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-05-13 Ole Laursen * da.po: Updated Danish translation, fixed a few long-standing bugs. === nemo 1.1.16 === 2002-05-13 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-05-11 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-05-11 Ole Laursen * da.po: Updated Danish translation. 2002-05-10 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-10 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha . 2002-05-09 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-08 Duarte Loreto * pt.po: Updated Portuguese translation and converted to UTF-8. 2002-05-07 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-05-06 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. === nemo 1.1.15 === 2002-05-05 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-05-05 Christophe Merlet * fr.po: Updated French translation. 2002-05-02 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2002-05-02 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho, Cha . 2002-04-30 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-04-29 Pablo Saratxaga * eu.po: Added Basque file 2002-04-29 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 1.1.14 === 2002-04-28 Fatih Demir * tr.po: Committed updated Turkish translation by Omer. 2002-04-23 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-04-23 Benedikt Roth * de.po: Fixes and updates for German translation. 2002-04-22 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 1.1.13 === 2002-04-20 Simos Xenitellis * el.po: Updated Greek translation. 2002-04-19 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-04-19 Changwoo Ryu * ko.po: Updated Korean translation from Young-Ho Cha . 2002-04-18 Pablo Saratxaga * ca.po: Updated Catalan file 2002-04-18 Vincent van Adrighem * nl.po: Updated Dutch translation by Ronald Hummelink. 2002-04-17 Pablo Saratxaga * vi.po: Added Vietnamese file 2002-04-16 Ole Laursen * da.po: Updated Danish translation. === nemo 1.1.12 === 2002-04-11 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-04-09 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-04-08 Christian Rose * POTFILES.in: Added missing file. * sv.po: Updated Swedish translation. 2002-04-06 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-04-06 Ole Laursen * da.po: Updated Danish translation. 2002-04-05 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-04-03 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-04-02 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-04-01 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-03-31 Christian Rose * sv.po: Updated Swedish translation. 2002-03-29 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-03-29 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-03-28 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-03-28 Ole Laursen * da.po: Updated Danish translation. 2002-03-28 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-03-26 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-03-26 Stanislav Visnovsky * sk.po: Updated Slovak translation. === nemo 1.1.11 === 2002-03-24 Alexander Larsson * POTFILES.in: Revert change by lark. Now make dist works again 2002-03-24 Wang Jian * zh_CN.po: Updated Simplified Chinese translation. 2002-03-21 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-03-21 German Poo-Caaman~o * es.po: Updated spanish translation from Pablo Gonzalo del Campo 2002-03-20 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-03-19 Ole Laursen * da.po: Updated Danish translation. 2002-03-18 Hasbullah Bin Pit * ms.po: Updated Malay Translation. === nemo 1.1.10 === 2002-03-17 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-03-17 Valek Filippov * ru.po: updated russian translation. 2002-03-17 Hasbullah Bin Pit * ms.po: Updated Malay Translation. 2002-03-15 Matthias Warkus * de.po: Updated German translation. 2002-03-15 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-03-15 Hasbullah Bin Pit * ms.po: Added Malay Translation. 2002-03-14 Christian Meyer * de.po: Exchanged German translation by my version. 2002-03-13 Matthias Warkus * de.po: Updated German translation 2002-03-12 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 1.1.9 === 2002-03-10 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-03-10 Christian Rose * POTFILES.in: Added missing file. * sv.po: Updated Swedish translation. 2002-03-08 Valek Filippov * ru.po: updated russian translation. 2002-03-07 Darin Adler * POTFILES.in: Zoom control doesn't have a translatable string any more. We don't need to translate x%. 2002-03-07 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-03-06 Darin Adler * POTFILES.skip: Add the libbackground file in here to quiet down intltool-update. 2002-03-06 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 1.1.8 === 2002-03-05 Carlos Perello Marin * es.po: Updated by Pablo del Campo , welcome Pablo. Also recoded as UTF-8 === nemo 1.1.7 === 2002-03-03 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-03-01 Christian Rose * sv.po: Updated Swedish translation. 2002-03-01 Pauli Virtanen * fi.po: Updated Finnish translation. 2002-03-01 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . 2002-03-01 Christophe Merlet * fr.po: Updated French translation and converted to UTF-8. 2002-02-28 Ole Laursen * da.po: Updated Danish translation. 2002-02-28 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-02-27 Darin Adler * POTFILES.in: Fix what I corrupted. 2002-02-27 Darin Adler * POTFILES.in: Remove nemo-about.c. === nemo 1.1.6 === 2002-02-26 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-02-23 Carlos Perell?? Mar??n * es.po: Updated with our translation memory && some personal updates. 2002-02-22 Darin Adler * POTFILES.in: Remove libbackground/applier.c, because it's not in the tarball, just in cvs, so it breaks tarball builds. Remove nemo-icon-text-item.c. * POTFILES.skip: Remove image-viewer. 2002-02-22 Christian Rose * sv.po: Updated Swedish translation. 2002-02-20 Michael Meeks * POTFILES.in: move image-viewer bits * POTFILES.skip: here. 2002-02-17 Wang Jian * zh_CN.po: Updated Simplified Chinese translation. 2002-02-10 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-02-10 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * POTFILES.in: Added data/*directory.in, components/tree/nemo-tree-model.c, libbackground/applier.c === nemo 1.1.5 === 2002-02-09 Darin Adler * POTFILES.in: Add nemo-dnd.c 2002-02-10 Ole Laursen * da.po: Updated Danish translation. 2002-02-09 Pauli Virtanen * fi.po: Updated Finnish translation and converted it to UTF-8. 2002-02-08 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-02-08 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2002-02-07 Changwoo Ryu * ko.po: Updated Korean translation. === nemo 1.1.4 === 2002-02-04 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-02-03 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-01-31 Christian Rose * sv.po: Updated Swedish translation. 2002-01-30 Ole Laursen * da.po: Updated Danish translation and converted it to UTF-8. 2002-01-30 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-01-30 Zbigniew Chyla * pl.po: Updated Polish translation by GNOME PL Team . === nemo 1.1.3 === 2002-01-27 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2002-01-27 Christian Rose * sv.po: Converted it to UTF-8. 2002-01-26 Christian Rose * sv.po: Updated Swedish translation. 2002-01-24 Ole Laursen * da.po: Updated Danish translation. 2002-01-23 Roy-Magne Mo * nn.po: Using translation from nemo 1.0 and converted it to UTF-8 2002-01-22 Christian Rose * sv.po: Updated Swedish translation. 2002-01-22 Seth Nickell reviewed by: * POTFILES.in: 2002-01-22 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2002-01-21 Christian Rose * sv.po: Updated Swedish translation. === nemo 1.1.2 === 2002-01-16 Darin Adler * POTFILES.skip: Removed the *.oaf.in files, so they don't need to be in here any more. 2002-01-16 Wang Jian * zh_CN.po: Updated Simplified Chinese translation. 2002-01-16 Christian Rose * POTFILES.in: Removed *oaf.in files. * POTFILES.skip: Moved them here. 2002-01-16 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. === nemo 1.1.1 === 2002-01-15 Darin Adler * POTFILES.in: So long, shell.c. 2002-01-14 Christian Rose * POTFILES.ignore: Renamed to POTFILES.skip to make intltool happier. * sv.po: Updated Swedish translation. 2002-01-09 Stanislav Visnovsky * sk.po: Updated Slovak translation 2002-01-08 Duarte Loreto * pt.po: Updated Portuguese translation. 2002-01-08 Darin Adler * POTFILES.in: So long nemo-help.desktop.in 2002-01-07 Darin Adler * POTFILES.in: Adios nemo-font-factory.c 2002-01-05 Christian Rose * sv.po: Updated Swedish translation. 2002-01-05 Christian Rose * POTFILES.in: Added missing files. * POTFILES.ignore: Added files that reportedly should not be translated. * sv.po: Updated Swedish translation. 2002-01-02 Marius Andreiana * ro.po: updated 2001-12-26 Fatih Demir * tr.po: Small correction in the charset field of the po file. 2001-12-19 Andras Timar * hu.po: Updated Hungarian translation from Emese. 2001-12-16 Duarte Loreto * pt.po: Updated Portuguese translation. 2001-12-14 Seth Nickell * POTFILES.in: Moved programs.desktop.in to applications.desktop.in 2001-12-13 Darin Adler * POTFILES.in: Removed translations for the help component. If we ever revive it, we can get the translations from here. 2001-12-06 Darin Adler * POTFILES.in: Moved mozilla component into its own module. 2001-12-05 Christian Rose * sv.po: Updated Swedish translation. 2001-12-02 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-11-28 Pablo Saratxaga * az.po: Updated Azeri file 2001-11-20 Christian Meyer * de.po: Updated German translation. 2001-11-18 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2001-11-16 Pablo Saratxaga * az.po: Updated Azeri file 2001-11-13 Wang Jian * zh_CN.po: Updated Simplified Chinese translation by Wang Jian. 2001-11-11 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-11-10 Peteris Krisjanis * lv.po: updated Latvian translation. 2001-11-08 Darin Adler * POTFILES.in: oaf -> server. 2001-11-08 Darin Adler * POTFILES.in: Remove all the link set stuff. 2001-11-08 Darin Adler * POTFILES.in: Add nemo-hyperbola-ui.xml 2001-11-07 Darin Adler * .cvsignore: Ignore glib-gettextize spoor. * POTFILES.in: Remove help converters, which have been moved to libgnome. 2001-11-07 Ole Laursen * da.po: Updated Danish translation - removed a lot of the old package management strings. 2001-11-07 Abel Cheung * zh_TW.po: A few fixes. 2001-11-07 Abel Cheung * zh_TW.po: Updated traditional Chinese translation. 2001-11-03 Carlos Perell?? Mar??n * POTFILES.in: Sync 2001-10-30 Benedikt Roth * de.po: Fix for German translation 2001-10-30 Christian Meyer * de.po: Fixed a typo, changed News-Panel to Neues-Panel. 2001-10-20 Christian Rose * sv.po: Fixed a problem with the Swedish translation. Thanks to Johan Dahlin for reporting this. 2001-10-20 Christian Rose * sv.po: Fixed a problem with the Swedish translation. Thanks to Anders Carlsson for reporting this. === nemo 1.0.5 === 2001-10-19 Darin Adler * *.po: Nemo 1.0.5 release. 2001-10-13 Carlos Perell?? Mar??n * pt.po: Added by Duarte Loreto 2001-10-12 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation. 2001-10-11 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-10-10 Matthias Warkus * de.po: Updated for release 2001-10-08 Peteris Krisjanis * lv.po: Latvian po first commit 2001-10-08 Pablo Saratxaga * az.po: Updated Azeri file 2001-10-07 Carlos Perell?? Mar??n * es.po: Fixed bug #61924 2001-10-07 Ole Laursen * da.po: Updated Danish translation. 2001-10-07 Sami Pesonen * fi.po: Updated Finnish translation by Pauli Virtanen . 2001-10-07 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-10-06 Carlos Perell?? Mar??n * es.po: Reviewed && updated. 2001-10-03 Christian Rose * sv.po: Updated Swedish translation. 2001-10-03 Valek Filippov * ru.po: updated russian translation. 2001-10-02 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-10-02 Frederic Crozat * fr.po: Add missing ' ' in which was oversizing Nemo Preference Dialog 2001-09-29 Christian Rose * sv.po: Updated Swedish translation. 2001-09-28 Pablo Saratxaga * az.po: Updated Azeri file 2001-09-24 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-09-24 Gediminas Paulauskas * lt.po: Updated Lithuanian translation. 2001-09-22 Christian Meyer * de.po: Updated German translation. 2001-09-22 Wang Jian * zh_CN.po: Updated Simpfiled Chinese translation. 2001-09-21 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation. 2001-09-21 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-09-17 Akira TAGOH * ja.po: Updated Japanese translation. 2001-09-14 Christian Rose * POTFILES.in: Added missing .desktop.in files. * sv.po: Updated Swedish translation. 2001-09-13 Pablo Saratxaga * ca.po: Updated Catalan file 2001-09-11 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-09-11 Christian Rose * sv.po: Updated Swedish translation. 2001-09-11 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-09-10 Pablo Saratxaga * ga.po: Updated Irish file 2001-09-08 Abel Cheung * Updated traditional Chinese translation. 2001-09-03 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-09-01 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-09-01 Christophe Merlet * fr.po: Updated French translation from Christophe Fergeaux . 2001-09-01 Wang Jian * zh_CN.po: Updated Simplifed Chinese. 2001-09-01 Wang Jian * zh_CN.po: Renamed from zh_CN.GB2312.po. * zh_CN.po: Updated Simplified Chinese. 2001-08-31 Yukihiro Nakai * ja.po: Update Japanese translation and overwrite Tagoh's work (w 2001-08-31 Abel Cheung * zh_TW.Big5.po: Rename to ...... * zh_TW.po: This. 2001-08-31 Akira TAGOH * ja.po: Updated Japanese translation. 2001-08-29 Wang Jian * zh_CN.GB2312.po: Translation update. 2001-08-27 Ole Laursen * da.po: Updated Danish translation. 2001-08-27 Abel Cheung * ro.po: Modified line 5010, gettext complains. * zh_CN.GB2312.po: Modified line 130, reason is the same as above. 2001-08-22 Christian Meyer * de.po: Update hence my recent changes. * POTFILE.in: Removed nemo-services-ui.xml. 2001-08-20 Christian Meyer * de.po: Updated German translation. Fixed some nasty strings. Added some comments. Fixed mawa's email. Made translation for consistent. 2001-08-19 Jesus Bravo Alvarez * gl.po: (Partially) Updated Galician translation. 2001-08-19 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-08-19 Wang Jian * zh_CN.GB2312.po: Added by Wang Jian . 2001-08-15 Darin Adler * POTFILES.in: Add the file system XML file. 2001-08-06 Yukihiro Nakai * ja.po: Update Japanese translation. 2001-07-29 Christian Meyer * de.po: Updated German translation. Corrected my email address. Changed "Factory" in translated messages to "Fabrik" 2001-07-24 Ole Laursen * da.po: Revamped a few strings in Danish translation. 2001-07-23 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-07-22 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * nn.po: Updated Norwegian (nynorsk) translation. 2001-07-21 Christian Rose * POTFILES.in: Added libnemo-private/nemo-customization-data.c. * sv.po: Updated Swedish translation. 2001-07-20 Ole Laursen * da.po: Updated & fixed a few strings in the Danish translation. 2001-07-20 Darin Adler * it.po: Current versions of libxml can't handle the " character, so we must use ' instead. For GNOME 2 we can upgrade the character. 2001-07-19 Marius Andreiana * ro.po: updated 2001-07-17 Christian Rose * sv.po: Updated Swedish translation. 2001-07-17 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-07-15 Kjartan Maraas * nn.po: Updated Norwegian (nynorsk) translation. * no.po: Updated Norwegian (bokmal) translation. 2001-07-15 Fatih Demir * tr.po: Committed updated Turkish translation by G??rkem Cetin. 2001-07-12 Christopher R. Gabriel * it.po: Updated italian translation. 2001-07-12 Christian Rose * sv.po: Translated Alex' newly added "Ext3 Volume" string. 2001-07-10 Christian Rose * sv.po: Minor fixes for the Swedish translation. 2001-07-10 Benedikt Roth * de.po: Fixed German translation * ChangeLog: Remove gettextize spam 2001-07-09 Christophe Merlet * fr.po: Updated French translation. 2001-07-05 Kjartan Maraas * no.po: Updated Norwegian translation. === Nemo 1.0.4 === 2001-07-05 Darin Adler * Makefile.i18npatch: * POTFILES.skip: * update.sh: Remove remnants of the old localization scheme. These are all superseded by xml-i18n-tools. 2001-07-05 Benedikt Roth * de.po: Updated German translation 2001-07-05 Christian Rose * sv.po: Updated Swedish translation. 2001-07-04 Pablo Saratxaga * ca.po: updated Catalan file 2001-07-01 Pablo Saratxaga * ca.po: updated Catalan file 2001-06-29 Benedikt Roth * de.po: Fixed a spelling mistake, fixed a grammar error 2001-06-27 Marius Andreiana * ro.po: updated 2001-06-23 Gediminas Paulauskas * lt.po: most obvious fixes for release. 2001-06-16 Christian Rose * sv.po: Additional small fixes. 2001-06-16 Christian Rose * sv.po: Fixed small typo in the Swedish translation. Thanks to G??ran Weinholt. 2001-06-14 Marius Andreiana * ro.po: added 2001-06-10 Pablo Saratxaga * az.po: Updated Azeri file 2001-06-08 Valek Filippov * ru.po: microupdated russian translation. Thu Jun 07 21:00:00 2001 Matthias Warkus * de.po: update for release 2001-06-07 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-06-07 Emese Kovacs * hu.po: updated Hungarian translation. 2001-06-07 Valek Filippov * ru.po: microupdated russian translation. 2001-06-07 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-06-07 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-06-06 Ole Laursen * da.po: Fixed a few things in Danish translation before release. 2001-06-06 Christian Rose * sv.po: Updated Swedish translation. Tue Jun 05 05:05:10 2001 George Lebl * cs.po: update, fix mistakes Tue Jun 05 04:50:48 2001 George Lebl * cs.po: Update czech translations 2001-06-04 Kjartan Maraas * no.po: Updated Norwegian translation. Sun Jun 03 14:37:17 2001 George Lebl * cs.po: update 2001-06-02 Christian Rose * sv.po: Updated Swedish translation. 2001-05-27 Matthias Warkus * de.po: Conflicts resolved, fixes 2001-05-26 Pablo Saratxaga * az.po: Updated Azeri file 2001-05-24 Christian Meyer * de.po: Small Update. Tue May 22 18:19:55 2001 George Lebl * cs.po: update 2001-05-21 Fatih Demir * ko.po: Updated Korean translation by Young-Ho. 2001-05-21 Pablo Saratxaga * ja.po,pl.po,uk.po,zh_TW.Big5.po: fixed syntax errors and multibyte Sat May 19 14:47:34 2001 George Lebl * cs.po: update 2001-05-17 Ole Laursen * da.po: Updated Danish translation. 2001-05-16 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-05-16 Christian Rose * sv.po: Updated Swedish translation. 2001-05-15 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-05-15 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-05-14 Christian Rose * sv.po: Updated Swedish translation. 2001-05-09 Christian Rose * sv.po: Updated Swedish translation. 2001-05-08 Valek Filippov * ru.po: updated russian translation. 2001-05-06 Jarkko Ranta * fi.po: Updated Finnish translation by Pauli Virtanen. 2001-05-05 Ole Laursen * da.po: Updated Danish translation. 2001-05-04 Ramiro Estrugo * es.po: Fix a really tiny typo. 2001-05-04 Ramiro Estrugo * POTFILES.in: * az.po: * ca.po: * cs.po: * da.po: * de.po: * el.po: * en_GB.po: * es.po: * fi.po: * fr.po: * ga.po: * gl.po: * hu.po: * it.po: * ja.po: * ko.po: * lt.po: * nl.po: * nn.po: * no.po: * pl.po: * pt_BR.po: * ru.po: * sk.po: * sl.po: * sv.po: * ta.po: * tr.po: * uk.po: * zh_TW.Big5.po: Update for more stuff moving to eel. 2001-05-03 Ramiro Estrugo * az.po: * ca.po: * cs.po: * da.po: * de.po: * el.po: * en_GB.po: * es.po: * fi.po: * fr.po: * ga.po: * gl.po: * hu.po: * it.po: * ja.po: * ko.po: * lt.po: * nl.po: * nn.po: * no.po: * pl.po: * pt_BR.po: * ru.po: * sk.po: * sl.po: * sv.po: * ta.po: * tr.po: * uk.po: * zh_TW.Big5.po: Update for libnemo-extensions -> libnemo-private renaming. 2001-05-03 Matthias Warkus * de.po: Updated German translation 2001-05-02 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-05-02 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-05-01 Pablo Gonzalo del Campo * es.po: Updated Spanish Tranlation 2001-05-01 Zbigniew Chyla * pl.po: Updated Polish translation. 2001-04-30 Ramiro Estrugo * POTFILES.in: Rename the theme directories to match their displayed name. 2001-05-01 Zbigniew Chyla * POTFILES.in: Added components/news/nemo-news.c, components/news/Nemo_View_news.oaf.in 2001-04-30 Fatih Demir * ko.po: Committed updated Korean translation by Young-Ho. 2001-04-30 Matthias Warkus * de.po: Merged my changes with Christian's, added some fixes and consistency. 2001-04-30 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-04-29 Dan Mueth * lt.po: Added updated po file from Mantas 2001-04-29 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-04-29 Fatih Demir * tr.po: Updated Turkish translation by G??rkem. 2001-04-29 Christian Meyer * de.po: Updated German translation. 2001-04-27 Darin Adler * ja.po: Removed one translation that was triggering some kind of strange bug or feature in libxml. This is a very unimportant message to translate anyway, that never shows to the user. We can re-add it some day once the problem in libxml is resolved. 2001-04-27 Valek Filippov * ru.po: updated russian translation. 2001-04-27 Christian Rose * sv.po: Updated Swedish translation. 2001-04-26 Ole Laursen * da.po: Fixed a lot of things. 2001-04-25 Christian Rose * sv.po: Updated Swedish translation. 2001-04-25 Christian Meyer * de.po: Small update for German translation. Fixed my email address. 2001-04-25 Changwoo Ryu * ko.po: Updated Korean translation, by . 2001-04-25 Christian Rose * sv.po: Updated Swedish translation. 2001-04-24 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-04-23 Stanislav Visnovsky * sk.po: Updated slovak translation. 2001-04-23 Valek Filippov * ru.po: updated russian translation. 2001-04-23 Pablo Saratxaga * pl.po: enabled the header 2001-04-22 Ole Laursen * da.po: Updated Danish translation. Sat Apr 21 14:52:14 2001 George Lebl * cs.po: update 2001-04-21 Almer S. Tigelaar For Dirk-Jan C. Binnema : * nl.po: Updated Dutch translation. 2001-04-21 Matthias Warkus * de.po: Update, commit for release. 2001-04-21 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-04-20 Christian Rose * sv.po: Updated Swedish translation. 2001-04-19 Ramiro Estrugo * POTFILES.in: Update for new and removed files. Thu Apr 19 18:29:10 2001 George Lebl * cs.po: yet another update Wed Apr 18 23:24:41 2001 George Lebl * cs.po: more then half translated now Tue Apr 17 22:31:07 2001 George Lebl * cs.po: another bunch of translations Mon Apr 16 08:06:45 2001 George Lebl * cs.po: I'm too tired to code and have a couple of ours to kill instead of going to sleep, so here's another bunch of translations, now up to like 28% translated. Damn there is a lot of strings in nemo. 2001-04-16 Zbigniew Chyla * pl.po: Updated Polish translation 2001-04-13 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kov???cs (date string fixes) 2001-04-12 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kov???cs 2001-04-12 Pablo Saratxaga * az.po: Updated Azeri file 2001-04-12 Christian Rose * sv.po: Updated and fixed Swedish translation. Thanks to G??ran Uddeborg and Per Lindstr??m . 2001-04-11 Christian Rose * sv.po: Updated Swedish translation. 2001-04-11 Fatih Demir * tr.po: Committed updated Turkish translation. 2001-04-09 Pablo Saratxaga * az.po: Updated Azeri file 2001-04-09 Akira TAGOH * ja.po: Updated Japanese translation from Satoru Sato 2001-04-07 Fatih Demir * tr.po: Committed updated Turkish translation. 2001-04-04 Ramiro Estrugo * POTFILES.in: Remove a retired file. 2001-04-04 Christian Rose * sv.po: Updated Swedish translation. 2001-04-03 Ramiro Estrugo * everything: Update for eel changes. 2001-04-03 Christian Rose * sv.po: Updated Swedish translation. 2001-03-29 Darin Adler * de.po: Added missing characters to some long lines in the first time druid indexing messages to fix wide druid window. 2001-03-27 Simos Xenitellis * el.po: Update of Greek translation. 2001-03-27 Christian Rose * sv.po: Updated Swedish translation. 2001-03-26 Christian Rose * sv.po: Updated Swedish translation. 2001-03-24 Christian Rose * sv.po: Updated Swedish translation. 2001-03-23 Gediminas Paulauskas * lt.po: Added Lithuanian translation. 2001-03-22 Fatih Demir * tr.po: Cp stable HEAD. 2001-03-16 Pablo Saratxaga * az.po: Updated Azeri file * {el,ko,sl,uk}.po: fixed charset line and/or syntax errors 2001-03-15 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-03-15 Christian Rose * sv.po: Improved the Swedish translation, thanks goes to G??ran Uddeborg . 2001-03-12 Ramiro Estrugo * ja.po: Add missing quotes at end of many lines to fix the build. 2001-03-13 Takuo KITAME * ja.po: Updated Japanese translation. 2001-03-12 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation. 2001-03-12 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kovacs , QA in running Nemo :-) 2001-03-11 Jesus Bravo Alvarez * gl.po: Partially updated Galician translation. 2001-03-11 Christian Rose * sv.po: Updated Swedish translation. 2001-03-10 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kovacs , QA in running Nemo :-) 2001-03-10 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kovacs , spelling and typo fixes by Andras Timar . 2001-03-09 Matthias Warkus * de.po: Finally commit translation 2001-03-09 Christophe Merlet * fr.po: Updated French translation. 2001-03-08 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2001-03-08 Darin Adler * sv.po: Added missing characters to some long lines in the first time druid indexing messages to fix wide druid window. 2001-03-08 Szabolcs Ban * hu.po: Update of Hungarian translation by Emese Kovacs . 2001-03-08 Christophe Merlet * fr.po: Updated French translation. Use French quote intead of simple quote. 2001-03-07 Darin Adler * fr.po: Use 'Loser' instead of "Loser", since gnome-xml (I think the problem is gnome-xml) can't handle parsing a string with an entity-escaped quote in it, even if the quote is entity-escaped. We can only change this back once OAF has been updated to require a new gnome-xml and we have beep updated to require a new OAF. 2001-03-07 Darin Adler * da.po: Fixed recently-changed da.po (checked in without a ChangeLog entry) to get rid of entries where the original text does not end with " ", but the translated text does. Apparently, the gettext framework does not allow this kind of translation, even though I can see why it could be desirable. 2001-03-07 Christophe Merlet * fr.po: Updated French translation. 2001-03-07 Mathieu Lacage * fr.po: updated frenh translation. still a long way to go before it is finished. 2001-03-07 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-03-06 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-03-06 Christian Rose * sv.po: Updated Swedish translation. 2001-03-06 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-03-06 Christian Rose * sv.po: Updated Swedish translation. 2001-03-05 Pablo Gonzalo del Campo * Updated Spanish Translation 2001-03-06 Pauli Virtanen * fi.po: Updated Finnish 2001-03-05 Darin Adler * en_GB.po: Update of "make check" test results. 2001-03-05 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-03-05 Ramiro Estrugo * ja.po: Updated Japanese translation. The only thing I updated was the localized fonts strings to make my latest round of localization fixes in nemo work in the ja locale. 2001-03-03 Christian Rose * sv.po: Updated Swedish translation. 2001-03-02 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2001-03-02 Simos Xenitellis * el.po: Updated Greek translation. 2001-03-02 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-03-02 Simos Xenitellis * el.po: Updated Greek translation. 2001-03-02 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-03-02 Simos Xenitellis * el.po: Updated Greek translation. 2001-03-02 Christian Rose * sv.po: Updated Swedish translation. 2001-03-01 Darin Adler Work around bug in xml-i18n-tools that created bug 7230 (opening images fails). * hu.po: Use single quotes for now until we have the xml-i18n-tools that can handle \" characters widely enough distributed. 2001-03-01 Darin Adler * hu.po: Fix entry that was missing " ". 2001-03-01 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-03-01 Christian Rose * sv.po: Updated Swedish translation. 2001-03-01 Christophe Merlet * fr.po: Updated French translation. 2001-03-01 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * POTFILES.in: Added missing files. 2001-02-28 Takuo KITAME * ja.po: Updated Japanese translation. 2001-02-28 Eskil Heyn Olsen * da.po: Updated the View as XXX strings, not that it helped. 2001-02-28 Darin Adler * POTFILES.in: Added nemo-password-dialog.c 2001-03-01 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-28 Christian Rose * sv.po: Updated Swedish translation. 2001-02-28 Valek Filippov * ru.po: updated russian translation. 2001-02-28 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-27 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-27 Simos Xenitellis * el.po: Updated Greek translation. 2001-02-27 Christian Rose * sv.po: Updated Swedish translation. 2001-02-27 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-02-27 Matthias Warkus * de.po: Fix, fix, update, fix, fix. 2001-02-27 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-27 Christian Rose * sv.po: Updated Swedish translation. 2001-02-26 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-27 Pauli Virtanen * fi.po: Updated Finnish translation 2001-02-26 Szabolcs Ban * hu.po: Update of Hungarian translation by emese. 2001-02-26 Christian Rose * sv.po: Updated Swedish translation. 2001-02-26 Simos Xenitellis * el.po: Translated more messages to Greek :) 2001-02-25 Matthias Warkus * de.po: Updated again. Strings keep changing! This is mayhem. Someone please do some peer review. There are just about two or three days left. 2001-02-25 Simos Xenitellis * el.po: Updated Greek translation. 2001-02-25 Fatih Demir * tr.po: Committed updated Turkish translation. 2001-02-25 Christian Rose * sv.po: Updated Swedish translation. 2001-02-24 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-24 Gene Z. Ragan * POTFILES.in: Added libnemo-extensions/nautulus-drag.c 2001-02-24 Pauli Virtanen * fi.po: Updated Finnish translation 2001-02-24 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-02-24 Christian Rose * POTFILES.in: Added missing music view files. * sv.po: Updated Swedish translation. 2001-02-24 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-24 Szabolcs Ban * hu.po: Update of Hungarian translation. 2001-02-24 Christian Rose * sv.po: Updated Swedish translation. 2001-02-23 Kjartan Maraas * no.po: Updated Norwegian translation. 2001-02-23 Matthias Warkus * de.po: Fixes and updates to German l10n. 2001-02-23 Laszlo Kovacs * POTFILES.in: components/help/hyperbola-filefmt.c added 2001-02-23 Ramiro Estrugo * POTFILES.in: Add more missing files. This three have (or soon will have) font names for localization. 2001-02-23 Christian Rose * sv.po: Updated Swedish translation. 2001-02-23 Simos Xenitellis * el.po: More updates in messages. * el.po: Updated Greek translation. 2001-02-22 Yukihiro Nakai * ja.po: Update Japanese translation. 2001-02-22 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-22 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-22 Ramiro Estrugo * po/POTFILES.in: Added new file with mozilla charset encoding strings tables. 2001-02-21 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-21 Akira TAGOH * ja.po: Updated Japanese translation. 2001-02-21 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation. 2001-02-22 Christian Rose * sv.po: Updated Swedish translation. 2001-02-21 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * da.po: Committed an update from Kenneth. 2001-02-21 Yukihiro Nakai * ja.po: Update Japanese translation. 2001-02-21 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-21 Matthias Warkus * de.po: Updated for freeze etc. 2001-02-21 Fatih Demir * ko.po: Committed updated Korean translation. 2001-02-20 Darin Adler * da.po: Another update from Kjenneth. 2001-02-21 Christian Rose * sv.po: Updated Swedish translation. 2001-02-20 Darin Adler * da.po: Update of Danish translation from Kjenneth Christiansen . 2001-02-20 Simos Xenitellis * el.po: Update of Greek translation. 2001-02-20 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * POTFILES.in: Update. 2001-02-19 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-19 Simos Xenitellis * el.po: Updated Greek translation. 2001-02-19 Christian Rose * sv.po: Updated Swedish translation. 2001-02-19 Szabolcs Ban * hu.po: Update of Hungarian translation. 2001-02-19 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-19 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-19 Simos Xenitellis * el.po: Update of Greek translation. 2001-02-18 Christian Rose * sv.po: Updated Swedish translation. 2001-02-17 Christian Rose * sv.po: Updated Swedish translation. 2001-02-16 Ramiro Estrugo * POTFILES.in: Add some mozilla stuff that needs to be localized. 2001-02-16 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-16 Christian Rose * sv.po: Updated Swedish translation. 2001-02-15 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-02-15 Christophe Merlet * fr.po: Updated French translation. 2001-02-14 Christophe Merlet * fr.po: Updated French translation. 2001-02-13 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * nn.po: Added Norwegian (nynorsk) translation. 2001-02-14 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-14 Christian Rose * sv.po: Updated Swedish translation. 2001-02-13 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-13 Christian Rose * sv.po: Updated Swedish translation. 2001-02-12 John Sullivan * sk.po: Removed an extra " " that didn't match between msgid and msgstr, breaking "make dist" 2001-02-12 Christophe Merlet * fr.po: Updated French translation. 2001-02-12 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-11 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-10 Matthias Warkus * de.po: Severely updated German translation ;) 2001-02-10 Pablo Gonzalo del Campo * es.po: Updated Spanish translation. 2001-02-09 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-07 Gustavo Maciel Dias Vieira * pt_BR.po: Updated Brazilian Portuguese translation. 2001-02-07 Pablo Gonzalo del Campo * Updated Spanish Translation 2001-02-07 Valek Filippov * ru.po: updated russian translation. 2001-02-07 Martin Norb??ck * sv.po: Updated Swedish translation 2001-02-06 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation 2001-02-06 Fatih Demir * ko.po: Committed updated Korean translation. 2001-02-05 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-05 Christian Rose * sv.po: Updated Swedish translation. 2001-02-04 Fatih Demir * tr.po: Committed updated Turkish translation by G??rkem Cetin. 2001-02-03 Pablo Gonzalo del Campo * es.po: Updated Spanish Translation. 2001-02-03 Christian Rose * sv.po: Updated Swedish translation. 2001-02-02 Martin Norb??ck * sv.po: Fixed some errors in the translation 2001-02-02 Christian Rose * sv.po: Updated Swedish translation. 2001-02-02 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-02 Martin Norb??ck * sv.po: Updated Swedish translation. 2001-01-29 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * POTFILES.in: Updated and ran it through sort. 2001-02-01 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-02-01 Martin Norb??ck * sv.po: Updated Swedish translation. 2001-01-31 Szabolcs Ban * hu.po: Terminology fixes by Andras Timar 2001-01-31 Carlos Perell?? Mar??n * es.po: Updated Spanish translation from Pablo del Campo 2001-01-31 Martin Norb??ck * sv.po: Updated Swedish translation. 2001-01-31 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-01-22 Martin Norb??ck * sv.po: Updated Swedish translation. 2001-01-30 Simos Xenitellis * el.po: Addition of initial Greek translation. 2001-01-30 Christian Rose * sv.po: Updated Swedish translation. 2001-01-29 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-01-29 Fatih Demir * ko.po: Committed updated Korean translation. 2001-01-29 Manuel de Vega Barreiro * es.po: Updated Spanish translation 2001-01-29 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-01-29 Fatih Demir * tr.po: Committed updated Turkish translation by Gorkem Cetin. 2001-01-28 Christian Rose * sv.po: Updated Swedish translation. 2001-01-27 Fatih Demir * ko.po: Committed updated Korean translation. 2001-01-26 Pablo Saratxaga * az.po: Added Azeri file * {ga,ko,pl,ta,uk}.po: corrected headers and syntax errors 2001-01-26 Valek Filippov * ru.po: updated russian translation. 2001-01-26 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-01-25 Christian Rose * sv.po: Updated Swedish translation. 2001-01-24 Christian Rose * sv.po: Updated Swedish translation. 2001-01-24 Zbigniew Chyla * pl.po: Updated Polish translation 2001-01-24 Matthias Warkus * de.po: Big update. This is NOT yet release quality, though. 2001-01-24 Szabolcs Ban * hu.po: Tons of fixes by Andras and Emese (spelling, terminology, headers) 2001-01-24 Stanislav Visnovsky * sk.po: Updated Slovak translation. 2001-01-23 Fatih Demir * tr.po: Committed updated Turkish translation. 2001-01-22 Manuel de Vega Barreiro * es.po: Updated Spanish translation 2001-01-22 Christian Rose * sv.po: Updated Swedish translation. 2001-01-22 Carlos Perell?? Mar??n * es.po: Updated Spanish translation from Pablo del Campo 2000-01-21 Akira TAGOH * ja.po: Updated Japanese translation. 2001-01-20 Kenneth Christiansen * POTFILES.in: Update 2001-01-20 Fatih Demir * ko.po: Committed updated Korean translation. 2001-01-19 Carlos Perell?? Mar??n * es.po: Updated Spanish translation from Pablo del Campo 2001-01-19 Stanislav Visnovsky * sk.po: Added initial Slovak translation. 2001-01-18 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2001-01-17 Ramiro Estrugo * POTFILES.in: Remove nemo-user-level-manager.[ch] which was just retired. 2001-01-17 Christian Rose * sv.po: Updated Swedish translation. 2001-01-15 Darin Adler * POTFILES.in: * POTFILES.skip: Move files that are not part of what's currently built from POTFILES.in to POTFILES.skip. 2001-01-15 Christian Rose * sv.po: Updated Swedish translation. 2000-11-02 Manuel de Vega Barreiro * es.po: Updated Spanish translation. 2001-01-13 Christian Rose * sv.po: Updated Swedish translation. 2001-01-10 Christian Rose * sv.po: Updated Swedish translation. 2001-01-08 Christian Rose * sv.po: Updated Swedish translation. 2001-01-07 Matthias Warkus * de.po: Updated German translation. 2001-01-07 Benedikt Roth * de.po: Updated German translation 2001-01-07 Kjenneth Christiansen * da.po: Committed update. 2001-01-06 Fatih Demir * ko.po: Committed update. 2001-01-06 Christian Rose * sv.po: Updated Swedish translation. 2001-01-05 Christian Rose * update.sh: Added new xml-18n-tools-using update.sh script from Kenneth Christiansen . * sv.po: Updated Swedish translation. 2001-01-04 Matthias Warkus * de.po: Update. 2001-01-04 Christian Rose * sv.po: Updated Swedish translation. 2001-01-02 Christian Rose * sv.po: Updated Swedish translation. 2001-01-02 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-29 Fatih Demir * ko.po: Committed updated Korean translation by YHC ;-) 2000-12-27 Christian Rose * sv.po: Updated Swedish translation. 2000-12-25 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-22 Christian Rose * sv.po: Updated Swedish translation. 2000-12-21 Valek Filippov * ru.po: updated russian translation. 2000-12-21 Christian Rose * sv.po: Updated Swedish translation. 2000-12-20 Christian Rose * sv.po: Updated Swedish translation. 2000-12-19 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-19 Christian Rose * sv.po: Updated Swedish translation. 2000-12-18 Valek Filippov * ru.po: updated russian translation. 2000-12-17 Matthias Warkus * de.po: Update-O-Rama. 2000-12-17 Szabolcs Ban * hu.po: Updated Hungarian translation. 2000-12-17 Szabolcs Ban * hu.po: Updated Hungarian translation, fixed "fixed" translation. 2000-12-16 Christian Rose * sv.po: Updated Swedish translation. 2000-12-15 Zbigniew Chyla * pl.po: Updated Polish translation 2000-12-15 Christian Rose * sv.po: Updated Swedish translation. 2000-12-14 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-14 Martin Norb??ck * sv.po: Updated Swedish translation. 2000-12-13 Christian Rose * sv.po: Updated Swedish translation. 2000-12-13 Martin Norb??ck * sv.po: Updated Swedish translation. 2000-12-13 Valek Filippov * ru.po: updated russian translation. 2000-12-13 Christian Rose * sv.po: Updated Swedish translation. 2000-12-11 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. * POTFILES.in: Updated this. 2000-12-12 Christian Rose * sv.po: Updated Swedish translation. 2000-12-11 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-09 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-12-06 Fatih Demir * ko.po: Committed updated Korean translation. 2000-12-06 Christian Rose * sv.po: Updated Swedish translation. 2000-12-05 Darin Adler * ui-extract.pl: Took out header. Since the .h files are never put anywhere anyone would see them, it's better to not have the extraneous comment that just shows up in all the pot files. 2000-12-05 Christian Rose * sv.po: Updated Swedish translation. 2000-12-04 Valek Filippov * ru.po: updated russian translation. 2000-12-02 Robert Brady * ta.po: Added Tamil translation from Veeravanallore Madhavan. 2000-12-02 Zbigniew Chyla * pl.po: Updated Polish translation 2000-12-02 Christian Rose * sv.po: Updated Swedish translation. 2000-12-01 Valek Filippov * ru.po: updated russian translation. 2000-11-28 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-11-24 Christian Rose * sv.po: Updated Swedish translation. 2000-11-21 Christian Rose * sv.po: Updated Swedish translation. 2000-11-18 Christian Rose * sv.po: Updated Swedish translation. 2000-11-17 Christian Rose * sv.po: Updated Swedish translation. 2000-11-16 Szabolcs BAN * hu.po: initial Hungarian translations. 2000-11-15 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-11-10 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-11-14 Matthias Warkus * de.po: Updated. 2000-11-13 Christian Rose * sv.po: Updated Swedish translation. 2000-11-09 Darin Adler * Makefile.i18npatch: Turns out it can be even simpler. There's no need to generate the headers when making the POTFILE. * .cvsignore: No need to ignore "headers" any more. 2000-11-09 Darin Adler * Makefile.i18npatch: Fixed the patch so it will apply successfully. Also fixed a small problem that leads to an infinite loop when building. * .cvsignore: Ignore the new "headers" file needed to make the build rules work right. 2000-11-09 Eric Brayeur * fr.po: Updated French translation. 2000-11-09 Jarkko Ranta * fi.po: Added Finnish translation 2000-11-08 Kenneth Christiansen Install new versions of the XML-translation scripts. These now works even better, and do not leave behind a "po/.headerlock" file after a build. * Makefile.i18npatch: Minor changes. * ui-extract.pl: New version which fixes bugs for XML messages with more than one newling. * update.pl: Newest release. Keeps Darin happy ;) 2000-11-08 Valek Filippov * ru.po: updated russian translation. 2000-11-08 Robert Brady * en_GB.po: s/trash/wastebasket. 2000-11-07 Fatih Demir * ko.po: Committed updated ko.po. 2000-11-07 Christian Rose * sv.po: Updated Swedish translation. 2000-11-06 Matthias Warkus * de.po: Updated. 2000-11-06 Darin Adler Install new versions of the XML-translation scripts from Kenneth. These work better, but still seem to leave behind a "po/.headerlock" file and "po/tmp" directory after a build. * Makefile.i18npatch: Copied from bonobo. * ui-extract.pl: From Kenneth. * update.pl: Fron Kenneth. 2000-11-06 Christian Rose * sv.po: Updated Swedish translation. 2000-11-04 Zbigniew Chyla * pl.po: Updated Polish translation 2000-11-04 Almer S. Tigelaar * nl.po: Add Dutch translation. 2000-11-04 Valek Filippov * ru.po: updated russian translation. 2000-11-04 Christian Rose * sv.po: Updated Swedish translation. 2000-11-03 Christian Rose * sv.po: Updated Swedish translation. 2000-11-03 Kjartan Maraas * no.po: Updated Norwegian (bokmal) translation. 2000-11-02 Carlos Perell?? Mar??n * es.po: more updates to Spanish translation. 2000-11-02 Andrew V. Samoilov * ru.po: typos fixed. 2000-11-02 Fatih Demir * ko.po: Committed updated ko.po. 2000-11-02 Carlos Perell?? Mar??n * es.po: some updates to Spanish translation. 2000-11-02 Christian Rose * sv.po: Updated Swedish translation. 2000-11-01 Christian Rose * sv.po: Updated Swedish translation. 2000-11-01 Valek Filippov * ru.po: updated russian translation. 2000-10-31 Christian Rose * sv.po: Updated Swedish translation. 2000-10-31 Valek Filippov * ru.po: updated russian translation. 2000-10-29 Kenneth Christiansen * update.pl: Started new approach 2000-10-29 Kenneth Christiansen * update.pl: Started commenting the script 2000-10-29 Kenneth Christiansen * update.pl: Changes small things 2000-10-29 Andrew V. Samoilov * ru.po: updated Russian translation. 2000-10-29 Zbigniew Chyla * pl.po: Updated Polish translation. 2000-10-29 Christian Rose * sv.po: Updated Swedish translation. 2000-10-28 Kenneth Christiansen * da.po: Updated * Added new releases of update.pl and added new ui-extract.pl script aswell 2000-10-28 Takuo Kitame * ja.po: Updated Japanese Translation. 2000-10-28 Matthias Warkus * de.po: Updated. 2000-10-28 Christopher R. Gabriel * it.po: Updated italian translation 2000-10-28 Christian Rose * sv.po: Updated Swedish translation. 2000-10-27 Maciej Stachowiak * da.po: Reverting to version 1.30 (1.31 was mistakenly checked in as a PDF file). 2000-10-27 Zbigniew Chyla * pl.po: Updated Polish translation. 2000-10-27 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-26 Matthias Warkus * de.po: Small update. 2000-10-26 Fatih Demir * ko.po: Committed updated Korean translation by Young-Ho Cha. 2000-10-25 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-24 Zbigniew Chyla * pl.po: Updated Polish translation. 2000-10-23 Fatih Demir * ko.po: Committed updated Korean translation by Young-Ho Cha. 2000-10-23 Matthias Warkus * de.po: Huge update. Everything's translated; all the "Could/Could not/Can/Cannot" stuff now translates to "Konnte nicht werden". I don't think this sounds good, but it's policy and I don't know a better solution. 2000-10-23 Christian Rose * sv.po: Updated Swedish translation. 2000-10-22 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-22 Robert Brady * en_GB.po: Added British translation. 2000-10-21 Zbigniew Chyla * pl.po: Added Polish translation. 2000-10-20 Darin Adler * po/POTFILES.in: Added some new .xml.h files. Got rid of the duplicates I put in there yesterday. 2000-10-19 Darin Adler * po/POTFILES.in: Added the new generated .xml.h files. We'll see how this works in RPM builds. For now, it's a bit inconvenient because the .xml.h files aren't checked in. I'll probably take care of that soon. 2000-10-19 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-18 Christian Rose * sv.po: Updated Swedish translation with update.sh. 2000-10-17 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-15 Christian Rose * sv.po: Updated Swedish translation with update.sh. 2000-10-13 Takuo Kitame * ja.po: Update Japanese translation. 2000-10-13 Christian Rose * sv.po: Updated Swedish translation with update.sh. 2000-10-11 Christian Rose * sv.po: Updated Swedish translation with update.sh, because update.pl is broken with the xml stuff. 2000-10-10 Christian Rose * sv.po: Updated Swedish translation. 2000-10-09 Eric Brayeur * fr.po: Updated French translation. 2000-10-09 Christian Rose * sv.po: Updated Swedish translation. 2000-10-09 Akira TAGOH * ja.po: Updated Japanese translation. 2000-10-08 Valek Filippov * ru.po: updated russian translation. 2000-10-08 Kjartan Maraas * no.po: Updated Norwegian translation. * XMLFILES.in: Added this for the new XML ui-description. * xml2pot.pl: Added this to extract strings from the .xml files * Makefile.in.in: Hacked this in to make all this work with make dist. All this is from Kenneth Christiansen. 2000-10-07 Jesus Bravo Alvarez * gl.po: Updated Galician translation. 2000-10-04 Christian Rose * sv.po: Updated Swedish translation. 2000-10-03 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-10-03 Christian Rose * sv.po: Updated Swedish translation. 2000-09-29 Valek Filippov * ru.po: updated russian translation. 2000-09-29 Christian Rose * sv.po: Updated Swedish translation. 2000-09-28 Pablo Saratxaga * sv.po,uk.po,zh_TW.Big5.po: corrected some syntax errors 2000-09-27 Christian Rose * sv.po: Updated Swedish translation. 2000-09-26 Christian Rose * sv.po: Updated Swedish translation. 2000-09-25 Christian Rose * sv.po: Updated Swedish translation. 2000-09-24 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-09-23 Christian Rose * sv.po: Updated Swedish translation. 2000-09-22 Valek Filippov * ru.po: updated russian translation. 2000-09-22 Christian Rose * sv.po: Updated Swedish translation. 2000-09-21 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-09-20 Christian Rose * sv.po: Updated Swedish translation. 2000-09-20 Kjartan Maraas * no.po: Updated Norwegian translation. * POTFILES.in: Added some more missing files. 2000-09-19 Christian Rose * sv.po: Updated Swedish translation. * POTFILES.in: Added the nemo-user-level-manager.c file. 2000-09-18 Christian Rose * sv.po: Updated Swedish translation. 2000-09-17 Christian Rose * sv.po: Updated Swedish translation. 2000-09-17 Matthias Warkus * de.po: Updates galore. 2000-09-14 Christian Rose * sv.po: Updated Swedish translation. 2000-09-13 Christian Rose * sv.po: Updated Swedish translation. 2000-09-12 Christian Rose * sv.po: Updated Swedish translation. 2000-09-09 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-09-09 Christian Rose * sv.po: Updated Swedish translation. 2000-09-07 Christian Rose * sv.po: Updated Swedish translation. 2000-09-06 Matthias Warkus * de.po: Fixes and updates. In the future, please have an eye on typos, hyphens, microsoftisms and imperatives in this translation. I've encountered a lot of them. "It's beta" is not an excuse for sloppiness! 2000-09-06 Christian Rose * sv.po: Updated Swedish translation. 2000-09-04 Kjartan Maraas * no.po: Updated Norwegian translation. * de.po: Updated German translation from Christian Meyer . 2000-09-04 Valek Filippov * ru.po: updated russian translation. 2000-09-03 Christian Rose * sv.po: Updated Swedish translation. 2000-09-02 Christian Rose * sv.po: Updated Swedish translation. 2000-09-01 Eric Brayeur * fr.po: updated french translation. 2000-08-31 Valek Filippov * ru.po: updated russian translation. 2000-08-30 Jesus Bravo Alvarez * gl.po: Updated Galician translation. 2000-08-30 Valek Filippov * ru.po: updated russian translation. 2000-08-29 Akira TAGOH * ja.po: Updated Japanese translation. 2000-08-27 Valek Filippov * ru.po: updated russian translation. 2000-08-24 Alastair McKinstry * ga.po: Added Irish translation. 2000-08-23 Yuri Syrota * uk.po: Added Ukrainian translation. 2000-08-20 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-08-19 Matthias Warkus * de.po: Updated. 2000-08-19 Valek Filippov * ru.po: updated russian translation. 2000-08-18 Valek Filippov * ru.po: updated russian translation. 2000-08-18 Christopher R. Gabriel * it.po: added italian translation 2000-08-17 Valek Filippov * ru.po: updated russian translation. 2000-08-16 Valek Filippov * ru.po: updated russian translation. 2000-08-15 Valek Filippov * ru.po: updated russian translation. 2000-08-10 Akira TAGOH * ja.po: Updated Japanese translation. 2000-08-09 Matthias Warkus * de.po: Fixed small but nasty error. 2000-08-08 Matthias Warkus * de.po: Nice large update. 2000-08-08 Valek Filippov * ru.po: updated russian translation. 2000-08-05 Fatih Demir * tr.po: Updated the Turkish translation. 2000-08-04 Valek Filippov * ru.po: updated russian translation. 2000-08-03 Fatih Demir * tr.po: Updated the Turkish translation. 2000-08-02 Valek Filippov * ru.po: updated russian translation. 2000-08-02 Pablo Saratxaga * ko.po,tr.po,zh_TW.Big5.po: corrected some syntax errors 2000-07-31 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-31 Valek Filippov * ru.po: updated russian translation. 2000-07-26 Valek Filippov * ru.po: updated russian translation. 2000-07-26 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-25 Fatih Demir * ko.po: Commited updated Korean translation by Young-Ho Cha . 2000-07-25 Valek Filippov * ru.po: updated russian translation. 2000-07-24 Matthias Warkus * de.po: Updated German translation. 2000-07-24 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-23 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-07-22 Richard Hult * sv.po: Updated Swedish translation. 2000-07-22 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-20 Valek Filippov * ru.po: updated russian translation. 2000-07-18 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-17 Andreas Hyden * sv.po: Updated Swedish translation. 2000-07-16 Valek Filippov * ru.po: updated russian translation. 2000-07-16 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-07-15 Matthias Warkus * de.po: Updated. 2000-07-15 Andreas Hyden * sv.po: Updated Swedish translation. 2000-07-11 Valek Filippov * ru.po: updated russian translation. 2000-07-10 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-09 Valek Filippov * ru.po: updated russian translation. 2000-07-09 Matthias Warkus * de.po: Updated. 2000-07-06 Fatih Demir * tr.po: Updated the Turkish translation. 2000-07-05 Valek Filippov * ru.po: updated russian translation. 2000-07-01 Eric Brayeur * fr.po: updated French translation. 2000-06-30 Fatih Demir * .cvsignore: Ignore the messages file produced by msgfmt ( on update ). * tr.po: ( Guess it .. ) Updated the Turkish translation. 2000-06-30 Valek Filippov * ru.po: updated russian translation. 2000-06-27 Valek Filippov * ru.po: updated russian translation. 2000-06-27 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-24 Valek Filippov * ru.po: updated russian translation. 2000-06-23 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-21 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-06-16 Matthias Warkus * de.po: Updated German translation. 2000-06-15 Valek Filippov * ru.po: updated russian translation. 2000-06-15 Kenneth Christiansen * da.po: update 2000-06-14 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-14 Benedikt Roth * de.po: Updated German translation. 2000-06-14 Valek Filippov * ru.po: updated russian translation. 2000-06-13 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-13 Valek Filippov * ru.po: updated russian translation. 2000-06-10 Valek Filippov * ru.po: updated russian translation. 2000-06-10 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-09 Ramiro Estrugo * po/POTFILES.in: Move the nemo-widgets classes to libnemo-extensions. 2000-06-09 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-08 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-06-08 Valek Filippov * ru.po: updated russian translation. 2000-06-06 Fatih Demir * tr.po: Updated the Turkish translation. 2000-06-05 Valek Filippov * POTFILES.in: added some files. 2000-06-04 Fatih Demir * tr.po: Updated the Turkish translation. * ko.po: Committed updated Korean translation. 2000-06-03 Valek Filippov * ru.po: updated russian translation. 2000-06-01 Valek Filippov * ru.po: updated russian translation. 2000-06-01 Benedikt Roth * de.po: Added a very beta german translation 2000-05-31 Kenneth Christiansen * README.tools: Added readme file, which explains the use of the newly checked in po tools. Please go read. 2000-05-31 Fatih Demir * tr.po: Corrected some typos. * tr.po: Updated the Turkish translation. 2000-05-31 Kenneth Christiansen * POTFILES.in: Added files * desk.pl: Script for finding missing translations in desktop files * update.pl: Script for updating and finding missing files for POTFILES.in 2000-05-28 Fatih Demir * tr.po: Die, all you fuzzy entries... 2000-05-26 Valek Filippov * updated russian translation. 2000-05-25 Robin * Slomkowski * fr.po (added) This was create by Jean-Michel Ardantz 2000-05-25 Fatih Demir * tr.po: Updated the Turkish translation. 2000-05-24 Valek Filippov * ru.po: Updated russian translation. 2000-05-23 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-05-22 Valek Filippov * ru.po: Updated russian translation. * update.sh: version 1.2.5. 2000-05-22 Yukihiro Nakai * ja.po: Update from Akira TAGOH. 2000-05-20 Fatih Demir * tr.po : Updated the Turkish translation. * ko.po : Committed ko.po's update. 2000-05-20 Yukihiro Nakai * ja.po: Update from Akira TAGOH. 2000-05-19 Yukihiro Nakai * ja.po: Initial Japanese translation from Akira Tagoh. 2000-05-18 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-05-17 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-05-17 Jesus Bravo Alvarez * gl.po: Updated Galician translation. 2000-05-17 Valek Filippov * ru.po: Updated russian translation. * update.sh: new version. 2000-05-13 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-05-12 Fatih Demir * ko.po : Committed the updated Korean translation. 2000-05-11 Fatih Demir * tr.po : Updated the Turkish translation. 2000-05-10 Fatih Demir * ko.po : Updated Korean translation from Young-Ho Cha . 2000-05-08 Andreas Hyden * sv.po: Updated Swedish translation. 2000-05-07 Andreas Hyden * sv.po: Updated Swedish translation. 2000-05-07 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-05-06 Jesus Bravo Alvarez * gl.po: Added Galician translation. 2000-05-04 Fatih Demir * tr.po : Updated the Turkish translation . 2000-05-04 Valek Filippov * ru.po: updated russian translation. 2000-05-03 Kjartan Maraas * POTFILES.in: Added music view. * no.po: Updated Norwegian translation. 2000-05-03 Fatih Demir * tr.po : Updated the Turkish translation . * ko.po : Added Korean translation by : Young-Ho Cha 2000-05-02 Kjartan Maraas * no.po: Updated Norwegian translation. * POTFILES.in: Added some more files. 2000-05-01 Valek Filippov * ru.po: Updated russian translation. 2000-04-30 Fatih Demir * tr.po : Updated it . 2000-04-29 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-04-27 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-04-27 Ramiro Estrugo * POTFILES.in: s/main/ntl-web-browser.c 2000-04-27 Valek Filippov * ru.po: Small updated russian translation. 2000-04-25 Valek Filippov * ru.po: Small updated russian translation. 2000-04-25 Kjartan Maraas * no.po: Updated Norwegian translation. 2000-04-21 Fatih Demir * update.sh : Added a nicer version of it . * tr.po : Updated the Turkish translation . 2000-04-20 Andreas Hyden sv.po: Added Swedish translation. 2000-04-19 Pablo Saratxaga * da.po: Added Danish file 2000-04-18 Kjartan Maraas * no.po: Added Norwegian translation. 2000-04-15 Fatih Demir * tr.po : Update ++++ 2000-04-15 Valek Filippov * Updatetd russian translation. 2000-04-14 Ramiro Estrugo * .cvsignore: ignore *.gmo and *.mo generated files. 2000-04-14 Ramiro Estrugo * POTFILES.in: Updated for libnemo -> libnemo-extensions changes. 2000-04-14 Fatih Demir * tr.po : Added the Turkish translation . 2000-04-14 Ramiro Estrugo * ChangeLog: Added this thing to make 'make dist' happy. nemo-4.4.2/po/Makefile.in.in000066400000000000000000000157561357442400300155670ustar00rootroot00000000000000# Makefile for program source directory in GNU NLS utilities package. # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper # Copyright (C) 2004-2008 Rodney Dawes # # This file may be copied and used freely without restrictions. It may # be used in projects which are not available under a GNU Public License, # but which still want to provide support for the GNU gettext functionality. # # - Modified by Owen Taylor to use GETTEXT_PACKAGE # instead of PACKAGE and to look for po2tbl in ./ not in intl/ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize # # - Modified by Rodney Dawes for use with intltool # # We have the following line for use by intltoolize: # INTLTOOL_MAKEFILE GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datadir = @datadir@ datarootdir = @datarootdir@ libdir = @libdir@ localedir = @localedir@ subdir = po install_sh = @install_sh@ # Automake >= 1.8 provides @mkdir_p@. # Until it can be supposed, use the safe fallback: mkdir_p = $(install_sh) -d INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ XGETTEXT = @XGETTEXT@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot ALL_LINGUAS = @ALL_LINGUAS@ PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) DISTFILES = Makefile.in.in POTFILES.in $(POFILES) EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS POTFILES = \ # This comment gets stripped out CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) .SUFFIXES: .SUFFIXES: .po .pox .gmo .mo .msg .cat AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot $(MSGMERGE) $* $(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< .po.gmo: $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ && rm -f $$file && $(GMSGFMT) -o $$file $< .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ && rm -f $@ && gencat $@ $*.msg all: all-@USE_NLS@ all-yes: $(CATALOGS) all-no: $(GETTEXT_PACKAGE).pot: $(POTFILES) $(GENPOT) install: install-data install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ dir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $$dir; \ if test -r $$lang.gmo; then \ $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ else \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $(srcdir)/$$lang.gmo as" \ "$$dir/$(GETTEXT_PACKAGE).mo"; \ fi; \ if test -r $$lang.gmo.m; then \ $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ if test -r $(srcdir)/$$lang.gmo.m ; then \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $(srcdir)/$$lang.gmo.m as" \ "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ true; \ fi; \ fi; \ done # Empty stubs to satisfy archaic automake needs dvi info ctags tags CTAGS TAGS ID: # Define this as empty until I found a useful application. install-exec installcheck: uninstall: linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ done check: all $(GETTEXT_PACKAGE).pot rm -f missing notexist srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m if [ -r missing -o -r notexist ]; then \ exit 1; \ fi mostlyclean: rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp rm -f .intltool-merge-cache clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES stamp-it rm -f *.mo *.msg *.cat *.cat.m *.gmo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f Makefile.in.in distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(DISTFILES) dists="$(DISTFILES)"; \ extra_dists="$(EXTRA_DISTFILES)"; \ for file in $$extra_dists; do \ test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ done; \ for file in $$dists; do \ test -f $$file || file="$(srcdir)/$$file"; \ ln $$file $(distdir) 2> /dev/null \ || cp -p $$file $(distdir); \ done update-po: Makefile $(MAKE) $(GETTEXT_PACKAGE).pot tmpdir=`pwd`; \ linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ echo "$$lang:"; \ result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ if $$result; then \ if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.gmo failed!"; \ rm -f $$tmpdir/$$lang.new.po; \ fi; \ done Makefile POTFILES: stamp-it @if test ! -f $@; then \ rm -f stamp-it; \ $(MAKE) stamp-it; \ fi stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ $(SHELL) ./config.status # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nemo-4.4.2/po/POTFILES.in000066400000000000000000000066141357442400300146630ustar00rootroot00000000000000# List of source files containing translatable strings. # Please keep this file sorted alphabetically. [encoding: UTF-8] data/action_i18n_strings.py data/nemo.xml.in data/nemo-autorun-software.desktop.in.in data/nemo.desktop.in.in eel/eel-canvas.c eel/eel-editable-label.c eel/eel-glib-extensions.c eel/eel-gnome-extensions.c eel/eel-gtk-extensions.c eel/eel-stock-dialogs.c eel/eel-vfs-extensions.c files/usr/share/gtksourceview-2.0/language-specs/nemo_action.lang files/usr/share/gtksourceview-3.0/language-specs/nemo_action.lang libnemo-extension/nemo-column.c libnemo-extension/nemo-menu-item.c libnemo-extension/nemo-property-page.c libnemo-private/nemo-action.c libnemo-private/nemo-bookmark.c libnemo-private/nemo-clipboard.c libnemo-private/nemo-column-chooser.c libnemo-private/nemo-column-utilities.c libnemo-private/nemo-context-menu-menu-item.c libnemo-private/nemo-desktop-directory-file.c libnemo-private/nemo-desktop-icon-file.c libnemo-private/nemo-desktop-link.c libnemo-private/nemo-desktop-link-monitor.c libnemo-private/nemo-dnd.c libnemo-private/nemo-entry.c libnemo-private/nemo-file.c libnemo-private/nemo-file-conflict-dialog.c libnemo-private/nemo-file-operations.c libnemo-private/nemo-file-undo-operations.c libnemo-private/nemo-file-utilities.c libnemo-private/nemo-global-preferences.c libnemo-private/nemo-icon-canvas-item.c libnemo-private/nemo-icon-container.c libnemo-private/nemo-icon-dnd.c libnemo-private/nemo-mime-application-chooser.c libnemo-private/nemo-program-choosing.c libnemo-private/nemo-progress-info.c libnemo-private/nemo-query.c libnemo-private/nemo-search-directory-file.c libnemo-private/nemo-tree-view-drag-dest.c libnemo-private/nemo-undo-signal-handlers.c libnemo-private/nemo-vfs-file.c libnemo-private/org.nemo.gschema.xml.in src/nemo-action-config-widget.c src/nemo-application.c src/nemo-autorun-software.c src/nemo-blank-desktop-window.c src/nemo-bookmarks-window.c [type: gettext/glade]src/nemo-bookmarks-window.glade src/nemo-config-base-widget.c src/nemo-connect-server-dialog.c src/nemo-connect-server-dialog-main.c src/nemo-desktop-application.c src/nemo-desktop-icon-grid-view.c src/nemo-desktop-icon-view.c src/nemo-desktop-icon-view-ui.xml src/nemo-desktop-item-properties.c src/nemo-desktop-window.c src/nemo-directory-view-ui.xml src/nemo-error-reporting.c src/nemo-extension-config-widget.c src/nemo-file-management-properties.c [type: gettext/glade]src/nemo-file-management-properties.glade src/nemo-icon-view.c src/nemo-icon-view-container.c src/nemo-icon-view-grid-container.c src/nemo-icon-view-ui.xml src/nemo-image-properties-page.c src/nemo-interesting-folder-bar.c src/nemo-list-model.c src/nemo-list-view.c src/nemo-list-view-ui.xml src/nemo-location-bar.c src/nemo-location-entry.c src/nemo-main-application.c src/nemo-main.c src/nemo-mime-actions.c src/nemo-notebook.c src/nemo-open-with-main.c src/nemo-pathbar.c src/nemo-places-sidebar.c src/nemo-plugin-manager.c src/nemo-progress-ui-handler.c src/nemo-properties-window.c src/nemo-query-editor.c src/nemo-script-config-widget.c src/nemo-shell-ui.xml src/nemo-statusbar.c src/nemo-thumbnail-problem-bar.c src/nemo-toolbar.c src/nemo-trash-bar.c src/nemo-tree-sidebar.c src/nemo-tree-sidebar-model.c src/nemo-view.c src/nemo-view-dnd.c src/nemo-window-bookmarks.c src/nemo-window.c src/nemo-window-manage-views.c src/nemo-window-menus.c src/nemo-window-pane.c src/nemo-window-private.h src/nemo-window-slot.c src/nemo-x-content-bar.c nemo-4.4.2/po/POTFILES.skip000066400000000000000000000005501357442400300152140ustar00rootroot00000000000000# List of source files that should NOT be translated. # Please keep this file sorted alphabetically. libbackground/applier.c data/nemo-autorun-software.desktop.in data/nemo-computer.desktop.in data/nemo-file-management-properties.desktop.in data/nemo-folder-handler.desktop.in data/nemo-home.desktop.in data/nemo.desktop.in data/nemo-browser.desktop.in debian nemo-4.4.2/po/README000066400000000000000000000006201357442400300137550ustar00rootroot00000000000000Translations are done on Launchpad: https://translations.launchpad.net/linuxmint/latest/+pots/nemo From Launchpad we export two sets of files: - The mo files go to files/usr/share/locale/ and eventually end up in the nemo package itself - The po files go to po/po-files/. They are not compiled into mo files (this is done by Launchpad) but are present in this archive as source for the mo files. nemo-4.4.2/polkit.its000066400000000000000000000003761357442400300145120ustar00rootroot00000000000000 nemo-4.4.2/polkit.loc000066400000000000000000000003021357442400300144550ustar00rootroot00000000000000 nemo-4.4.2/src/000077500000000000000000000000001357442400300132505ustar00rootroot00000000000000nemo-4.4.2/src/check-nemo000077500000000000000000000000541357442400300152060ustar00rootroot00000000000000#!/bin/sh ./nemo --check --g-fatal-warnings nemo-4.4.2/src/meson.build000066400000000000000000000104731357442400300154170ustar00rootroot00000000000000dbusBuiltSources = gnome.gdbus_codegen( 'nemo-freedesktop-generated', join_paths(meson.source_root(), 'data', 'freedesktop-dbus-interfaces.xml'), interface_prefix: 'org.freedesktop.', namespace: 'NemoFreedesktop', object_manager: true ) nemoBuiltSources = gnome.gdbus_codegen( 'nemo-cinnamon-dbus', join_paths(meson.source_root(), 'data', 'org.Cinnamon.xml'), interface_prefix: 'org.', namespace: 'Nemo', object_manager: true ) nemoCommon_sources = [ dbusBuiltSources, nemoBuiltSources, 'nemo-action-config-widget.c', 'nemo-application.c', 'nemo-blank-desktop-window.c', 'nemo-bookmark-list.c', 'nemo-bookmarks-window.c', 'nemo-config-base-widget.c', 'nemo-connect-server-dialog-nonmain.c', 'nemo-connect-server-dialog.c', 'nemo-connect-server-operation.c', 'nemo-desktop-icon-grid-view.c', 'nemo-desktop-item-properties.c', 'nemo-desktop-manager.c', 'nemo-desktop-overlay.c', 'nemo-desktop-window.c', 'nemo-error-reporting.c', 'nemo-extension-config-widget.c', 'nemo-file-management-properties.c', 'nemo-floating-bar.c', 'nemo-freedesktop-dbus.c', 'nemo-icon-view-container.c', 'nemo-icon-view-grid-container.c', 'nemo-icon-view.c', 'nemo-image-properties-page.c', 'nemo-interesting-folder-bar.c', 'nemo-list-model.c', 'nemo-list-view.c', 'nemo-location-bar.c', 'nemo-location-entry.c', 'nemo-mime-actions.c', 'nemo-navigation-action.c', 'nemo-navigation-state.c', 'nemo-notebook.c', 'nemo-pathbar.c', 'nemo-places-sidebar.c', 'nemo-plugin-manager.c', 'nemo-previewer.c', 'nemo-progress-info-widget.c', 'nemo-progress-ui-handler.c', 'nemo-properties-window.c', 'nemo-query-editor.c', 'nemo-script-config-widget.c', 'nemo-self-check-functions.c', 'nemo-statusbar.c', 'nemo-thumbnail-problem-bar.c', 'nemo-toolbar.c', 'nemo-trash-bar.c', 'nemo-tree-sidebar-model.c', 'nemo-tree-sidebar.c', 'nemo-view-dnd.c', 'nemo-view-factory.c', 'nemo-view.c', 'nemo-window-bookmarks.c', 'nemo-window-manage-views.c', 'nemo-window-menus.c', 'nemo-window-pane.c', 'nemo-window-slot-dnd.c', 'nemo-window-slot.c', 'nemo-window.c', 'nemo-x-content-bar.c', ] nemoWindow_sources = [ 'nemo-main-application.c', 'nemo-main.c', ] nemoWindow_headers = [ 'nemo-main-application.h', ] nemoDesktop_sources = [ 'nemo-desktop-application.c', 'nemo-desktop-icon-view.c', 'nemo-desktop-main.c', ] nemoDesktop_headers = [ 'nemo-desktop-application.h', 'nemo-desktop-overlay.h', 'nemo-desktop-icon-view.h', ] if enableEmptyView nemoCommon_sources += 'nemo-empty-view.c' endif nemo_deps = [ cinnamon, gail, glib, gtk, libnotif, libxml, math, x11, egg, nemo_extension, nemo_private, xapp ] if exempi_enabled nemo_deps += exempi endif if libexif_enabled nemo_deps += libexif endif nemo = executable('nemo', nemoCommon_sources + nemoWindow_sources, include_directories: [ rootInclude ], c_args: nemo_definitions, dependencies: nemo_deps, install: true ) nemoDesktop = executable('nemo-desktop', nemoCommon_sources + nemoDesktop_sources, include_directories: [ rootInclude], c_args: nemo_definitions, dependencies: nemo_deps, install: true ) nemo_autorun_software = executable('nemo-autorun-software', [ 'nemo-autorun-software.c' ], include_directories: [ rootInclude, ], c_args: nemo_definitions, dependencies: nemo_deps, install: true ) nemo_connect_server = executable('nemo-connect-server', [ 'nemo-bookmark-list.c', 'nemo-connect-server-dialog.c', 'nemo-connect-server-dialog-main.c', 'nemo-connect-server-operation.c' ], include_directories: [ rootInclude, ], c_args: nemo_definitions, dependencies: nemo_deps, install: true ) nemo_open_with = executable('nemo-open-with', [ 'nemo-open-with-main.c' ], include_directories: [ rootInclude, ], c_args: nemo_definitions, dependencies: nemo_deps, install: true ) # LibExecs nemo_convert_metadata = executable('nemo-convert-metadata', [ 'nemo-convert-metadata.c' ], include_directories: [ rootInclude, ], c_args: nemo_definitions, dependencies: nemo_deps, install: true, install_dir: libExecPath, ) nemo_extensions_list = executable('nemo-extensions-list', [ 'nemo-extensions-list.c' ], include_directories: [ rootInclude, ], c_args: nemo_definitions, dependencies: [ nemo_deps ], install: true, install_dir: libExecPath, ) nemo-4.4.2/src/nemo-action-config-widget.c000066400000000000000000000347611357442400300203640ustar00rootroot00000000000000/* nemo-action-config-widget.h */ /* A widget that displays a list of actions to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #include #include "nemo-action-config-widget.h" #include "nemo-application.h" #include "nemo-view.h" #include "nemo-file.h" #include #include #include #include "nemo-global-preferences.h" G_DEFINE_TYPE (NemoActionConfigWidget, nemo_action_config_widget, NEMO_TYPE_CONFIG_BASE_WIDGET); typedef struct { NemoActionConfigWidget *widget; gchar *name; gchar *comment; gchar *stock_id; gchar *icon_name; gchar *filename; } ActionProxy; static void action_proxy_free (ActionProxy *proxy) { g_clear_pointer (&proxy->name, g_free); g_clear_pointer (&proxy->comment, g_free); g_clear_pointer (&proxy->stock_id, g_free); g_clear_pointer (&proxy->icon_name, g_free); g_clear_pointer (&proxy->filename, g_free); } static GtkWidget * get_button_for_row (GtkWidget *row) { GtkWidget *ret; GtkWidget *box = gtk_bin_get_child (GTK_BIN (row)); GList *clist = gtk_container_get_children (GTK_CONTAINER (box)); ret = clist->data; g_list_free (clist); return ret; } static void on_row_activated (GtkWidget *box, GtkWidget *row, GtkWidget *widget) { GtkWidget *button = get_button_for_row (row); gtk_button_clicked (GTK_BUTTON (button)); } static void on_check_toggled(GtkWidget *button, ActionProxy *proxy) { gboolean enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS); GPtrArray *new_list = g_ptr_array_new (); guint i; if (enabled) { for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->filename) == 0) continue; g_ptr_array_add (new_list, g_strdup (blacklist[i])); } } else { for (i = 0; i < g_strv_length (blacklist); i++) { g_ptr_array_add (new_list, g_strdup (blacklist[i])); } g_ptr_array_add (new_list, g_strdup (proxy->filename)); } g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_signal_handler_block (nemo_plugin_preferences, proxy->widget->bl_handler); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS, (const gchar * const *) new_list_ptr); g_signal_handler_unblock (nemo_plugin_preferences, proxy->widget->bl_handler); g_strfreev (blacklist); g_strfreev (new_list_ptr); } static ActionProxy * make_action_proxy (const gchar *filename, const gchar *fullpath) { GKeyFile *key_file = g_key_file_new(); g_key_file_load_from_file (key_file, fullpath, G_KEY_FILE_NONE, NULL); if (g_key_file_has_key (key_file, ACTION_FILE_GROUP, KEY_ACTIVE, NULL)) { if (!g_key_file_get_boolean (key_file, ACTION_FILE_GROUP, KEY_ACTIVE, NULL)) { g_key_file_free (key_file); return NULL; } } ActionProxy *proxy = g_slice_new0 (ActionProxy); gchar *name = g_key_file_get_locale_string (key_file, ACTION_FILE_GROUP, KEY_NAME, NULL, NULL); if (name != NULL) proxy->name = g_strdup (name); gchar *comment = g_key_file_get_locale_string (key_file, ACTION_FILE_GROUP, KEY_COMMENT, NULL, NULL); if (comment != NULL) proxy->comment = g_strdup (comment); gchar *icon_name = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_ICON_NAME, NULL); if (icon_name != NULL) proxy->icon_name = g_strdup (icon_name); gchar *stock_id = g_key_file_get_string (key_file, ACTION_FILE_GROUP, KEY_STOCK_ID, NULL); if (stock_id != NULL) proxy->stock_id = g_strdup (stock_id); proxy->filename = g_strdup (filename); g_free (name); g_free (icon_name); g_free (stock_id); g_key_file_free (key_file); return proxy; } static void populate_from_directory (NemoActionConfigWidget *widget, const gchar *path) { GDir *dir; dir = g_dir_open (path, 0, NULL); if (dir) { const char *name; while ((name = g_dir_read_name (dir))) { if (g_str_has_suffix (name, ".nemo_action")) { char *filename; filename = g_build_filename (path, name, NULL); ActionProxy *p = make_action_proxy (name, filename); if (p != NULL) { p->widget = widget; widget->actions = g_list_append (widget->actions, p); } g_free (filename); } } g_dir_close (dir); } } static gchar * strip_accel (const gchar *input) { gchar *ret = NULL; gchar **split = g_strsplit (input, "_", 2); if (g_strv_length (split) == 1) ret = g_strdup (split[0]); else if (g_strv_length (split) == 2) ret = g_strconcat (split[0], split[1], NULL); g_strfreev (split); return ret; } static void refresh_widget (NemoActionConfigWidget *widget) { gchar **data_dirs; gchar *path; guint i; if (widget->actions != NULL) { g_list_free_full (widget->actions, (GDestroyNotify) action_proxy_free); widget->actions = NULL; } nemo_config_base_widget_clear_list (NEMO_CONFIG_BASE_WIDGET (widget)); data_dirs = (gchar **) g_get_system_data_dirs (); for (i = 0; i < g_strv_length (data_dirs); i++) { path = g_build_filename (data_dirs[i], "nemo", "actions", NULL); populate_from_directory (widget, path); g_clear_pointer (&path, g_free); } path = nemo_action_manager_get_user_directory_path (); populate_from_directory (widget, path); g_clear_pointer (&path, g_free); if (widget->actions == NULL) { GtkWidget *empty_label = gtk_label_new (NULL); gchar *markup = NULL; markup = g_strdup_printf ("%s", _("No actions found")); gtk_label_set_markup (GTK_LABEL (empty_label), markup); g_free (markup); GtkWidget *empty_row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (empty_row), empty_label); gtk_widget_show_all (empty_row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), empty_row); gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), FALSE); } else { GList *l; gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS); for (l = widget->actions; l != NULL; l=l->next) { ActionProxy *proxy = l->data; gboolean active = TRUE; guint i = 0; for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->filename) == 0) { active = FALSE; break; } } GtkWidget *w; GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); GtkWidget *button = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active); g_signal_connect (button, "toggled", G_CALLBACK (on_check_toggled), proxy); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2); w = gtk_image_new (); if (proxy->stock_id != NULL) gtk_image_set_from_stock (GTK_IMAGE (w), proxy->stock_id, GTK_ICON_SIZE_MENU); else if (proxy->icon_name != NULL) gtk_image_set_from_icon_name (GTK_IMAGE (w), proxy->icon_name, GTK_ICON_SIZE_MENU); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 2); gchar *display_name = strip_accel (proxy->name); w = gtk_label_new (display_name); g_free (display_name); gtk_widget_set_tooltip_text(w, proxy->comment); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 2); GtkWidget *row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (row), box); gtk_widget_show_all (row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), row); } gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), TRUE); g_strfreev (blacklist); } nemo_config_base_widget_set_default_buttons_sensitive (NEMO_CONFIG_BASE_WIDGET (widget), widget->actions != NULL); } static void on_settings_changed (GSettings *settings, gchar *key, gpointer user_data) { NemoActionConfigWidget *w = NEMO_ACTION_CONFIG_WIDGET (user_data); refresh_widget (w); } static void on_enable_clicked (GtkWidget *button, NemoActionConfigWidget *widget) { g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS, NULL); } static void on_disable_clicked (GtkWidget *button, NemoActionConfigWidget *widget) { GPtrArray *new_list = g_ptr_array_new (); GList *l; for (l = widget->actions; l != NULL; l = l->next) g_ptr_array_add (new_list, g_strdup (((ActionProxy *) l->data)->filename)); g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS, (const gchar * const *) new_list_ptr); g_strfreev (new_list_ptr); } static void on_open_folder_clicked (GtkWidget *button, NemoActionConfigWidget *widget) { gchar *path = NULL; path = g_build_filename (g_get_user_data_dir (), "nemo", "actions", NULL); GFile *location = g_file_new_for_path (path); nemo_application_open_location (nemo_application_get_singleton (), location, NULL, "nemo", FALSE); g_free (path); g_object_unref (location); } static void on_dir_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { NemoActionConfigWidget *widget = NEMO_ACTION_CONFIG_WIDGET (user_data); refresh_widget (widget); } static void try_monitor_path (NemoActionConfigWidget *widget, const gchar *path) { GFile *dir = g_file_new_for_path (path); GFileMonitor *mon = g_file_monitor_directory (dir, G_FILE_MONITOR_SEND_MOVED, NULL, NULL); g_object_unref (dir); if (mon != NULL) { g_signal_connect (mon, "changed", G_CALLBACK (on_dir_changed), widget); widget->dir_monitors = g_list_append (widget->dir_monitors, mon); } } static void setup_dir_monitors (NemoActionConfigWidget *widget) { widget->dir_monitors = NULL; gchar **data_dirs = (gchar **) g_get_system_data_dirs (); guint i; for (i = 0; i < g_strv_length (data_dirs); i++) { gchar *path = g_build_filename (data_dirs[i], "nemo", "actions", NULL); try_monitor_path (widget, path); g_free (path); } gchar *path = nemo_action_manager_get_user_directory_path (); try_monitor_path (widget, path); g_free (path); } static void nemo_action_config_widget_finalize (GObject *object) { NemoActionConfigWidget *widget = NEMO_ACTION_CONFIG_WIDGET (object); if (widget->actions != NULL) { g_list_free_full (widget->actions, (GDestroyNotify) action_proxy_free); widget->actions = NULL; } GList *l; for (l = widget->dir_monitors; l != NULL; l = l->next) { g_file_monitor_cancel (l->data); g_object_unref (l->data); } g_list_free (widget->dir_monitors); g_signal_handler_disconnect (nemo_plugin_preferences, widget->bl_handler); G_OBJECT_CLASS (nemo_action_config_widget_parent_class)->finalize (object); } static void nemo_action_config_widget_class_init (NemoActionConfigWidgetClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_action_config_widget_finalize; } static void nemo_action_config_widget_init (NemoActionConfigWidget *self) { self->actions = NULL; self->bl_handler = g_signal_connect (nemo_plugin_preferences, "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_ACTIONS, G_CALLBACK (on_settings_changed), self); GtkWidget *label = nemo_config_base_widget_get_label (NEMO_CONFIG_BASE_WIDGET (self)); gchar *title = g_strdup (_("Actions")); gchar *markup = g_strdup_printf ("%s", title); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (title); g_free (markup); GtkWidget *widget = gtk_button_new_from_icon_name ("folder", GTK_ICON_SIZE_BUTTON); GtkWidget *bb = nemo_config_base_widget_get_buttonbox (NEMO_CONFIG_BASE_WIDGET (self)); gtk_box_pack_end (GTK_BOX (bb), widget, FALSE, FALSE, 0); gtk_widget_show (widget); g_signal_connect (widget, "clicked", G_CALLBACK (on_open_folder_clicked), self); g_signal_connect (nemo_config_base_widget_get_enable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_enable_clicked), self); g_signal_connect (nemo_config_base_widget_get_disable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_disable_clicked), self); g_signal_connect (NEMO_CONFIG_BASE_WIDGET (self)->listbox, "row-activated", G_CALLBACK (on_row_activated), self); refresh_widget (self); setup_dir_monitors (self); } GtkWidget * nemo_action_config_widget_new (void) { return g_object_new (NEMO_TYPE_ACTION_CONFIG_WIDGET, NULL); } nemo-4.4.2/src/nemo-action-config-widget.h000066400000000000000000000031331357442400300203560ustar00rootroot00000000000000/* nemo-action-config-widget.h */ /* A widget that displays a list of actions to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #ifndef __NEMO_ACTION_CONFIG_WIDGET_H__ #define __NEMO_ACTION_CONFIG_WIDGET_H__ #include #include #include #include "nemo-config-base-widget.h" G_BEGIN_DECLS #define NEMO_TYPE_ACTION_CONFIG_WIDGET (nemo_action_config_widget_get_type()) #define NEMO_ACTION_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ACTION_CONFIG_WIDGET, NemoActionConfigWidget)) #define NEMO_ACTION_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ACTION_CONFIG_WIDGET, NemoActionConfigWidgetClass)) #define NEMO_IS_ACTION_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ACTION_CONFIG_WIDGET)) #define NEMO_IS_ACTION_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ACTION_CONFIG_WIDGET)) #define NEMO_ACTION_CONFIG_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ACTION_CONFIG_WIDGET, NemoActionConfigWidgetClass)) typedef struct _NemoActionConfigWidget NemoActionConfigWidget; typedef struct _NemoActionConfigWidgetClass NemoActionConfigWidgetClass; struct _NemoActionConfigWidget { NemoConfigBaseWidget parent; GList *actions; GList *dir_monitors; gulong bl_handler; }; struct _NemoActionConfigWidgetClass { NemoConfigBaseWidgetClass parent_class; }; GType nemo_action_config_widget_get_type (void); GtkWidget *nemo_action_config_widget_new (void); G_END_DECLS #endif /* __NEMO_ACTION_CONFIG_WIDGET_H__ */ nemo-4.4.2/src/nemo-actions.h000066400000000000000000000274471357442400300160330ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 2004 Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Alexander Larsson * */ #ifndef NEMO_ACTIONS_H #define NEMO_ACTIONS_H #include #define NEMO_ACTION_STOP "Stop" #define NEMO_ACTION_RELOAD "Reload" #define NEMO_ACTION_BACK "Back" #define NEMO_ACTION_COMPUTER "Computer" #define NEMO_ACTION_UP "Up" #define NEMO_ACTION_UP_ACCEL "UpAccel" #define NEMO_ACTION_UP_ACCEL "UpAccel" #define NEMO_ACTION_FORWARD "Forward" #define NEMO_ACTION_SHOW_HIDE_TOOLBAR "Show Hide Toolbar" #define NEMO_ACTION_SHOW_HIDE_SIDEBAR "Show Hide Sidebar" #define NEMO_ACTION_SHOW_HIDE_STATUSBAR "Show Hide Statusbar" #define NEMO_ACTION_SHOW_HIDE_MENUBAR "Show Hide Menubar" #define NEMO_ACTION_SHOW_HIDE_LOCATION_BAR "Show Hide Location Bar" #define NEMO_ACTION_SHOW_HIDE_EXTRA_PANE "Show Hide Extra Pane" #define NEMO_ACTION_SHOW_HIDE_LOCATION_ENTRY "Show Hide Location Entry" #define NEMO_ACTION_GO_TO_BURN_CD "Go to Burn CD" #define NEMO_ACTION_EDIT_LOCATION "Edit Location" #define NEMO_ACTION_COMPACT_VIEW "CompactView" #define NEMO_ACTION_ICON_VIEW "IconView" #define NEMO_ACTION_LIST_VIEW "ListView" #define NEMO_ACTION_GO_HOME "Home" #define NEMO_ACTION_ADD_BOOKMARK "Add Bookmark" #define NEMO_ACTION_EDIT_BOOKMARKS "Edit Bookmarks" #define NEMO_ACTION_HOME "Home" #define NEMO_ACTION_ZOOM_IN "Zoom In" #define NEMO_ACTION_ZOOM_OUT "Zoom Out" #define NEMO_ACTION_ZOOM_NORMAL "Zoom Normal" #define NEMO_ACTION_SHOW_HIDDEN_FILES "Show Hidden Files" #define NEMO_ACTION_CLOSE "Close" #define NEMO_ACTION_SEARCH "Search" #define NEMO_ACTION_FOLDER_WINDOW "Folder Window" #define NEMO_ACTION_NEW_TAB "New Tab" #define NEMO_ACTION_OPEN "Open" #define NEMO_ACTION_OPEN_ALTERNATE "OpenAlternate" #define NEMO_ACTION_OPEN_IN_NEW_TAB "OpenInNewTab" #define NEMO_ACTION_LOCATION_OPEN_ALTERNATE "LocationOpenAlternate" #define NEMO_ACTION_LOCATION_OPEN_IN_NEW_TAB "LocationOpenInNewTab" #define NEMO_ACTION_OTHER_APPLICATION1 "OtherApplication1" #define NEMO_ACTION_OTHER_APPLICATION2 "OtherApplication2" #define NEMO_ACTION_NEW_FOLDER "New Folder" #define NEMO_ACTION_PROPERTIES "Properties" #define NEMO_ACTION_PROPERTIES_ACCEL "PropertiesAccel" #define NEMO_ACTION_LOCATION_PROPERTIES "LocationProperties" #define NEMO_ACTION_NO_TEMPLATES "No Templates" #define NEMO_ACTION_EMPTY_TRASH "Empty Trash" #define NEMO_ACTION_SAVE_SEARCH "Save Search" #define NEMO_ACTION_SAVE_SEARCH_AS "Save Search As" #define NEMO_ACTION_CUT "Cut" #define NEMO_ACTION_LOCATION_CUT "LocationCut" #define NEMO_ACTION_COPY "Copy" #define NEMO_ACTION_LOCATION_COPY "LocationCopy" #define NEMO_ACTION_PASTE "Paste" #define NEMO_ACTION_PASTE_FILES_INTO "Paste Files Into" #define NEMO_ACTION_COPY_TO_NEXT_PANE "Copy to next pane" #define NEMO_ACTION_MOVE_TO_NEXT_PANE "Move to next pane" #define NEMO_ACTION_COPY_TO_HOME "Copy to Home" #define NEMO_ACTION_MOVE_TO_HOME "Move to Home" #define NEMO_ACTION_COPY_TO_DESKTOP "Copy to Desktop" #define NEMO_ACTION_MOVE_TO_DESKTOP "Move to Desktop" #define NEMO_ACTION_BROWSE_MOVE_TO "BrowseMoveTo" #define NEMO_ACTION_BROWSE_COPY_TO "BrowseCopyTo" #define NEMO_ACTION_COPY_TO_MENU "CopyToMenu" #define NEMO_ACTION_MOVE_TO_MENU "MoveToMenu" #define NEMO_ACTION_LOCATION_PASTE_FILES_INTO "LocationPasteFilesInto" #define NEMO_ACTION_RENAME "Rename" #define NEMO_ACTION_DUPLICATE "Duplicate" #define NEMO_ACTION_CREATE_LINK "Create Link" #define NEMO_ACTION_SELECT_ALL "Select All" #define NEMO_ACTION_INVERT_SELECTION "Invert Selection" #define NEMO_ACTION_SELECT_PATTERN "Select Pattern" #define NEMO_ACTION_TRASH "Trash" #define NEMO_ACTION_LOCATION_TRASH "LocationTrash" #define NEMO_ACTION_DELETE "Delete" #define NEMO_ACTION_LOCATION_DELETE "LocationDelete" #define NEMO_ACTION_RESTORE_FROM_TRASH "Restore From Trash" #define NEMO_ACTION_LOCATION_RESTORE_FROM_TRASH "LocationRestoreFromTrash" #define NEMO_ACTION_CONNECT_TO_SERVER_LINK "Connect To Server Link" #define NEMO_ACTION_MOUNT_VOLUME "Mount Volume" #define NEMO_ACTION_UNMOUNT_VOLUME "Unmount Volume" #define NEMO_ACTION_EJECT_VOLUME "Eject Volume" #define NEMO_ACTION_START_VOLUME "Start Volume" #define NEMO_ACTION_STOP_VOLUME "Stop Volume" #define NEMO_ACTION_POLL "Poll" #define NEMO_ACTION_SELF_MOUNT_VOLUME "Self Mount Volume" #define NEMO_ACTION_SELF_UNMOUNT_VOLUME "Self Unmount Volume" #define NEMO_ACTION_SELF_EJECT_VOLUME "Self Eject Volume" #define NEMO_ACTION_SELF_START_VOLUME "Self Start Volume" #define NEMO_ACTION_SELF_STOP_VOLUME "Self Stop Volume" #define NEMO_ACTION_SELF_POLL "Self Poll" #define NEMO_ACTION_LOCATION_MOUNT_VOLUME "Location Mount Volume" #define NEMO_ACTION_LOCATION_UNMOUNT_VOLUME "Location Unmount Volume" #define NEMO_ACTION_LOCATION_EJECT_VOLUME "Location Eject Volume" #define NEMO_ACTION_LOCATION_START_VOLUME "Location Start Volume" #define NEMO_ACTION_LOCATION_STOP_VOLUME "Location Stop Volume" #define NEMO_ACTION_LOCATION_POLL "Location Poll" #define NEMO_ACTION_SCRIPTS "Scripts" #define NEMO_ACTION_ACTIONS "Actions" #define NEMO_ACTION_NEW_DOCUMENTS "New Documents" #define NEMO_ACTION_NEW_EMPTY_DOCUMENT "New Empty Document" #define NEMO_ACTION_EMPTY_TRASH_CONDITIONAL "Empty Trash Conditional" #define NEMO_ACTION_MANUAL_LAYOUT "Manual Layout" #define NEMO_ACTION_REVERSED_ORDER "Reversed Order" #define NEMO_ACTION_CLEAN_UP "Clean Up" #define NEMO_ACTION_KEEP_ALIGNED "Keep Aligned" #define NEMO_ACTION_ARRANGE_ITEMS "Arrange Items" #define NEMO_ACTION_STRETCH "Stretch" #define NEMO_ACTION_UNSTRETCH "Unstretch" #define NEMO_ACTION_ZOOM_ITEMS "Zoom Items" #define NEMO_ACTION_SORT_TRASH_TIME "Sort by Trash Time" #define NEMO_ACTION_OPEN_AS_ROOT "OpenAsRoot" #define NEMO_ACTION_TOGGLE_LOCATION "Toggle Location Button" #define NEMO_ACTION_STATUSBAR_PLACES "Statusbar Places" #define NEMO_ACTION_STATUSBAR_TREEVIEW "Statusbar Treeview" #define NEMO_ACTION_STATUSBAR_SIDEBAR_TOGGLE "Statusbar Sidebar Toggle" #define NEMO_ACTION_OPEN_IN_TERMINAL "OpenInTerminal" #define NEMO_ACTION_FOLLOW_SYMLINK "FollowSymbolicLink" #define NEMO_ACTION_OPEN_CONTAINING_FOLDER "OpenContainingFolder" #define NEMO_ACTION_PLUGIN_MANAGER "NemoPluginManager" #define NEMO_ACTION_SHOW_THUMBNAILS "Show Thumbnails" #define NEMO_ACTION_SHOW_FULL_CONTEXT_MENU "ShowFullContextMenu" #define NEMO_ACTION_PIN_FILE "Pin File" #define NEMO_ACTION_UNPIN_FILE "Unpin File" #define NEMO_ACTION_DESKTOP_OVERLAY "Desktop Overlay" typedef struct { const gchar *action_name; // The action's name const gchar *config_widget_name; // The builder id of the corresponding toggle in preferences // Can be null if the action's should be tied to another // action's visibility. const gchar *ui_path; // The xml path of the item from the ui file const gchar *settings_key;; // The gsettings key corresponding to the menu item's visibility. } ConfigurableMenuItemInfo; static const ConfigurableMenuItemInfo CONFIGURABLE_MENU_ITEM_INFO [] = { // Selection { NEMO_ACTION_OPEN, "selection_menu__open_check", "/selection/Open Placeholder/Open", "selection-menu-open" }, { NEMO_ACTION_OPEN_IN_NEW_TAB, "selection_menu__open_in_new_tab_check", "/selection/Open Placeholder/OpenInNewTab", "selection-menu-open-in-new-tab" }, { NEMO_ACTION_OPEN_ALTERNATE, "selection_menu__open_in_new_window_check", "/selection/Open Placeholder/OpenAlternate", "selection-menu-open-in-new-window" }, { NEMO_ACTION_SCRIPTS, "selection_menu__scripts_check", "/selection/Open Placeholder/Scripts", "selection-menu-scripts" }, { NEMO_ACTION_CUT, "selection_menu__cut_check", "/selection/File Clipboard Actions/Cut", "selection-menu-cut" }, { NEMO_ACTION_COPY, "selection_menu__copy_check", "/selection/File Clipboard Actions/Copy", "selection-menu-copy" }, { NEMO_ACTION_PASTE_FILES_INTO, "selection_menu__paste_check", "/selection/File Clipboard Actions/Paste Files Into", "selection-menu-paste" }, { NEMO_ACTION_DUPLICATE, "selection_menu__duplicate_check", "/selection/File Clipboard Actions/Duplicate", "selection-menu-duplicate" }, { NEMO_ACTION_PIN_FILE, "selection_menu__pin_check", "/selection/File Actions/Pin File", "selection-menu-pin" }, { NEMO_ACTION_UNPIN_FILE, NULL, "/selection/File Actions/Unpin File", "selection-menu-pin" }, { NEMO_ACTION_CREATE_LINK, "selection_menu__make_link_check", "/selection/File Actions/Create Link", "selection-menu-make-link" }, { NEMO_ACTION_RENAME, "selection_menu__rename_check", "/selection/File Actions/Rename", "selection-menu-rename" }, { NEMO_ACTION_COPY_TO_MENU, "selection_menu__copy_to_check", "/selection/File Actions/CopyToMenu", "selection-menu-copy-to" }, { NEMO_ACTION_MOVE_TO_MENU, "selection_menu__move_to_check", "/selection/File Actions/MoveToMenu", "selection-menu-move-to" }, { NEMO_ACTION_OPEN_IN_TERMINAL, "selection_menu__open_in_terminal_check", "/selection/OpenInTerminal", "selection-menu-open-in-terminal" }, { NEMO_ACTION_OPEN_AS_ROOT, "selection_menu__open_as_root_check", "/selection/OpenAsRoot", "selection-menu-open-as-root" }, { NEMO_ACTION_TRASH, "selection_menu__move_to_trash_check", "/selection/Dangerous File Actions/Trash", "selection-menu-move-to-trash" }, { NEMO_ACTION_PROPERTIES, "selection_menu__properties_check", "/selection/Properties", "selection-menu-properties" }, // Background { NEMO_ACTION_NEW_FOLDER, "background_menu__create_new_folder_check", "/background/Before Zoom Items/New Object Items/New Folder", "background-menu-create-new-folder" }, { NEMO_ACTION_SCRIPTS, "background_menu__scripts_check", "/background/Before Zoom Items/New Object Items/Scripts", "background-menu-scripts" }, { NEMO_ACTION_OPEN_IN_TERMINAL, "background_menu__open_in_terminal_check", "/background/Before Zoom Items/OpenInTerminal", "background-menu-open-in-terminal" }, { NEMO_ACTION_OPEN_AS_ROOT, "background_menu__open_as_root_check", "/background/Before Zoom Items/OpenAsRoot", "background-menu-open-as-root" }, { NEMO_ACTION_SHOW_HIDDEN_FILES, "background_menu__show_hidden_files_check", "/background/Before Zoom Items/Show Hidden Files", "background-menu-show-hidden-files" }, { NEMO_ACTION_PASTE, "background_menu__paste_check", "/background/Before Zoom Items/File Clipboard Actions/Paste", "background-menu-paste" }, { NEMO_ACTION_PROPERTIES, "background_menu__properties_check", "/background/Folder Items Placeholder/Properties", "background-menu-properties" }, // Icon View (merged with background) { NEMO_ACTION_ARRANGE_ITEMS, "iconview_menu__arrange_items_check", "/background/Before Zoom Items/View Items/Arrange Items", "iconview-menu-arrange-items" }, { NEMO_ACTION_CLEAN_UP, "iconview_menu__organize_by_name_check", "/background/Before Zoom Items/View Items/Clean Up", "iconview-menu-organize-by-name" }, // Desktop (new) { NEMO_ACTION_DESKTOP_OVERLAY, "desktop_menu__customize_check", "/background/Before Zoom Items/View Items/Desktop Overlay", "desktop-menu-customize" }, }; #define CONFIGURABLE_MENU_ITEM_COUNT (G_N_ELEMENTS (CONFIGURABLE_MENU_ITEM_INFO)) #endif /* NEMO_ACTIONS_H */ nemo-4.4.2/src/nemo-application.c000066400000000000000000000471711357442400300166650ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-application: main Nemo application class. * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2010, Cosimo Cecchi * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee , * Darin Adler * Cosimo Cecchi * */ #include #include "nemo-application.h" #if (defined(ENABLE_EMPTY_VIEW) && ENABLE_EMPTY_VIEW) #include "nemo-empty-view.h" #endif /* ENABLE_EMPTY_VIEW */ #include "nemo-freedesktop-dbus.h" #include "nemo-icon-view.h" #include "nemo-image-properties-page.h" #include "nemo-list-view.h" #include "nemo-previewer.h" #include "nemo-progress-ui-handler.h" #include "nemo-self-check-functions.h" #include "nemo-window.h" #include "nemo-window-bookmarks.h" #include "nemo-window-manage-views.h" #include "nemo-window-private.h" #include "nemo-window-slot.h" #include "nemo-statusbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_APPLICATION #include #include #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #define NEMO_ACCEL_MAP_SAVE_DELAY 30 G_DEFINE_TYPE (NemoApplication, nemo_application, GTK_TYPE_APPLICATION); struct _NemoApplicationPriv { NemoProgressUIHandler *progress_handler; gboolean cache_problem; gboolean ignore_cache_problem; }; static NemoApplication *singleton = NULL; /* Common startup stuff */ /* The saving of the accelerator map was requested */ static gboolean save_of_accel_map_requested = FALSE; static gboolean css_provider_load_from_resource (GtkCssProvider *provider, const char *resource_path, GError **error) { GBytes *data; gboolean retval; data = g_resources_lookup_data (resource_path, 0, error); if (!data) return FALSE; retval = gtk_css_provider_load_from_data (provider, g_bytes_get_data (data, NULL), g_bytes_get_size (data), error); g_bytes_unref (data); return retval; } static gchar * load_file_contents_from_resource (const char *resource_path, GError **error) { GBytes *data; gchar *retval; data = NULL; data = g_resources_lookup_data (resource_path, 0, error); if (!data) { return FALSE; } retval = g_strdup ((gchar *) g_bytes_get_data (data, NULL)); g_bytes_unref (data); return retval; } static void add_css_provider_at_priority (const gchar *rpath, guint priority) { GtkCssProvider *provider; GError *error = NULL; provider = gtk_css_provider_new (); if (!css_provider_load_from_resource (provider, rpath, &error)) { g_warning ("Failed to load fallback css file: %s", error->message); if (error->message != NULL) g_error_free (error); goto out; } gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), priority); out: g_object_unref (provider); } static void add_fallback_mandatory_css_provider (const gchar *theme_name) { GtkCssProvider *current_provider, *fallback_provider; gchar *css, *init_fallback_css, *final_fallback_css; GError *error = NULL; current_provider = gtk_css_provider_get_named (theme_name, NULL); css = gtk_css_provider_to_string (current_provider); init_fallback_css = NULL; if (!g_strstr_len (css, -1, "nemo")) { g_warning ("The theme appears to have no nemo support. Adding some..."); init_fallback_css = load_file_contents_from_resource ("/org/nemo/nemo-style-fallback-mandatory.css", &error); if (!init_fallback_css) { g_warning ("Failed to load fallback mandatory css file: %s", error->message); g_clear_error (&error); goto out; } } else { goto out; } final_fallback_css = NULL; /* Our fallback uses @theme_ prefixed names for colors. If the active theme does also, skip * to apply */ if (g_strstr_len (css, -1, "theme_selected_bg_color")) { final_fallback_css = g_strdup (init_fallback_css); goto apply; } /* Some themes don't prefix colors with theme_ - remove this from our fallback css */ if (g_strstr_len (css, -1, "@define-color selected_bg_color")) { g_warning ("Replacing theme_selected_bg_color with selected_bg_color"); final_fallback_css = eel_str_replace_substring (init_fallback_css, "@theme_", "@"); } else { /* If we can find neither, just bail out */ goto out; } apply: g_free (init_fallback_css); fallback_provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (fallback_provider, final_fallback_css, -1, &error); if (error) { g_warning ("Failed to create a fallback provider: %s", error->message); g_clear_error (&error); goto out; } gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (fallback_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref (fallback_provider); out: g_free (css); } static const char *supported_theme_hints[] = { "mint", "arc", "numix" }; static gboolean is_known_supported_theme (const gchar *theme_name) { gint i; gchar *name; gboolean ret; name = g_utf8_casefold (theme_name, -1); ret = FALSE; for (i = 0; i < G_N_ELEMENTS (supported_theme_hints); i++) { gchar *hint; hint = g_utf8_casefold (supported_theme_hints[i], -1); if (g_strstr_len (name, -1, hint)) { ret = TRUE; } g_free (hint); if (ret) { break; } } g_free (name); return ret; } static void init_icons_and_styles (void) { gchar *theme_name; /* initialize search path for custom icons */ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), NEMO_DATADIR G_DIR_SEPARATOR_S "icons"); gtk_icon_size_register (NEMO_STATUSBAR_ICON_SIZE_NAME, NEMO_STATUSBAR_ICON_SIZE, NEMO_STATUSBAR_ICON_SIZE); add_css_provider_at_priority ("/org/nemo/nemo-style-fallback.css", GTK_STYLE_PROVIDER_PRIORITY_FALLBACK); add_css_provider_at_priority ("/org/nemo/nemo-style-application.css", GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_get (gtk_settings_get_default (), "gtk-theme-name", &theme_name, NULL); if (!is_known_supported_theme (theme_name)) { g_warning ("Current gtk theme is not known to have nemo support (%s) - checking...", theme_name); add_fallback_mandatory_css_provider (theme_name); } g_free (theme_name); } static gboolean save_accel_map (gpointer data) { if (save_of_accel_map_requested) { char *accel_map_filename; accel_map_filename = nemo_get_accel_map_file (); if (accel_map_filename) { gtk_accel_map_save (accel_map_filename); g_free (accel_map_filename); } save_of_accel_map_requested = FALSE; } return FALSE; } static void queue_accel_map_save_callback (GtkAccelMap *object, gchar *accel_path, guint accel_key, GdkModifierType accel_mods, gpointer user_data) { if (!save_of_accel_map_requested) { save_of_accel_map_requested = TRUE; g_timeout_add_seconds (NEMO_ACCEL_MAP_SAVE_DELAY, save_accel_map, NULL); } } static void init_gtk_accels (void) { char *accel_map_filename; /* load accelerator map, and register save callback */ accel_map_filename = nemo_get_accel_map_file (); if (accel_map_filename) { gtk_accel_map_load (accel_map_filename); g_free (accel_map_filename); } g_signal_connect (gtk_accel_map_get (), "changed", G_CALLBACK (queue_accel_map_save_callback), NULL); } static void menu_provider_items_updated_handler (NemoMenuProvider *provider, GtkWidget* parent_window, gpointer data) { g_signal_emit_by_name (nemo_signaller_get_current (), "popup_menu_changed"); } static void init_menu_provider_callback (void) { GList *providers; GList *l; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_MENU_PROVIDER); for (l = providers; l != NULL; l = l->next) { NemoMenuProvider *provider = NEMO_MENU_PROVIDER (l->data); g_signal_connect_after (G_OBJECT (provider), "items_updated", (GCallback)menu_provider_items_updated_handler, NULL); } nemo_module_extension_list_free (providers); } /* end Common Startup Stuff */ gboolean nemo_application_check_required_directory (NemoApplication *application, gchar *path) { gboolean ret; g_assert (NEMO_IS_APPLICATION (application)); ret = TRUE; if (!g_file_test (path, G_FILE_TEST_IS_DIR)) { ret = FALSE; } if (!ret) { char *error_string; const char *detail_string; GtkDialog *dialog; error_string = g_strdup_printf (_("Nemo could not create the required folder \"%s\"."), path); detail_string = _("Before running Nemo, please create the following folder, or " "set permissions such that Nemo can create it."); dialog = eel_show_error_dialog (error_string, detail_string, NULL); /* We need the main event loop so the user has a chance to see the dialog. */ gtk_application_add_window (GTK_APPLICATION (application), GTK_WINDOW (dialog)); g_free (error_string); } g_free (path); return ret; } void nemo_application_open_location (NemoApplication *application, GFile *location, GFile *selection, const char *startup_id, const gboolean open_in_tabs) { NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (application))->open_location (application, location, selection, startup_id, open_in_tabs); } NemoWindow * nemo_application_create_window (NemoApplication *application, GdkScreen *screen) { return NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (application))->create_window (application, screen); } void nemo_application_notify_unmount_done (NemoApplication *application, const gchar *message) { NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (application))->notify_unmount_done (application, message); } void nemo_application_notify_unmount_show (NemoApplication *application, const gchar *message) { NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (application))->notify_unmount_show (application, message); } void nemo_application_close_all_windows (NemoApplication *application) { NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (application))->close_all_windows (application); } static GObject * nemo_application_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *retval; retval = G_OBJECT_CLASS (nemo_application_parent_class)->constructor (type, n_construct_params, construct_params); singleton = NEMO_APPLICATION (retval); g_object_add_weak_pointer (retval, (gpointer) &singleton); return retval; } static void nemo_application_init (NemoApplication *application) { GSimpleAction *action; application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application, NEMO_TYPE_APPLICATION, NemoApplicationPriv); if (g_getenv("NEMO_BENCHMARK_LOADING")) nemo_startup_timer = g_timer_new (); action = g_simple_action_new ("quit", NULL); g_action_map_add_action (G_ACTION_MAP (application), G_ACTION (action)); g_signal_connect_swapped (action, "activate", G_CALLBACK (nemo_application_quit), application); g_object_unref (action); } void nemo_application_quit (NemoApplication *self) { GApplication *app = G_APPLICATION (self); /* Run desktop or -main specific destruction - namely tearing down the * desktop manager before our g_list_foreach below takes out its windows. */ NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (self))->continue_quit (self); GList *windows; windows = gtk_application_get_windows (GTK_APPLICATION (app)); g_list_foreach (windows, (GFunc) gtk_widget_destroy, NULL); /* we have been asked to force quit */ g_application_quit (G_APPLICATION (self)); } static void nemo_application_startup (GApplication *app) { NemoApplication *self = NEMO_APPLICATION (app); /* chain up to the GTK+ implementation early, so gtk_init() * is called for us. */ G_APPLICATION_CLASS (nemo_application_parent_class)->startup (app); /* create an undo manager */ self->undo_manager = nemo_undo_manager_new (); /* initialize preferences and create the global GSettings objects */ nemo_global_preferences_init (); /* Run desktop- or main- specific things */ NEMO_APPLICATION_CLASS (G_OBJECT_GET_CLASS (self))->continue_startup (self); /* register property pages */ nemo_image_properties_page_register (); /* initialize theming */ init_icons_and_styles (); init_gtk_accels (); /* initialize nemo modules */ nemo_module_setup (); /* attach menu-provider module callback */ init_menu_provider_callback (); /* Initialize the UI handler singleton for file operations */ notify_init (GETTEXT_PACKAGE); self->priv->progress_handler = nemo_progress_ui_handler_new (); self->priv->cache_problem = FALSE; self->priv->ignore_cache_problem = FALSE; /* silently do a full check of the cache and fix if running as root. * If running as a normal user, do a quick check, and we'll notify the * user later if there's a problem via an infobar */ if (geteuid () == 0) { if (!gnome_desktop_thumbnail_cache_check_permissions (NULL, FALSE)) gnome_desktop_thumbnail_cache_fix_permissions (); } else { if (!gnome_desktop_thumbnail_cache_check_permissions (NULL, TRUE)) self->priv->cache_problem = TRUE; } } static void nemo_application_quit_mainloop (GApplication *app) { DEBUG ("Quitting mainloop"); nemo_icon_info_clear_caches (); save_accel_map (NULL); nemo_application_notify_unmount_done (NEMO_APPLICATION (app), NULL); G_APPLICATION_CLASS (nemo_application_parent_class)->quit_mainloop (app); } static void nemo_application_window_removed (GtkApplication *app, GtkWindow *window) { NemoPreviewer *previewer; /* chain to parent */ GTK_APPLICATION_CLASS (nemo_application_parent_class)->window_removed (app, window); /* if this was the last window, close the previewer */ if (g_list_length (gtk_application_get_windows (app)) == 0) { previewer = nemo_previewer_get_singleton (); nemo_previewer_call_close (previewer); } } static void nemo_application_class_init (NemoApplicationClass *class) { GObjectClass *object_class; GApplicationClass *application_class; GtkApplicationClass *gtkapp_class; object_class = G_OBJECT_CLASS (class); object_class->constructor = nemo_application_constructor; application_class = G_APPLICATION_CLASS (class); application_class->startup = nemo_application_startup; application_class->quit_mainloop = nemo_application_quit_mainloop; gtkapp_class = GTK_APPLICATION_CLASS (class); gtkapp_class->window_removed = nemo_application_window_removed; g_type_class_add_private (class, sizeof (NemoApplicationPriv)); } NemoApplication * nemo_application_initialize_singleton (GType object_type, const gchar *first_property_name, ...) { NemoApplication *application; va_list var_args; va_start (var_args, first_property_name); application = NEMO_APPLICATION (g_object_new_valist (object_type, first_property_name, var_args)); va_end (var_args); return application; } NemoApplication * nemo_application_get_singleton (void) { return singleton; } void nemo_application_check_thumbnail_cache (NemoApplication *application) { application->priv->cache_problem = !nemo_thumbnail_factory_check_status (); } gboolean nemo_application_get_cache_bad (NemoApplication *application) { return application->priv->cache_problem; } void nemo_application_clear_cache_flag (NemoApplication *application) { application->priv->cache_problem = FALSE; } void nemo_application_set_cache_flag (NemoApplication *application) { application->priv->cache_problem = TRUE; } void nemo_application_ignore_cache_problem (NemoApplication *application) { application->priv->ignore_cache_problem = TRUE; } gboolean nemo_application_get_cache_problem_ignored (NemoApplication *application) { return application->priv->ignore_cache_problem; } nemo-4.4.2/src/nemo-application.h000066400000000000000000000114051357442400300166610ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-application: main Nemo application class. * * Copyright (C) 2000 Red Hat, Inc. * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __NEMO_APPLICATION_H__ #define __NEMO_APPLICATION_H__ #include #include #include #include #include "nemo-window.h" #define NEMO_TYPE_APPLICATION nemo_application_get_type() #define NEMO_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_APPLICATION, NemoApplication)) #define NEMO_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_APPLICATION, NemoApplicationClass)) #define NEMO_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_APPLICATION)) #define NEMO_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_APPLICATION)) #define NEMO_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_APPLICATION, NemoApplicationClass)) typedef struct _NemoApplicationPriv NemoApplicationPriv; typedef struct NemoApplicationClass NemoApplicationClass; typedef struct { GtkApplication parent; NemoUndoManager *undo_manager; NemoApplicationPriv *priv; } NemoApplication; struct NemoApplicationClass { GtkApplicationClass parent_class; void (* continue_startup) (NemoApplication *application); void (* continue_quit) (NemoApplication *application); void (* open_location) (NemoApplication *application, GFile *location, GFile *selection, const char *startup_id, const gboolean open_in_tabs); NemoWindow * (* create_window) (NemoApplication *application, GdkScreen *screen); void (* notify_unmount_done) (NemoApplication *application, const gchar *message); void (* notify_unmount_show) (NemoApplication *application, const gchar *message); void (* close_all_windows) (NemoApplication *application); }; GType nemo_application_get_type (void); NemoApplication *nemo_application_initialize_singleton (GType object_type, const gchar *first_property_name, ...); NemoApplication *nemo_application_get_singleton (void); void nemo_application_quit (NemoApplication *self); NemoWindow * nemo_application_create_window (NemoApplication *application, GdkScreen *screen); void nemo_application_open_location (NemoApplication *application, GFile *location, GFile *selection, const char *startup_id, const gboolean open_in_tabs); void nemo_application_close_all_windows (NemoApplication *self); void nemo_application_notify_unmount_show (NemoApplication *application, const gchar *message); void nemo_application_notify_unmount_done (NemoApplication *application, const gchar *message); gboolean nemo_application_check_required_directory (NemoApplication *application, gchar *path); void nemo_application_check_thumbnail_cache (NemoApplication *application); gboolean nemo_application_get_cache_bad (NemoApplication *application); void nemo_application_clear_cache_flag (NemoApplication *application); void nemo_application_set_cache_flag (NemoApplication *application); void nemo_application_ignore_cache_problem (NemoApplication *application); gboolean nemo_application_get_cache_problem_ignored (NemoApplication *application); gboolean nemo_application_get_show_desktop (NemoApplication *application); #endif /* __NEMO_APPLICATION_H__ */ nemo-4.4.2/src/nemo-autorun-software.c000066400000000000000000000204401357442400300176750ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo Copyright (C) 2008 Red Hat, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: David Zeuthen */ #include #include #include #include #include #include #include #include #include #include typedef struct { GtkWidget *dialog; GMount *mount; } AutorunSoftwareDialogData; static void autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data); static void autorun_software_dialog_destroy (AutorunSoftwareDialogData *data) { g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount), G_CALLBACK (autorun_software_dialog_mount_unmounted), data); gtk_widget_destroy (GTK_WIDGET (data->dialog)); g_object_unref (data->mount); g_free (data); } static void autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data) { autorun_software_dialog_destroy (data); } static gboolean _check_file (GFile *mount_root, const char *file_path, gboolean must_be_executable) { GFile *file; GFileInfo *file_info; gboolean ret; ret = FALSE; file = g_file_get_child (mount_root, file_path); file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (file_info != NULL) { if (must_be_executable) { if (g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) { ret = TRUE; } } else { ret = TRUE; } g_object_unref (file_info); } g_object_unref (file); return ret; } static void autorun (GMount *mount) { char *error_string; GFile *root; GFile *program_to_spawn; GFile *program_parameter_file; char *path_to_spawn; char *cwd_for_program; char *program_parameter; root = g_mount_get_root (mount); /* Careful here, according to * * http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html * * the ordering does matter. */ program_to_spawn = NULL; path_to_spawn = NULL; program_parameter_file = NULL; program_parameter = NULL; if (_check_file (root, ".autorun", TRUE)) { program_to_spawn = g_file_get_child (root, ".autorun"); } else if (_check_file (root, "autorun", TRUE)) { program_to_spawn = g_file_get_child (root, "autorun"); } else if (_check_file (root, "autorun.sh", TRUE)) { program_to_spawn = g_file_new_for_path ("/bin/sh"); program_parameter_file = g_file_get_child (root, "autorun.sh"); } if (program_to_spawn != NULL) { path_to_spawn = g_file_get_path (program_to_spawn); } if (program_parameter_file != NULL) { program_parameter = g_file_get_path (program_parameter_file); } cwd_for_program = g_file_get_path (root); error_string = NULL; if (path_to_spawn != NULL && cwd_for_program != NULL) { if (chdir (cwd_for_program) == 0) { execl (path_to_spawn, path_to_spawn, program_parameter, NULL); error_string = g_strdup_printf (_("Error starting autorun program: %s"), strerror (errno)); goto out; } error_string = g_strdup_printf (_("Error starting autorun program: %s"), strerror (errno)); goto out; } error_string = g_strdup_printf (_("Cannot find the autorun program")); out: if (program_to_spawn != NULL) { g_object_unref (program_to_spawn); } if(program_parameter_file != NULL) { g_object_unref (program_parameter_file); } if (root != NULL) { g_object_unref (root); } g_free (path_to_spawn); g_free (cwd_for_program); g_free (program_parameter); if (error_string != NULL) { GtkWidget *dialog; dialog = gtk_message_dialog_new_with_markup (NULL, /* TODO: parent window? */ 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error autorunning software")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error_string); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (error_string); } } static void present_autorun_for_software_dialog (GMount *mount) { GIcon *icon; int icon_size; NemoIconInfo *icon_info; GdkPixbuf *pixbuf; GtkWidget *image; char *mount_name; GtkWidget *dialog; AutorunSoftwareDialogData *data; mount_name = g_mount_get_name (mount); dialog = gtk_message_dialog_new_with_markup (NULL, /* TODO: parent window? */ 0, GTK_MESSAGE_OTHER, GTK_BUTTONS_CANCEL, _("This medium contains software intended to be automatically started. Would you like to run it?")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("The software will run directly from the medium \"%s\". " "You should never run software that you don't trust.\n" "\n" "If in doubt, press Cancel."), mount_name); /* TODO: in a star trek future add support for verifying * software on media (e.g. if it has a certificate, check it * etc.) */ icon = g_mount_get_icon (mount); icon_size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG); icon_info = nemo_icon_info_lookup (icon, icon_size, gtk_widget_get_scale_factor (GTK_WIDGET (dialog))); pixbuf = nemo_icon_info_get_pixbuf_at_size (icon_info, icon_size); image = gtk_image_new_from_pixbuf (pixbuf); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image); gtk_window_set_title (GTK_WINDOW (dialog), mount_name); gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf); data = g_new0 (AutorunSoftwareDialogData, 1); data->dialog = dialog; data->mount = g_object_ref (mount); g_signal_connect (G_OBJECT (mount), "unmounted", G_CALLBACK (autorun_software_dialog_mount_unmounted), data); gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Run"), GTK_RESPONSE_OK); gtk_widget_show_all (dialog); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { gtk_widget_destroy (dialog); autorun (mount); } nemo_icon_info_unref (icon_info); g_object_unref (pixbuf); g_free (mount_name); } int main (int argc, char *argv[]) { GVolumeMonitor *monitor; GFile *file; GMount *mount; bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); gtk_init (&argc, &argv); if (argc != 2) { goto out; } /* instantiate monitor so we get the "unmounted" signal properly */ monitor = g_volume_monitor_get (); if (monitor == NULL) { goto out; } file = g_file_new_for_commandline_arg (argv[1]); if (file == NULL) { g_object_unref (monitor); goto out; } mount = g_file_find_enclosing_mount (file, NULL, NULL); if (mount == NULL) { g_object_unref (file); g_object_unref (monitor); goto out; } present_autorun_for_software_dialog (mount); g_object_unref (file); g_object_unref (monitor); g_object_unref (mount); out: return 0; } nemo-4.4.2/src/nemo-blank-desktop-window.c000066400000000000000000000310471357442400300204200ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * */ #include #include "nemo-blank-desktop-window.h" #include "nemo-desktop-manager.h" #include #include #include #include #include #include #include #include #include #include #include "nemo-plugin-manager.h" #define DEBUG_FLAG NEMO_DEBUG_DESKTOP #include enum { PROP_MONITOR = 1, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; struct NemoBlankDesktopWindowDetails { gint monitor; GtkWidget *popup_menu; gulong actions_changed_id; }; G_DEFINE_TYPE (NemoBlankDesktopWindow, nemo_blank_desktop_window, GTK_TYPE_WINDOW); static void customize_clicked_callback (GtkMenuItem *item, NemoBlankDesktopWindow *window) { g_return_if_fail (NEMO_IS_BLANK_DESKTOP_WINDOW (window)); nemo_desktop_manager_show_desktop_overlay (nemo_desktop_manager_get (), window->details->monitor); } static void action_activated_callback (GtkMenuItem *item, NemoAction *action) { GFile *desktop_location = nemo_get_desktop_location (); NemoFile *desktop_file = nemo_file_get (desktop_location); g_object_unref (desktop_location); nemo_action_activate (NEMO_ACTION (action), NULL, desktop_file); } static void actions_changed_cb (NemoBlankDesktopWindow *window) { g_clear_pointer (&window->details->popup_menu, gtk_widget_destroy); } static void build_menu (NemoBlankDesktopWindow *window) { if (window->details->popup_menu) { return; } NemoActionManager *desktop_action_manager = nemo_desktop_manager_get_action_manager (); if (window->details->actions_changed_id == 0) { window->details->actions_changed_id = g_signal_connect_swapped (desktop_action_manager, "changed", G_CALLBACK (actions_changed_cb), window); } GList *action_list = nemo_action_manager_list_actions (desktop_action_manager); if (g_list_length (action_list) == 0) return; window->details->popup_menu = gtk_menu_new (); gboolean show; g_object_get (gtk_settings_get_default (), "gtk-menu-images", &show, NULL); gtk_menu_attach_to_widget (GTK_MENU (window->details->popup_menu), GTK_WIDGET (window), NULL); GtkWidget *item; GList *l; NemoAction *action; for (l = action_list; l != NULL; l = l->next) { action = l->data; if (action->show_in_blank_desktop && action->dbus_satisfied && action->gsettings_satisfied) { gchar *label = nemo_action_get_label (action, NULL, NULL); item = gtk_image_menu_item_new_with_mnemonic (label); g_free (label); const gchar *stock_id = gtk_action_get_stock_id (GTK_ACTION (action)); const gchar *icon_name = gtk_action_get_icon_name (GTK_ACTION (action)); if (stock_id || icon_name) { GtkWidget *image = stock_id ? gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU) : gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), show); } gtk_widget_set_visible (item, TRUE); g_signal_connect (item, "activate", G_CALLBACK (action_activated_callback), action); gtk_menu_shell_append (GTK_MENU_SHELL (window->details->popup_menu), item); } } item = gtk_menu_item_new_with_label (_("Customize")); gtk_widget_set_visible (item, TRUE); g_signal_connect (item, "activate", G_CALLBACK (customize_clicked_callback), window); gtk_menu_shell_append (GTK_MENU_SHELL (window->details->popup_menu), item); } static void do_popup_menu (NemoBlankDesktopWindow *window, GdkEventButton *event) { build_menu (window); eel_pop_up_context_menu (GTK_MENU(window->details->popup_menu), event); } static gboolean on_popup_menu (GtkWidget *widget, NemoBlankDesktopWindow *window) { do_popup_menu (window, NULL); return TRUE; } static gboolean on_button_press (GtkWidget *widget, GdkEventButton *event, NemoBlankDesktopWindow *window) { if (event->type != GDK_BUTTON_PRESS) { /* ignore multiple clicks */ return TRUE; } if (event->button == 3) { do_popup_menu (window, event); } return FALSE; } static void nemo_blank_desktop_window_dispose (GObject *obj) { NemoBlankDesktopWindow *window = NEMO_BLANK_DESKTOP_WINDOW (obj); if (window->details->actions_changed_id > 0) { g_signal_handler_disconnect (nemo_desktop_manager_get_action_manager (), window->details->actions_changed_id); window->details->actions_changed_id = 0; } G_OBJECT_CLASS (nemo_blank_desktop_window_parent_class)->dispose (obj); } static void nemo_blank_desktop_window_finalize (GObject *obj) { G_OBJECT_CLASS (nemo_blank_desktop_window_parent_class)->finalize (obj); } static void nemo_blank_desktop_window_constructed (GObject *obj) { AtkObject *accessible; NemoBlankDesktopWindow *window = NEMO_BLANK_DESKTOP_WINDOW (obj); G_OBJECT_CLASS (nemo_blank_desktop_window_parent_class)->constructed (obj); /* Set the accessible name so that it doesn't inherit the cryptic desktop URI. */ accessible = gtk_widget_get_accessible (GTK_WIDGET (window)); if (accessible) { atk_object_set_name (accessible, _("Desktop")); } /* We don't want this extra action manager unless there's actually * a blank desktop in use. If so, however, we need to initialize it early here, * as it populates itself with actions asynchronously, and would not be ready * in build_menu().*/ nemo_desktop_manager_get_action_manager (); nemo_blank_desktop_window_update_geometry (window); gtk_window_set_resizable (GTK_WINDOW (window), FALSE); gtk_window_set_decorated (GTK_WINDOW (window), FALSE); gtk_widget_show_all (GTK_WIDGET (window)); g_signal_connect (GTK_WIDGET (window), "button-press-event", G_CALLBACK (on_button_press), window); g_signal_connect (GTK_WIDGET (window), "popup-menu", G_CALLBACK (on_popup_menu), window); } static void nemo_blank_desktop_window_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoBlankDesktopWindow *window = NEMO_BLANK_DESKTOP_WINDOW (object); switch (property_id) { case PROP_MONITOR: g_value_set_int (value, window->details->monitor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_blank_desktop_window_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoBlankDesktopWindow *window = NEMO_BLANK_DESKTOP_WINDOW (object); switch (property_id) { case PROP_MONITOR: window->details->monitor = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_blank_desktop_window_init (NemoBlankDesktopWindow *window) { window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_BLANK_DESKTOP_WINDOW, NemoBlankDesktopWindowDetails); window->details->popup_menu = NULL; window->details->actions_changed_id = 0; /* Make it easier for themes authors to style the desktop window separately */ gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "nemo-desktop-window"); } NemoBlankDesktopWindow * nemo_blank_desktop_window_new (gint monitor) { NemoBlankDesktopWindow *window; window = g_object_new (NEMO_TYPE_BLANK_DESKTOP_WINDOW, "monitor", monitor, NULL); GdkRGBA transparent = {0, 0, 0, 0}; gtk_widget_override_background_color (GTK_WIDGET (window), 0, &transparent); return window; } static gboolean nemo_blank_desktop_window_delete_event (GtkWidget *widget, GdkEventAny *event) { /* Returning true tells GTK+ not to delete the window. */ return TRUE; } static void map (GtkWidget *widget) { /* Chain up to realize our children */ GTK_WIDGET_CLASS (nemo_blank_desktop_window_parent_class)->map (widget); gdk_window_lower (gtk_widget_get_window (widget)); GdkWindow *window; GdkRGBA transparent = { 0, 0, 0, 0 }; window = gtk_widget_get_window (widget); gdk_window_set_background_rgba (window, &transparent); } static void unrealize (GtkWidget *widget) { GTK_WIDGET_CLASS (nemo_blank_desktop_window_parent_class)->unrealize (widget); } static void set_wmspec_desktop_hint (GdkWindow *window) { GdkAtom atom; atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE); gdk_property_change (window, gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE), gdk_x11_xatom_to_atom (XA_ATOM), 32, GDK_PROP_MODE_REPLACE, (guchar *) &atom, 1); } static void realize (GtkWidget *widget) { GdkVisual *visual; visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (widget)); if (visual) { gtk_widget_set_visual (widget, visual); } GTK_WIDGET_CLASS (nemo_blank_desktop_window_parent_class)->realize (widget); /* This is the new way to set up the desktop window */ set_wmspec_desktop_hint (gtk_widget_get_window (widget)); } static void nemo_blank_desktop_window_class_init (NemoBlankDesktopWindowClass *klass) { GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->constructed = nemo_blank_desktop_window_constructed; oclass->dispose = nemo_blank_desktop_window_dispose; oclass->finalize = nemo_blank_desktop_window_finalize; oclass->set_property = nemo_blank_desktop_window_set_property; oclass->get_property = nemo_blank_desktop_window_get_property; wclass->realize = realize; wclass->unrealize = unrealize; wclass->map = map; wclass->delete_event = nemo_blank_desktop_window_delete_event; properties[PROP_MONITOR] = g_param_spec_int ("monitor", "Monitor number", "The monitor number this window is assigned to", G_MININT, G_MAXINT, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_type_class_add_private (klass, sizeof (NemoBlankDesktopWindowDetails)); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } void nemo_blank_desktop_window_update_geometry (NemoBlankDesktopWindow *window) { GdkRectangle rect; nemo_desktop_manager_get_window_rect_for_monitor (nemo_desktop_manager_get (), window->details->monitor, &rect); DEBUG ("NemoBlankDesktopWindow monitor:%d: x:%d, y:%d, w:%d, h:%d", window->details->monitor, rect.x, rect.y, rect.width, rect.height); gtk_window_move (GTK_WINDOW (window), rect.x, rect.y); gtk_widget_set_size_request (GTK_WIDGET (window), rect.width, rect.height); } nemo-4.4.2/src/nemo-blank-desktop-window.h000066400000000000000000000046061357442400300204260ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * */ /* nemo-blank-desktop-window.h */ #ifndef NEMO_BLANK_DESKTOP_WINDOW_H #define NEMO_BLANK_DESKTOP_WINDOW_H #include #include #define NEMO_TYPE_BLANK_DESKTOP_WINDOW nemo_blank_desktop_window_get_type() #define NEMO_BLANK_DESKTOP_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_BLANK_DESKTOP_WINDOW, NemoBlankDesktopWindow)) #define NEMO_BLANK_DESKTOP_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_BLANK_DESKTOP_WINDOW, NemoBlankDesktopWindowClass)) #define NEMO_IS_BLANK_DESKTOP_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_BLANK_DESKTOP_WINDOW)) #define NEMO_IS_BLANK_DESKTOP_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_BLANK_DESKTOP_WINDOW)) #define NEMO_BLANK_DESKTOP_WINDOW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_BLANK_DESKTOP_WINDOW, NemoBlankDesktopWindowClass)) typedef struct NemoBlankDesktopWindowDetails NemoBlankDesktopWindowDetails; typedef struct { GtkWindow parent_spot; NemoBlankDesktopWindowDetails *details; } NemoBlankDesktopWindow; typedef struct { GtkWindowClass parent_spot; void (* plugin_manager) (NemoBlankDesktopWindow *window); } NemoBlankDesktopWindowClass; GType nemo_blank_desktop_window_get_type (void); NemoBlankDesktopWindow *nemo_blank_desktop_window_new (gint monitor); NemoActionManager *nemo_desktop_manager_get_action_manager (void); void nemo_blank_desktop_window_update_geometry (NemoBlankDesktopWindow *window); #endif /* NEMO_BLANK_DESKTOP_WINDOW_H */ nemo-4.4.2/src/nemo-bookmark-list.c000066400000000000000000000731131357442400300171330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: John Sullivan */ /* nemo-bookmark-list.c - implementation of centralized list of bookmarks. */ #include #include "nemo-bookmark-list.h" #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include #define MAX_BOOKMARK_LENGTH 80 #define LOAD_JOB 1 #define SAVE_JOB 2 #define KEY_ICON_URI "IconUri" #define KEY_ICON_NAME "IconName" #define KEY_ICON_EMBLEMS "IconEmblems" enum { CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static char *window_geometry; static NemoBookmarkList *singleton = NULL; /* forward declarations */ static void nemo_bookmark_list_load_file (NemoBookmarkList *bookmarks); static void nemo_bookmark_list_save_file (NemoBookmarkList *bookmarks); G_DEFINE_TYPE(NemoBookmarkList, nemo_bookmark_list, G_TYPE_OBJECT); static void ensure_proper_file_permissions (GFile *file) { if (geteuid () == 0) { struct passwd *pwent; pwent = gnome_desktop_get_session_user_pwent (); gchar *path = g_file_get_path (file); if (g_strcmp0 (pwent->pw_dir, g_get_home_dir ()) == 0) { G_GNUC_UNUSED int res; res = chown (path, pwent->pw_uid, pwent->pw_gid); } g_free (path); } } static NemoBookmark * new_bookmark_from_uri (const char *uri, const char *label, NemoBookmarkMetadata *md) { NemoBookmark *new_bookmark; GFile *location; location = NULL; if (uri) { location = g_file_new_for_uri (uri); } new_bookmark = NULL; if (location) { new_bookmark = nemo_bookmark_new (location, label, NULL, md); g_object_unref (location); } return new_bookmark; } static GFile * nemo_bookmark_list_get_legacy_file (void) { char *filename; GFile *file; filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL); file = g_file_new_for_path (filename); g_free (filename); return file; } static GFile * nemo_bookmark_list_get_file (void) { char *filename; GFile *file; filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL); file = g_file_new_for_path (filename); g_free (filename); return file; } /* Initialization. */ static void bookmark_in_list_changed_callback (NemoBookmark *bookmark, NemoBookmarkList *bookmarks) { g_assert (NEMO_IS_BOOKMARK (bookmark)); g_assert (NEMO_IS_BOOKMARK_LIST (bookmarks)); /* save changes to the list */ nemo_bookmark_list_save_file (bookmarks); } static gboolean idle_notify (NemoBookmarkList *bookmarks) { g_signal_emit (bookmarks, signals[CHANGED], 0); bookmarks->idle_notify_id = 0; return FALSE; } static void bookmark_in_list_notify (GObject *object, GParamSpec *pspec, NemoBookmarkList *bookmarks) { /* emit the changed signal without saving, as only appearance properties changed */ if (bookmarks->idle_notify_id > 0) { g_source_remove (bookmarks->idle_notify_id); bookmarks->idle_notify_id = 0; } bookmarks->idle_notify_id = g_idle_add ((GSourceFunc) idle_notify, bookmarks); } static gboolean bookmark_location_mounted_callback (NemoBookmark *bookmark, GFile *location, NemoBookmarkList *bookmarks) { gboolean ret = FALSE; GList *volumes = g_volume_monitor_get_mounts (bookmarks->volume_monitor); GList *iter = volumes; while (iter != NULL) { GMount *mount = G_MOUNT (iter->data); GFile *mount_location = g_mount_get_root (mount); gchar *mount_root_uri = g_file_get_uri (mount_location); gchar *location_uri = g_file_get_uri (location); ret = g_str_has_prefix (location_uri, mount_root_uri); g_free (mount_root_uri); g_free (location_uri); g_object_unref (mount_location); if (ret == TRUE) break; iter = iter->next; } g_list_free_full (volumes, (GDestroyNotify) g_object_unref); return ret; } static void stop_monitoring_bookmark (NemoBookmarkList *bookmarks, NemoBookmark *bookmark) { g_signal_handlers_disconnect_by_func (bookmark, bookmark_in_list_changed_callback, bookmarks); g_signal_handlers_disconnect_by_func (bookmark, bookmark_location_mounted_callback, bookmarks); } static void stop_monitoring_one (gpointer data, gpointer user_data) { g_assert (NEMO_IS_BOOKMARK (data)); g_assert (NEMO_IS_BOOKMARK_LIST (user_data)); stop_monitoring_bookmark (NEMO_BOOKMARK_LIST (user_data), NEMO_BOOKMARK (data)); } static void clear_bookmarks (NemoBookmarkList *bookmarks, GList *list) { g_list_foreach (list, stop_monitoring_one, bookmarks); g_list_free_full (list, g_object_unref); list = NULL; } static void do_finalize (GObject *object) { if (NEMO_BOOKMARK_LIST (object)->monitor != NULL) { g_file_monitor_cancel (NEMO_BOOKMARK_LIST (object)->monitor); NEMO_BOOKMARK_LIST (object)->monitor = NULL; } g_queue_free (NEMO_BOOKMARK_LIST (object)->pending_ops); clear_bookmarks (NEMO_BOOKMARK_LIST (object), NEMO_BOOKMARK_LIST (object)->list); g_object_unref (NEMO_BOOKMARK_LIST (object)->volume_monitor); G_OBJECT_CLASS (nemo_bookmark_list_parent_class)->finalize (object); } static GObject * do_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *retval; if (singleton != NULL) { return g_object_ref (G_OBJECT (singleton)); } retval = G_OBJECT_CLASS (nemo_bookmark_list_parent_class)->constructor (type, n_construct_params, construct_params); singleton = NEMO_BOOKMARK_LIST (retval); g_object_add_weak_pointer (retval, (gpointer) &singleton); return retval; } static void do_constructed (GObject *object) { G_OBJECT_CLASS (nemo_bookmark_list_parent_class)->constructed (object); nemo_bookmark_list_load_file (NEMO_BOOKMARK_LIST (object)); } static void nemo_bookmark_list_class_init (NemoBookmarkListClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->finalize = do_finalize; object_class->constructor = do_constructor; object_class->constructed = do_constructed; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoBookmarkListClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void bookmark_monitor_changed_cb (GFileMonitor *monitor, GFile *child, GFile *other_file, GFileMonitorEvent eflags, gpointer user_data) { if (eflags == G_FILE_MONITOR_EVENT_CHANGED || eflags == G_FILE_MONITOR_EVENT_CREATED) { g_return_if_fail (NEMO_IS_BOOKMARK_LIST (NEMO_BOOKMARK_LIST (user_data))); nemo_bookmark_list_load_file (NEMO_BOOKMARK_LIST (user_data)); } } static void volume_monitor_activity_cb (GVolumeMonitor *monitor, GMount *mount, gpointer user_data) { NemoBookmarkList *bookmarks = NEMO_BOOKMARK_LIST (user_data); nemo_bookmark_list_load_file (bookmarks); } static void nemo_bookmark_list_init (NemoBookmarkList *bookmarks) { GFile *file; bookmarks->list = NULL; bookmarks->idle_notify_id = 0; bookmarks->pending_ops = g_queue_new (); file = nemo_bookmark_list_get_file (); bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL); g_file_monitor_set_rate_limit (bookmarks->monitor, 1000); g_signal_connect (bookmarks->monitor, "changed", G_CALLBACK (bookmark_monitor_changed_cb), bookmarks); g_object_unref (file); bookmarks->volume_monitor = g_volume_monitor_get (); g_signal_connect (bookmarks->volume_monitor, "mount-added", G_CALLBACK (volume_monitor_activity_cb), bookmarks); g_signal_connect (bookmarks->volume_monitor, "mount-removed", G_CALLBACK (volume_monitor_activity_cb), bookmarks); g_signal_connect (bookmarks->volume_monitor, "mount-changed", G_CALLBACK (volume_monitor_activity_cb), bookmarks); } static void connect_bookmark_signals (NemoBookmark *bookmark, NemoBookmarkList *bookmarks) { g_signal_connect_object (bookmark, "location-mounted", G_CALLBACK (bookmark_location_mounted_callback), bookmarks, 0); g_signal_connect_object (bookmark, "contents-changed", G_CALLBACK (bookmark_in_list_changed_callback), bookmarks, 0); g_signal_connect_object (bookmark, "notify::icon-name", G_CALLBACK (bookmark_in_list_notify), bookmarks, 0); g_signal_connect_object (bookmark, "notify::name", G_CALLBACK (bookmark_in_list_notify), bookmarks, 0); nemo_bookmark_connect (bookmark); } static void insert_bookmark_internal (NemoBookmarkList *bookmarks, NemoBookmark *bookmark, int index) { bookmarks->list = g_list_insert (bookmarks->list, bookmark, index); connect_bookmark_signals (bookmark, bookmarks); } /** * nemo_bookmark_list_append: * * Append a bookmark to a bookmark list. * @bookmarks: NemoBookmarkList to append to. * @bookmark: Bookmark to append a copy of. **/ void nemo_bookmark_list_append (NemoBookmarkList *bookmarks, NemoBookmark *bookmark) { g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); g_return_if_fail (NEMO_IS_BOOKMARK (bookmark)); insert_bookmark_internal (bookmarks, nemo_bookmark_copy (bookmark), -1); nemo_bookmark_list_save_file (bookmarks); } /** * nemo_bookmark_list_contains: * * Check whether a bookmark with matching name and url is already in the list. * @bookmarks: NemoBookmarkList to check contents of. * @bookmark: NemoBookmark to match against. * * Return value: TRUE if matching bookmark is in list, FALSE otherwise **/ gboolean nemo_bookmark_list_contains (NemoBookmarkList *bookmarks, NemoBookmark *bookmark) { g_return_val_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks), FALSE); g_return_val_if_fail (NEMO_IS_BOOKMARK (bookmark), FALSE); return g_list_find_custom (bookmarks->list, (gpointer)bookmark, nemo_bookmark_compare_with) != NULL; } /** * nemo_bookmark_list_delete_item_at: * * Delete the bookmark at the specified position. * @bookmarks: the list of bookmarks. * @index: index, must be less than length of list. **/ void nemo_bookmark_list_delete_item_at (NemoBookmarkList *bookmarks, guint index) { GList *doomed; g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); g_return_if_fail (index < g_list_length (bookmarks->list)); doomed = g_list_nth (bookmarks->list, index); g_return_if_fail (doomed != NULL); bookmarks->list = g_list_remove_link (bookmarks->list, doomed); g_assert (NEMO_IS_BOOKMARK (doomed->data)); stop_monitoring_bookmark (bookmarks, NEMO_BOOKMARK (doomed->data)); g_object_unref (doomed->data); g_list_free_1 (doomed); nemo_bookmark_list_save_file (bookmarks); } /** * nemo_bookmark_list_move_item: * * Move the item from the given position to the destination. * @index: the index of the first bookmark. * @destination: the index of the second bookmark. **/ void nemo_bookmark_list_move_item (NemoBookmarkList *bookmarks, guint index, guint destination) { GList *bookmark_item; if (index == destination) { return; } bookmark_item = g_list_nth (bookmarks->list, index); g_return_if_fail (bookmark_item != NULL); bookmarks->list = g_list_remove_link (bookmarks->list, bookmark_item); if (index < destination) { bookmarks->list = g_list_insert (bookmarks->list, bookmark_item->data, destination - 1); } else { bookmarks->list = g_list_insert (bookmarks->list, bookmark_item->data, destination); } nemo_bookmark_list_save_file (bookmarks); } static gint nemo_bookmark_list_compare_func (gconstpointer a, gconstpointer b) { g_assert (NEMO_IS_BOOKMARK (a)); g_assert (NEMO_IS_BOOKMARK (b)); return g_utf8_collate (nemo_bookmark_get_name (NEMO_BOOKMARK (a)), nemo_bookmark_get_name (NEMO_BOOKMARK (b))); } /** * nemo_bookmark_list_sort_ascending: * * Sort bookmarks in ascending order. * @bookmarks: the list of bookmarks. **/ void nemo_bookmark_list_sort_ascending (NemoBookmarkList *bookmarks) { g_assert (NEMO_IS_BOOKMARK_LIST (bookmarks)); bookmarks->list = g_list_sort ( bookmarks->list, (GCompareFunc)nemo_bookmark_list_compare_func); /* Save bookmarks to file. This will also inform widgets about the changes * we just made to the list. */ nemo_bookmark_list_save_file (bookmarks); } /** * nemo_bookmark_list_delete_items_with_uri: * * Delete all bookmarks with the given uri. * @bookmarks: the list of bookmarks. * @uri: The uri to match. **/ void nemo_bookmark_list_delete_items_with_uri (NemoBookmarkList *bookmarks, const char *uri) { GList *node, *next; gboolean list_changed; char *bookmark_uri; g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); g_return_if_fail (uri != NULL); list_changed = FALSE; for (node = bookmarks->list; node != NULL; node = next) { next = node->next; bookmark_uri = nemo_bookmark_get_uri (NEMO_BOOKMARK (node->data)); if (g_strcmp0 (bookmark_uri, uri) == 0) { bookmarks->list = g_list_remove_link (bookmarks->list, node); stop_monitoring_bookmark (bookmarks, NEMO_BOOKMARK (node->data)); g_object_unref (node->data); g_list_free_1 (node); list_changed = TRUE; } g_free (bookmark_uri); } if (list_changed) { nemo_bookmark_list_save_file (bookmarks); } } /** * nemo_bookmark_list_get_window_geometry: * * Get a string representing the bookmark_list's window's geometry. * This is the value set earlier by nemo_bookmark_list_set_window_geometry. * @bookmarks: the list of bookmarks associated with the window. * Return value: string representation of window's geometry, suitable for * passing to gnome_parse_geometry(), or NULL if * no window geometry has yet been saved for this bookmark list. **/ const char * nemo_bookmark_list_get_window_geometry (NemoBookmarkList *bookmarks) { return window_geometry; } /** * nemo_bookmark_list_insert_item: * * Insert a bookmark at a specified position. * @bookmarks: the list of bookmarks. * @index: the position to insert the bookmark at. * @new_bookmark: the bookmark to insert a copy of. **/ void nemo_bookmark_list_insert_item (NemoBookmarkList *bookmarks, NemoBookmark *new_bookmark, guint index) { g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); g_return_if_fail (index <= g_list_length (bookmarks->list)); insert_bookmark_internal (bookmarks, nemo_bookmark_copy (new_bookmark), index); nemo_bookmark_list_save_file (bookmarks); } GList * nemo_bookmark_list_get_for_uri (NemoBookmarkList *bookmarks, const char *uri) { g_return_val_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks), NULL); GList *iter; GList *results = NULL; NemoBookmark *bookmark; for (iter = bookmarks->list; iter != NULL; iter = iter->next) { bookmark = iter->data; gchar *bm_uri = nemo_bookmark_get_uri (bookmark); if (g_strcmp0 (uri, bm_uri) == 0) { results = g_list_append (results, bookmark); } g_free (bm_uri); } return results; } /** * nemo_bookmark_list_item_at: * * Get the bookmark at the specified position. * @bookmarks: the list of bookmarks. * @index: index, must be less than length of list. * * Return value: the bookmark at position @index in @bookmarks. **/ NemoBookmark * nemo_bookmark_list_item_at (NemoBookmarkList *bookmarks, guint index) { g_return_val_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks), NULL); g_return_val_if_fail (index < g_list_length (bookmarks->list), NULL); return NEMO_BOOKMARK (g_list_nth_data (bookmarks->list, index)); } /** * nemo_bookmark_list_length: * * Get the number of bookmarks in the list. * @bookmarks: the list of bookmarks. * * Return value: the length of the bookmark list. **/ guint nemo_bookmark_list_length (NemoBookmarkList *bookmarks) { g_return_val_if_fail (NEMO_IS_BOOKMARK_LIST(bookmarks), 0); return g_list_length (bookmarks->list); } static GList * load_bookmark_metadata_file (NemoBookmarkList *list) { /* Part of load_files thread */ GError *error = NULL; GKeyFile *kfile = g_key_file_new (); GList *ret = NULL; gchar *filename; filename = g_build_filename (g_get_user_config_dir (), "nemo", "bookmark-metadata", NULL); if (g_key_file_load_from_file (kfile, filename, G_KEY_FILE_NONE, &error)) { gchar **items = g_key_file_get_groups (kfile, NULL); guint i; for (i = 0; i < g_strv_length (items); i++) { NemoBookmarkMetadata *meta = nemo_bookmark_metadata_new (); meta->bookmark_name = g_strdup (items[i]); meta->emblems = g_key_file_get_string_list (kfile, items[i], KEY_ICON_EMBLEMS, NULL, NULL); ret = g_list_append (ret, meta); } g_strfreev (items); } else if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { g_warning ("Could not load bookmark metadata file: %s\n", error->message); g_error_free (error); } g_key_file_free (kfile); g_free (filename); return ret; } static void load_files_finish (NemoBookmarkList *bookmarks, GObject *source, GAsyncResult *res) { GError *error = NULL; GList *new_list = g_task_propagate_pointer (G_TASK (res), &error); if (error != NULL && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_warning ("Could not load bookmarks: %s\n", error->message); g_error_free (error); return; } GList *old_list = bookmarks->list; bookmarks->list = new_list; clear_bookmarks (bookmarks, old_list); g_list_foreach (bookmarks->list, (GFunc) connect_bookmark_signals, bookmarks); g_signal_emit (bookmarks, signals[CHANGED], 0); } static gint find_meta_func (gconstpointer a, gconstpointer b) { return g_strcmp0 (((NemoBookmarkMetadata *) a)->bookmark_name, (gchar *) b); } static void load_files_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { NemoBookmarkList *list = NEMO_BOOKMARK_LIST (source_object); GError *error = NULL; GFile *file; file = nemo_bookmark_list_get_file (); if (!g_file_query_exists (file, NULL)) { g_object_unref (file); file = nemo_bookmark_list_get_legacy_file (); } gchar *contents = NULL; GList *new_list = NULL; if (g_file_load_contents (file, cancellable, &contents, NULL, NULL, &error)) { GList *metadata = load_bookmark_metadata_file (list); gchar **lines; gint i; lines = g_strsplit (contents, "\n", -1); for (i = 0; lines[i]; i++) { /* Ignore empty or invalid lines that cannot be parsed properly */ if (lines[i][0] != '\0' && lines[i][0] != ' ') { /* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */ /* we must seperate the bookmark uri and the potential label */ gchar *space, *label; label = NULL; space = strchr (lines[i], ' '); if (space) { *space = '\0'; label = g_strdup (space + 1); } GList *meta_ptr = g_list_find_custom (metadata, label, (GCompareFunc) find_meta_func); NemoBookmarkMetadata *md = NULL; if (meta_ptr) { metadata = g_list_remove_link (metadata, meta_ptr); md = (NemoBookmarkMetadata *) meta_ptr->data; g_list_free (meta_ptr); } new_list = g_list_insert (new_list, new_bookmark_from_uri (lines[i], label, md), -1); g_free (label); } } g_list_free_full (metadata, (GDestroyNotify) nemo_bookmark_metadata_free); g_free (contents); g_strfreev (lines); g_task_return_pointer (task, new_list, NULL); } else { g_task_return_error (task, error); } g_object_unref (file); } static void load_files_async (NemoBookmarkList *self, GAsyncReadyCallback callback) { GTask *task; g_object_ref (self); task = g_task_new (self, NULL, callback, self); g_task_run_in_thread (task, load_files_thread); g_object_unref (task); } static void save_bookmark_metadata_file (NemoBookmarkList *list) { /* Part of save_files thread */ GError *error = NULL; GKeyFile *kfile = g_key_file_new (); gchar *filename; filename = g_build_filename (g_get_user_config_dir (), "nemo", "bookmark-metadata", NULL); GFile *file = g_file_new_for_path (filename); GFile *parent = g_file_get_parent (file); gchar *path = g_file_get_path (parent); g_mkdir_with_parents (path, 0700); g_free (path); g_object_unref (parent); GList *ptr; for (ptr = list->list; ptr != NULL; ptr = ptr->next) { NemoBookmark *bookmark = NEMO_BOOKMARK (ptr->data); NemoBookmarkMetadata *data = nemo_bookmark_get_updated_metadata (bookmark); if (data == NULL) continue; if (data->emblems) { g_key_file_set_string_list (kfile, nemo_bookmark_get_name (bookmark), KEY_ICON_EMBLEMS, (const gchar * const *) data->emblems, g_strv_length (data->emblems)); } nemo_bookmark_metadata_free (data); } if (g_key_file_save_to_file (kfile, filename, &error)) { ensure_proper_file_permissions (file); } else { g_warning ("Could not save bookmark metadata file: %s\n", error->message); g_error_free (error); } g_free (filename); g_key_file_free (kfile); g_object_unref (file); } static void save_files_finish (NemoBookmarkList *bookmarks, GObject *source, GAsyncResult *res) { GError *error = NULL; g_task_propagate_boolean (G_TASK (res), &error); if (error != NULL) { g_warning ("Unable to replace contents of the bookmarks file: %s", error->message); g_error_free (error); } GFile *file = nemo_bookmark_list_get_file (); /* re-enable bookmark file monitoring */ bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL); g_file_monitor_set_rate_limit (bookmarks->monitor, 1000); g_signal_connect (bookmarks->monitor, "changed", G_CALLBACK (bookmark_monitor_changed_cb), bookmarks); g_object_unref (file); } static void save_files_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { NemoBookmarkList *bookmarks = NEMO_BOOKMARK_LIST (source_object); GFile *file; GList *l; GString *bookmark_string; GFile *parent; char *path; /* temporarily disable bookmark file monitoring when writing file */ if (bookmarks->monitor != NULL) { g_file_monitor_cancel (bookmarks->monitor); bookmarks->monitor = NULL; } file = nemo_bookmark_list_get_file (); bookmark_string = g_string_new (NULL); for (l = bookmarks->list; l; l = l->next) { NemoBookmark *bookmark; bookmark = NEMO_BOOKMARK (l->data); const char *label; char *uri; label = nemo_bookmark_get_name (bookmark); uri = nemo_bookmark_get_uri (bookmark); g_string_append_printf (bookmark_string, "%s %s\n", uri, label); g_free (uri); } parent = g_file_get_parent (file); path = g_file_get_path (parent); g_mkdir_with_parents (path, 0700); g_free (path); g_object_unref (parent); GError *error = NULL; if (g_file_replace_contents (file, bookmark_string->str, bookmark_string->len, NULL, FALSE, 0, NULL, NULL, &error)) { ensure_proper_file_permissions (file); g_task_return_boolean (task, TRUE); } else { g_task_return_error (task, error); } g_string_free (bookmark_string, TRUE); g_object_unref (file); save_bookmark_metadata_file (bookmarks); } static void save_files_async (NemoBookmarkList *self, GAsyncReadyCallback callback) { GTask *task; g_object_ref (self); task = g_task_new (self, NULL, callback, self); g_task_run_in_thread (task, save_files_thread); g_object_unref (task); } static void process_next_op (NemoBookmarkList *bookmarks); static void op_processed_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NemoBookmarkList *self = user_data; int op; op = GPOINTER_TO_INT (g_queue_pop_tail (self->pending_ops)); if (op == LOAD_JOB) { load_files_finish (self, source, res); } else { save_files_finish (self, source, res); } if (!g_queue_is_empty (self->pending_ops)) { process_next_op (self); } /* release the reference acquired during the _async method */ g_object_unref (self); } static void process_next_op (NemoBookmarkList *bookmarks) { gint op; op = GPOINTER_TO_INT (g_queue_peek_tail (bookmarks->pending_ops)); if (op == LOAD_JOB) { load_files_async (bookmarks, op_processed_cb); } else { save_files_async (bookmarks, op_processed_cb); } } /** * nemo_bookmark_list_load_file: * * Reads bookmarks from file, clobbering contents in memory. * @bookmarks: the list of bookmarks to fill with file contents. **/ static void nemo_bookmark_list_load_file (NemoBookmarkList *bookmarks) { g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (LOAD_JOB)); if (g_queue_get_length (bookmarks->pending_ops) == 1) { process_next_op (bookmarks); } } /** * nemo_bookmark_list_save_file: * * Save bookmarks to disk. * @bookmarks: the list of bookmarks to save. **/ static void nemo_bookmark_list_save_file (NemoBookmarkList *bookmarks) { g_signal_emit (bookmarks, signals[CHANGED], 0); g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (SAVE_JOB)); if (g_queue_get_length (bookmarks->pending_ops) == 1) { process_next_op (bookmarks); } } static NemoBookmarkList *list = NULL; /** * nemo_bookmark_list_get_default: * * Retrieves the bookmark list singleton, with contents read from disk. * * Return value: A pointer to the object **/ NemoBookmarkList * nemo_bookmark_list_get_default (void) { if (list == NULL) { list = NEMO_BOOKMARK_LIST (g_object_new (NEMO_TYPE_BOOKMARK_LIST, NULL)); } return list; } /** * nemo_bookmark_list_set_window_geometry: * * Set a bookmarks window's geometry (position & size), in string form. This is * stored to disk by this class, and can be retrieved later in * the same session or in a future session. * @bookmarks: the list of bookmarks associated with the window. * @geometry: the new window geometry string. **/ void nemo_bookmark_list_set_window_geometry (NemoBookmarkList *bookmarks, const char *geometry) { g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); g_return_if_fail (geometry != NULL); g_free (window_geometry); window_geometry = g_strdup (geometry); nemo_bookmark_list_save_file (bookmarks); } nemo-4.4.2/src/nemo-bookmark-list.h000066400000000000000000000075411357442400300171420ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: John Sullivan */ /* nemo-bookmark-list.h - interface for centralized list of bookmarks. */ #ifndef NEMO_BOOKMARK_LIST_H #define NEMO_BOOKMARK_LIST_H #include #include typedef struct NemoBookmarkList NemoBookmarkList; typedef struct NemoBookmarkListClass NemoBookmarkListClass; #define NEMO_TYPE_BOOKMARK_LIST nemo_bookmark_list_get_type() #define NEMO_BOOKMARK_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_BOOKMARK_LIST, NemoBookmarkList)) #define NEMO_BOOKMARK_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_BOOKMARK_LIST, NemoBookmarkListClass)) #define NEMO_IS_BOOKMARK_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_BOOKMARK_LIST)) #define NEMO_IS_BOOKMARK_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_BOOKMARK_LIST)) #define NEMO_BOOKMARK_LIST_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_BOOKMARK_LIST, NemoBookmarkListClass)) struct NemoBookmarkList { GObject object; GList *list; GFileMonitor *monitor; GQueue *pending_ops; GVolumeMonitor *volume_monitor; guint idle_notify_id; }; struct NemoBookmarkListClass { GObjectClass parent_class; void (* changed) (NemoBookmarkList *bookmarks); }; GType nemo_bookmark_list_get_type (void); NemoBookmarkList * nemo_bookmark_list_get_default (void); void nemo_bookmark_list_append (NemoBookmarkList *bookmarks, NemoBookmark *bookmark); gboolean nemo_bookmark_list_contains (NemoBookmarkList *bookmarks, NemoBookmark *bookmark); void nemo_bookmark_list_delete_item_at (NemoBookmarkList *bookmarks, guint index); void nemo_bookmark_list_delete_items_with_uri (NemoBookmarkList *bookmarks, const char *uri); void nemo_bookmark_list_insert_item (NemoBookmarkList *bookmarks, NemoBookmark *bookmark, guint index); GList * nemo_bookmark_list_get_for_uri (NemoBookmarkList *bookmarks, const char *uri); guint nemo_bookmark_list_length (NemoBookmarkList *bookmarks); NemoBookmark * nemo_bookmark_list_item_at (NemoBookmarkList *bookmarks, guint index); void nemo_bookmark_list_move_item (NemoBookmarkList *bookmarks, guint index, guint destination); void nemo_bookmark_list_sort_ascending (NemoBookmarkList *bookmarks); void nemo_bookmark_list_set_window_geometry (NemoBookmarkList *bookmarks, const char *geometry); const char * nemo_bookmark_list_get_window_geometry (NemoBookmarkList *bookmarks); #endif /* NEMO_BOOKMARK_LIST_H */ nemo-4.4.2/src/nemo-bookmarks-window.c000066400000000000000000001062411357442400300176510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: John Sullivan */ /* nemo-bookmarks-window.c - implementation of bookmark-editing window. */ #include #include "nemo-bookmarks-window.h" #include "nemo-window.h" #include #include #include #include #include #include #include #include /* Static variables to keep track of window state. If there were * more than one bookmark-editing window, these would be struct or * class fields. */ static int bookmark_list_changed_signal_id; static NemoBookmarkList *bookmarks = NULL; static GtkTreeView *bookmark_list_widget = NULL; /* awkward name to distinguish from NemoBookmarkList */ static GtkListStore *bookmark_list_store = NULL; static GtkListStore *bookmark_empty_list_store = NULL; static GtkTreeSelection *bookmark_selection = NULL; static int selection_changed_id = 0; static GtkWidget *name_field = NULL; static int name_field_changed_signal_id; static GtkWidget *remove_button = NULL; static GtkWidget *jump_button = NULL; static GtkWidget *sort_button = NULL; static gboolean text_changed = FALSE; static gboolean name_text_changed = FALSE; static GtkWidget *uri_field = NULL; static int uri_field_changed_signal_id; static int row_changed_signal_id; static int row_deleted_signal_id; static int row_activated_signal_id; static int button_pressed_signal_id; static int key_pressed_signal_id; static int jump_button_signal_id; static int sort_button_signal_id; /* forward declarations */ static guint get_selected_row (void); static gboolean get_selection_exists (void); static gboolean get_selection_is_separator (void); static void name_or_uri_field_activate (NemoEntry *entry); static void nemo_bookmarks_window_restore_geometry (GtkWidget *window); static void on_bookmark_list_changed (NemoBookmarkList *list, gpointer user_data); static void on_name_field_changed (GtkEditable *editable, gpointer user_data); static void on_remove_button_clicked (GtkButton *button, gpointer user_data); static void on_jump_button_clicked (GtkButton *button, gpointer user_data); static void on_sort_button_clicked (GtkButton *button, gpointer user_data); static void on_row_changed (GtkListStore *store, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data); static void on_row_deleted (GtkListStore *store, GtkTreePath *path, gpointer user_data); static void on_row_activated (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data); static gboolean on_button_pressed (GtkTreeView *view, GdkEventButton *event, gpointer user_data); static gboolean on_key_pressed (GtkTreeView *view, GdkEventKey *event, gpointer user_data); static void on_selection_changed (GtkTreeSelection *treeselection, gpointer user_data); static gboolean on_text_field_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data); static void on_uri_field_changed (GtkEditable *editable, gpointer user_data); static gboolean on_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); static void on_window_hide_event (GtkWidget *widget, gpointer user_data); static void on_window_destroy_event (GtkWidget *widget, gpointer user_data); static void repopulate (void); static void set_up_close_accelerator (GtkWidget *window); static void open_selected_bookmark (gpointer user_data, GdkScreen *screen); static void update_bookmark_from_text (void); /* We store a pointer to the bookmark in a column so when an item is moved with DnD we know which item it is. However we have to be careful to keep this in sync with the actual bookmark. Note that nemo_bookmark_list_insert_item() makes a copy of the bookmark, so we have to fetch the new copy and update our pointer. */ #define BOOKMARK_LIST_COLUMN_ICON 0 #define BOOKMARK_LIST_COLUMN_NAME 1 #define BOOKMARK_LIST_COLUMN_BOOKMARK 2 #define BOOKMARK_LIST_COLUMN_STYLE 3 #define BOOKMARK_LIST_COLUMN_IS_SEPARATOR 4 #define BOOKMARK_LIST_COLUMN_COUNT 5 /* layout constants */ /* Keep window from shrinking down ridiculously small; numbers are somewhat arbitrary */ #define BOOKMARKS_WINDOW_MIN_WIDTH 300 #define BOOKMARKS_WINDOW_MIN_HEIGHT 100 /* Larger size initially; user can stretch or shrink (but not shrink below min) */ #define BOOKMARKS_WINDOW_INITIAL_WIDTH 500 #define BOOKMARKS_WINDOW_INITIAL_HEIGHT 300 static void nemo_bookmarks_window_response_callback (GtkDialog *dialog, int response_id, gpointer callback_data) { if (response_id == GTK_RESPONSE_CLOSE) { gtk_widget_hide (GTK_WIDGET (dialog)); } } static GtkListStore * create_bookmark_store (void) { return gtk_list_store_new (BOOKMARK_LIST_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT, PANGO_TYPE_STYLE, G_TYPE_BOOLEAN); } static void setup_empty_list (void) { GtkTreeIter iter; bookmark_empty_list_store = create_bookmark_store (); gtk_list_store_append (bookmark_empty_list_store, &iter); gtk_list_store_set (bookmark_empty_list_store, &iter, BOOKMARK_LIST_COLUMN_NAME, _("No bookmarks defined"), BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_ITALIC, -1); } static void bookmarks_set_empty (gboolean empty) { GtkTreeIter iter; if (empty) { gtk_tree_view_set_model (bookmark_list_widget, GTK_TREE_MODEL (bookmark_empty_list_store)); gtk_widget_set_sensitive (GTK_WIDGET (bookmark_list_widget), FALSE); } else { gtk_tree_view_set_model (bookmark_list_widget, GTK_TREE_MODEL (bookmark_list_store)); gtk_widget_set_sensitive (GTK_WIDGET (bookmark_list_widget), TRUE); if (nemo_bookmark_list_length (bookmarks) > 0 && !get_selection_exists ()) { gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (bookmark_list_store), &iter, NULL, 0); gtk_tree_selection_select_iter (bookmark_selection, &iter); } } on_selection_changed (bookmark_selection, NULL); } static void edit_bookmarks_dialog_reset_signals (gpointer data, GObject *obj) { g_signal_handler_disconnect (jump_button, jump_button_signal_id); g_signal_handler_disconnect (sort_button, sort_button_signal_id); g_signal_handler_disconnect (bookmark_list_widget, row_activated_signal_id); jump_button_signal_id = g_signal_connect (jump_button, "clicked", G_CALLBACK (on_jump_button_clicked), NULL); sort_button_signal_id = g_signal_connect (sort_button, "clicked", G_CALLBACK (on_sort_button_clicked), NULL); row_activated_signal_id = g_signal_connect (bookmark_list_widget, "row_activated", G_CALLBACK (on_row_activated), NULL); } /** * create_bookmarks_window: * * Create a new bookmark-editing window. * @list: The NemoBookmarkList that this window will edit. * * Return value: A pointer to the new window. **/ GtkWindow * create_bookmarks_window (NemoBookmarkList *list, GObject *undo_manager_source) { GtkWidget *window; GtkTreeViewColumn *col; GtkCellRenderer *rend; GtkBuilder *builder; bookmarks = list; builder = gtk_builder_new (); gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); if (!gtk_builder_add_from_resource (builder, "/org/nemo/nemo-bookmarks-window.glade", NULL)) { return NULL; } window = (GtkWidget *)gtk_builder_get_object (builder, "bookmarks_dialog"); bookmark_list_widget = (GtkTreeView *)gtk_builder_get_object (builder, "bookmark_tree_view"); remove_button = (GtkWidget *)gtk_builder_get_object (builder, "bookmark_delete_button"); jump_button = (GtkWidget *)gtk_builder_get_object (builder, "bookmark_jump_button"); sort_button = (GtkWidget *)gtk_builder_get_object (builder, "bookmark_sort_button"); set_up_close_accelerator (window); nemo_undo_share_undo_manager (G_OBJECT (window), undo_manager_source); gtk_window_set_wmclass (GTK_WINDOW (window), "bookmarks", "Nemo"); nemo_bookmarks_window_restore_geometry (window); g_object_weak_ref (G_OBJECT (undo_manager_source), edit_bookmarks_dialog_reset_signals, undo_manager_source); bookmark_list_widget = GTK_TREE_VIEW (gtk_builder_get_object (builder, "bookmark_tree_view")); rend = gtk_cell_renderer_pixbuf_new (); col = gtk_tree_view_column_new_with_attributes ("Icon", rend, "icon-name", BOOKMARK_LIST_COLUMN_ICON, NULL); gtk_tree_view_append_column (bookmark_list_widget, GTK_TREE_VIEW_COLUMN (col)); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (col), NEMO_ICON_SIZE_SMALLER); rend = gtk_cell_renderer_text_new (); g_object_set (rend, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); col = gtk_tree_view_column_new_with_attributes ("Icon", rend, "text", BOOKMARK_LIST_COLUMN_NAME, "style", BOOKMARK_LIST_COLUMN_STYLE, NULL); gtk_tree_view_append_column (bookmark_list_widget, GTK_TREE_VIEW_COLUMN (col)); bookmark_list_store = create_bookmark_store (); setup_empty_list (); gtk_tree_view_set_model (bookmark_list_widget, GTK_TREE_MODEL (bookmark_empty_list_store)); bookmark_selection = GTK_TREE_SELECTION (gtk_tree_view_get_selection (bookmark_list_widget)); name_field = nemo_entry_new (); gtk_widget_show (name_field); gtk_box_pack_start (GTK_BOX (gtk_builder_get_object (builder, "bookmark_name_placeholder")), name_field, TRUE, TRUE, 0); gtk_label_set_mnemonic_widget ( GTK_LABEL (gtk_builder_get_object (builder, "bookmark_name_label")), name_field); uri_field = nemo_entry_new (); gtk_widget_show (uri_field); gtk_box_pack_start (GTK_BOX (gtk_builder_get_object (builder, "bookmark_location_placeholder")), uri_field, TRUE, TRUE, 0); gtk_label_set_mnemonic_widget ( GTK_LABEL (gtk_builder_get_object (builder, "bookmark_location_label")), uri_field); bookmark_list_changed_signal_id = g_signal_connect (bookmarks, "changed", G_CALLBACK (on_bookmark_list_changed), NULL); row_changed_signal_id = g_signal_connect (bookmark_list_store, "row_changed", G_CALLBACK (on_row_changed), NULL); row_deleted_signal_id = g_signal_connect (bookmark_list_store, "row_deleted", G_CALLBACK (on_row_deleted), NULL); row_activated_signal_id = g_signal_connect (bookmark_list_widget, "row_activated", G_CALLBACK (on_row_activated), undo_manager_source); button_pressed_signal_id = g_signal_connect (bookmark_list_widget, "button_press_event", G_CALLBACK (on_button_pressed), NULL); key_pressed_signal_id = g_signal_connect (bookmark_list_widget, "key_press_event", G_CALLBACK (on_key_pressed), NULL); selection_changed_id = g_signal_connect (bookmark_selection, "changed", G_CALLBACK (on_selection_changed), NULL); g_signal_connect (window, "delete_event", G_CALLBACK (on_window_delete_event), NULL); g_signal_connect (window, "hide", G_CALLBACK (on_window_hide_event), NULL); g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy_event), NULL); g_signal_connect (window, "response", G_CALLBACK (nemo_bookmarks_window_response_callback), NULL); name_field_changed_signal_id = g_signal_connect (name_field, "changed", G_CALLBACK (on_name_field_changed), NULL); g_signal_connect (name_field, "focus_out_event", G_CALLBACK (on_text_field_focus_out_event), NULL); g_signal_connect (name_field, "activate", G_CALLBACK (name_or_uri_field_activate), NULL); uri_field_changed_signal_id = g_signal_connect (uri_field, "changed", G_CALLBACK (on_uri_field_changed), NULL); g_signal_connect (uri_field, "focus_out_event", G_CALLBACK (on_text_field_focus_out_event), NULL); g_signal_connect (uri_field, "activate", G_CALLBACK (name_or_uri_field_activate), NULL); g_signal_connect (remove_button, "clicked", G_CALLBACK (on_remove_button_clicked), NULL); jump_button_signal_id = g_signal_connect (jump_button, "clicked", G_CALLBACK (on_jump_button_clicked), undo_manager_source); sort_button_signal_id = g_signal_connect (sort_button, "clicked", G_CALLBACK (on_sort_button_clicked), NULL); gtk_tree_selection_set_mode (bookmark_selection, GTK_SELECTION_BROWSE); /* Fill in list widget with bookmarks, must be after signals are wired up. */ repopulate(); g_object_unref (builder); return GTK_WINDOW (window); } void edit_bookmarks_dialog_set_signals (GObject *undo_manager_source) { g_signal_handler_disconnect (jump_button, jump_button_signal_id); g_signal_handler_disconnect (sort_button, sort_button_signal_id); g_signal_handler_disconnect (bookmark_list_widget, row_activated_signal_id); jump_button_signal_id = g_signal_connect (jump_button, "clicked", G_CALLBACK (on_jump_button_clicked), undo_manager_source); sort_button_signal_id = g_signal_connect (sort_button, "clicked", G_CALLBACK (on_sort_button_clicked), NULL); row_activated_signal_id = g_signal_connect (bookmark_list_widget, "row_activated", G_CALLBACK (on_row_activated), undo_manager_source); g_object_weak_ref (G_OBJECT (undo_manager_source), edit_bookmarks_dialog_reset_signals, undo_manager_source); } static NemoBookmark * get_selected_bookmark (void) { gint selected_row; g_return_val_if_fail(NEMO_IS_BOOKMARK_LIST(bookmarks), NULL); if (!get_selection_exists()) return NULL; if (nemo_bookmark_list_length (bookmarks) < 1) return NULL; if (get_selection_is_separator ()) { return NULL; } selected_row = get_selected_row (); if (selected_row > g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT)) { selected_row--; } return nemo_bookmark_list_item_at(bookmarks, selected_row); } static guint get_selected_row (void) { GtkTreeIter iter; GtkTreePath *path; GtkTreeModel *model; gint *indices, row; g_assert (get_selection_exists()); model = GTK_TREE_MODEL (bookmark_list_store); gtk_tree_selection_get_selected (bookmark_selection, &model, &iter); path = gtk_tree_model_get_path (model, &iter); indices = gtk_tree_path_get_indices (path); row = indices[0]; gtk_tree_path_free (path); return row; } static gboolean get_selection_exists (void) { return gtk_tree_selection_get_selected (bookmark_selection, NULL, NULL); } static gboolean get_selection_is_separator (void) { GtkTreeIter iter; GtkTreeModel *model; gboolean is_separator; model = GTK_TREE_MODEL (bookmark_list_store); gtk_tree_selection_get_selected (bookmark_selection, &model, &iter); gtk_tree_model_get (model, &iter, BOOKMARK_LIST_COLUMN_IS_SEPARATOR, &is_separator, -1); return is_separator; } static void nemo_bookmarks_window_restore_geometry (GtkWidget *window) { const char *window_geometry; g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); window_geometry = nemo_bookmark_list_get_window_geometry (bookmarks); if (window_geometry != NULL) { eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window), window_geometry, BOOKMARKS_WINDOW_MIN_WIDTH, BOOKMARKS_WINDOW_MIN_HEIGHT, FALSE); } else { /* use default since there was no stored geometry */ gtk_window_set_default_size (GTK_WINDOW (window), BOOKMARKS_WINDOW_INITIAL_WIDTH, BOOKMARKS_WINDOW_INITIAL_HEIGHT); /* Let window manager handle default position if no position stored */ } } /** * nemo_bookmarks_window_save_geometry: * * Save window size & position to disk. * @window: The bookmarks window whose geometry should be saved. **/ void nemo_bookmarks_window_save_geometry (GtkWindow *window) { g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bookmarks)); /* Don't bother if window is already closed */ if (gtk_widget_get_visible (GTK_WIDGET (window))) { char *geometry_string; geometry_string = eel_gtk_window_get_geometry_string (window); nemo_bookmark_list_set_window_geometry (bookmarks, geometry_string); g_free (geometry_string); } } static void on_bookmark_list_changed (NemoBookmarkList *bmarks, gpointer data) { g_return_if_fail (NEMO_IS_BOOKMARK_LIST (bmarks)); /* maybe add logic here or in repopulate to save/restore selection */ repopulate (); } static void on_name_field_changed (GtkEditable *editable, gpointer user_data) { GtkTreeIter iter; g_return_if_fail(GTK_IS_TREE_VIEW(bookmark_list_widget)); g_return_if_fail(GTK_IS_ENTRY(name_field)); if (!get_selection_exists()) return; /* Update text displayed in list instantly. Also remember that * user has changed text so we update real bookmark later. */ gtk_tree_selection_get_selected (bookmark_selection, NULL, &iter); gtk_list_store_set (bookmark_list_store, &iter, BOOKMARK_LIST_COLUMN_NAME, gtk_entry_get_text (GTK_ENTRY (name_field)), -1); text_changed = TRUE; name_text_changed = TRUE; } static void open_selected_bookmark (gpointer user_data, GdkScreen *screen) { NemoBookmark *selected; NemoWindow *window; GFile *location; selected = get_selected_bookmark (); if (!selected) { return; } location = nemo_bookmark_get_location (selected); if (location == NULL) { return; } window = user_data; nemo_window_go_to (window, location); g_object_unref (location); } static void on_jump_button_clicked (GtkButton *button, gpointer user_data) { GdkScreen *screen; screen = gtk_widget_get_screen (GTK_WIDGET (button)); open_selected_bookmark (user_data, screen); } static void on_sort_button_clicked (GtkButton *button, gpointer user_data) { g_assert (NEMO_IS_BOOKMARK_LIST (bookmarks)); nemo_bookmark_list_sort_ascending (bookmarks); } static void bookmarks_delete_bookmark (void) { GtkTreeIter iter; GtkTreePath *path; gint *indices, row, rows; g_assert (GTK_IS_TREE_VIEW (bookmark_list_widget)); if (!gtk_tree_selection_get_selected (bookmark_selection, NULL, &iter)) return; /* Remove the selected item from the list store. on_row_deleted() will remove it from the bookmark list. */ path = gtk_tree_model_get_path (GTK_TREE_MODEL (bookmark_list_store), &iter); indices = gtk_tree_path_get_indices (path); row = indices[0]; gtk_tree_path_free (path); gtk_list_store_remove (bookmark_list_store, &iter); /* Try to select the same row, or the last one in the list. */ rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (bookmark_list_store), NULL); if (row >= rows) row = rows - 1; if (row < 0) { bookmarks_set_empty (TRUE); } else { gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (bookmark_list_store), &iter, NULL, row); gtk_tree_selection_select_iter (bookmark_selection, &iter); } } static void on_remove_button_clicked (GtkButton *button, gpointer user_data) { bookmarks_delete_bookmark (); } /* This is a bit of a kludge to get DnD to work. We check if the row in the GtkListStore matches the one in the bookmark list. If it doesn't, we assume the bookmark has just been dragged here and we insert it into the bookmark list. */ static void on_row_changed (GtkListStore *store, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { NemoBookmark *bookmark = NULL, *bookmark_in_list; gint *indices, row, breakpoint; gboolean insert_bookmark = TRUE; store = bookmark_list_store; indices = gtk_tree_path_get_indices (path); row = indices[0]; gtk_tree_model_get (GTK_TREE_MODEL (store), iter, BOOKMARK_LIST_COLUMN_BOOKMARK, &bookmark, -1); breakpoint = g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT); if (row > breakpoint) { row--; } if (!bookmark) { /* Separator */ g_settings_set_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, row); repopulate (); return; } /* If the bookmark in the list doesn't match the changed one, it must have been dragged here, so we insert it into the list. */ if (row < (gint) nemo_bookmark_list_length (bookmarks)) { bookmark_in_list = nemo_bookmark_list_item_at (bookmarks, row); if (bookmark_in_list == bookmark) insert_bookmark = FALSE; } if (insert_bookmark) { g_signal_handler_block (bookmarks, bookmark_list_changed_signal_id); nemo_bookmark_list_insert_item (bookmarks, bookmark, row); g_signal_handler_unblock (bookmarks, bookmark_list_changed_signal_id); /* The bookmark will be copied when inserted into the list, so we have to update the pointer in the list store. */ bookmark = nemo_bookmark_list_item_at (bookmarks, row); g_signal_handler_block (store, row_changed_signal_id); gtk_list_store_set (store, iter, BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark, -1); g_signal_handler_unblock (store, row_changed_signal_id); } } /* The update_bookmark_from_text() calls in the * on_button_pressed() and on_key_pressed() handlers * of the tree view are a hack. * * The purpose is to track selection changes to the view * and write the text fields back before the selection * actually changed. * * Note that the focus-out event of the text entries is emitted * after the selection changed, else this would not not be neccessary. */ static gboolean on_button_pressed (GtkTreeView *view, GdkEventButton *event, gpointer user_data) { update_bookmark_from_text (); return FALSE; } static gboolean on_key_pressed (GtkTreeView *view, GdkEventKey *event, gpointer user_data) { if (event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete) { bookmarks_delete_bookmark (); return TRUE; } update_bookmark_from_text (); return FALSE; } static void on_row_activated (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { GdkScreen *screen; screen = gtk_widget_get_screen (GTK_WIDGET (view)); open_selected_bookmark (user_data, screen); } static void on_row_deleted (GtkListStore *store, GtkTreePath *path, gpointer user_data) { gint *indices, row; indices = gtk_tree_path_get_indices (path); row = indices[0]; if (row > g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT)) { row--; } g_signal_handler_block (bookmarks, bookmark_list_changed_signal_id); nemo_bookmark_list_delete_item_at (bookmarks, row); g_signal_handler_unblock (bookmarks, bookmark_list_changed_signal_id); } static void on_selection_changed (GtkTreeSelection *treeselection, gpointer user_data) { NemoBookmark *selected; const char *name = NULL; char *entry_text = NULL; GFile *location; g_assert (GTK_IS_ENTRY (name_field)); g_assert (GTK_IS_ENTRY (uri_field)); selected = get_selected_bookmark (); if (selected) { name = nemo_bookmark_get_name (selected); location = nemo_bookmark_get_location (selected); entry_text = g_file_get_parse_name (location); g_object_unref (location); } /* Set the sensitivity of widgets that require a selection */ gtk_widget_set_sensitive (remove_button, selected != NULL); gtk_widget_set_sensitive (jump_button, selected != NULL); gtk_widget_set_sensitive (sort_button, selected != NULL); gtk_widget_set_sensitive (name_field, selected != NULL); gtk_widget_set_sensitive (uri_field, selected != NULL); g_signal_handler_block (name_field, name_field_changed_signal_id); nemo_entry_set_text (NEMO_ENTRY (name_field), name ? name : ""); g_signal_handler_unblock (name_field, name_field_changed_signal_id); g_signal_handler_block (uri_field, uri_field_changed_signal_id); nemo_entry_set_text (NEMO_ENTRY (uri_field), entry_text ? entry_text : ""); g_signal_handler_unblock (uri_field, uri_field_changed_signal_id); text_changed = FALSE; name_text_changed = FALSE; g_free (entry_text); } static void update_bookmark_from_text (void) { if (text_changed) { NemoBookmark *bookmark, *bookmark_in_list; const char *name; gchar *icon_name; guint selected_row; GtkTreeIter iter; GFile *location; g_assert (GTK_IS_ENTRY (name_field)); g_assert (GTK_IS_ENTRY (uri_field)); if (gtk_entry_get_text_length (GTK_ENTRY (uri_field)) == 0) { return; } location = g_file_parse_name (gtk_entry_get_text (GTK_ENTRY (uri_field))); bookmark = nemo_bookmark_new (location, name_text_changed ? gtk_entry_get_text (GTK_ENTRY (name_field)) : NULL, NULL, NULL); g_object_unref (location); selected_row = get_selected_row (); /* turn off list updating 'cuz otherwise the list-reordering code runs * after repopulate(), thus reordering the correctly-ordered list. */ g_signal_handler_block (bookmarks, bookmark_list_changed_signal_id); nemo_bookmark_list_delete_item_at (bookmarks, selected_row); nemo_bookmark_list_insert_item (bookmarks, bookmark, selected_row); g_signal_handler_unblock (bookmarks, bookmark_list_changed_signal_id); g_object_unref (bookmark); /* We also have to update the bookmark pointer in the list store. */ gtk_tree_selection_get_selected (bookmark_selection, NULL, &iter); g_signal_handler_block (bookmark_list_store, row_changed_signal_id); bookmark_in_list = nemo_bookmark_list_item_at (bookmarks, selected_row); name = nemo_bookmark_get_name (bookmark_in_list); icon_name = nemo_bookmark_get_icon_name (bookmark_in_list); gtk_list_store_set (bookmark_list_store, &iter, BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark_in_list, BOOKMARK_LIST_COLUMN_NAME, name, BOOKMARK_LIST_COLUMN_ICON, icon_name, -1); g_signal_handler_unblock (bookmark_list_store, row_changed_signal_id); g_free (icon_name); } } static gboolean on_text_field_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { g_assert (NEMO_IS_ENTRY (widget)); update_bookmark_from_text (); return FALSE; } static void name_or_uri_field_activate (NemoEntry *entry) { g_assert (NEMO_IS_ENTRY (entry)); update_bookmark_from_text (); nemo_entry_select_all_at_idle (entry); } static void on_uri_field_changed (GtkEditable *editable, gpointer user_data) { /* Remember that user has changed text so we * update real bookmark later. */ text_changed = TRUE; } static gboolean on_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { gtk_widget_hide (widget); return TRUE; } static gboolean restore_geometry (gpointer data) { g_assert (GTK_IS_WINDOW (data)); nemo_bookmarks_window_restore_geometry (GTK_WIDGET (data)); /* Don't call this again */ return FALSE; } static void on_window_hide_event (GtkWidget *widget, gpointer user_data) { nemo_bookmarks_window_save_geometry (GTK_WINDOW (widget)); /* Disable undo for entry widgets */ nemo_undo_unregister (G_OBJECT (name_field)); nemo_undo_unregister (G_OBJECT (uri_field)); /* restore_geometry only works after window is hidden */ g_idle_add (restore_geometry, widget); } static void on_window_destroy_event (GtkWidget *widget, gpointer user_data) { g_object_unref (bookmark_list_store); g_object_unref (bookmark_empty_list_store); g_source_remove_by_user_data (widget); } static void add_breakpoint (GtkListStore *store, GtkTreeIter *iter) { gtk_list_store_append (store, iter); gtk_list_store_set (store, iter, BOOKMARK_LIST_COLUMN_ICON, NULL, BOOKMARK_LIST_COLUMN_NAME, "------------------------", BOOKMARK_LIST_COLUMN_BOOKMARK, NULL, BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_NORMAL, BOOKMARK_LIST_COLUMN_IS_SEPARATOR, TRUE, -1); } static void repopulate (void) { NemoBookmark *selected; GtkListStore *store; GtkTreePath *path; GtkTreeRowReference *reference; guint index; gint breakpoint, bookmarks_length; gboolean breakpoint_added; g_assert (GTK_IS_TREE_VIEW (bookmark_list_widget)); g_assert (NEMO_IS_BOOKMARK_LIST (bookmarks)); store = GTK_LIST_STORE (bookmark_list_store); selected = get_selected_bookmark (); g_signal_handler_block (bookmark_selection, selection_changed_id); g_signal_handler_block (bookmark_list_store, row_deleted_signal_id); g_signal_handler_block (bookmark_list_widget, row_activated_signal_id); g_signal_handler_block (bookmark_list_widget, key_pressed_signal_id); g_signal_handler_block (bookmark_list_widget, button_pressed_signal_id); gtk_list_store_clear (store); g_signal_handler_unblock (bookmark_list_widget, row_activated_signal_id); g_signal_handler_unblock (bookmark_list_widget, key_pressed_signal_id); g_signal_handler_unblock (bookmark_list_widget, button_pressed_signal_id); g_signal_handler_unblock (bookmark_list_store, row_deleted_signal_id); g_signal_handler_unblock (bookmark_selection, selection_changed_id); /* Fill the list in with the bookmark names. */ g_signal_handler_block (store, row_changed_signal_id); bookmarks_length = nemo_bookmark_list_length (bookmarks); breakpoint = g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT); if (breakpoint < 0) { // Default gsettings value is -1 (which translates to 'not previously set') breakpoint = bookmarks_length; g_settings_set_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, breakpoint); } reference = NULL; index = 0; breakpoint_added = FALSE; while (index < bookmarks_length) { NemoBookmark *bookmark; const char *bookmark_name; gchar *bookmark_icon; GtkTreeIter iter; if (index == breakpoint && !breakpoint_added) { bookmark_icon = NULL; bookmark = NULL; add_breakpoint (store, &iter); breakpoint_added = TRUE; } else { bookmark = nemo_bookmark_list_item_at (bookmarks, index); bookmark_name = nemo_bookmark_get_name (bookmark); bookmark_icon = nemo_bookmark_get_icon_name (bookmark); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, BOOKMARK_LIST_COLUMN_ICON, bookmark_icon, BOOKMARK_LIST_COLUMN_NAME, bookmark_name, BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark, BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_NORMAL, BOOKMARK_LIST_COLUMN_IS_SEPARATOR, FALSE, -1); } if (bookmark == selected) { /* save old selection */ GtkTreePath *pth; pth = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), pth); gtk_tree_path_free (pth); } g_free (bookmark_icon); if (bookmark) { index++; } } if (!breakpoint_added) { GtkTreeIter iter; add_breakpoint (store, &iter); } g_signal_handler_unblock (store, row_changed_signal_id); if (reference != NULL) { /* restore old selection */ /* bookmarks_set_empty() will call the selection change handler, * so we block it here in case of selection change. */ g_signal_handler_block (bookmark_selection, selection_changed_id); g_assert (index != 0); g_assert (gtk_tree_row_reference_valid (reference)); path = gtk_tree_row_reference_get_path (reference); gtk_tree_selection_select_path (bookmark_selection, path); gtk_tree_view_scroll_to_cell (bookmark_list_widget, path, NULL, TRUE, 0.5, 0); gtk_tree_row_reference_free (reference); gtk_tree_path_free (path); g_signal_handler_unblock (bookmark_selection, selection_changed_id); } bookmarks_set_empty (index == 0); } static int handle_close_accelerator (GtkWindow *window, GdkEventKey *event, gpointer user_data) { g_assert (GTK_IS_WINDOW (window)); g_assert (event != NULL); g_assert (user_data == NULL); if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_w) { gtk_widget_hide (GTK_WIDGET (window)); return TRUE; } return FALSE; } static void set_up_close_accelerator (GtkWidget *window) { /* Note that we don't call eel_gtk_window_set_up_close_accelerator * here because we have to handle saving geometry before hiding the * window. */ g_signal_connect (window, "key_press_event", G_CALLBACK (handle_close_accelerator), NULL); } nemo-4.4.2/src/nemo-bookmarks-window.h000066400000000000000000000025751357442400300176630ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: John Sullivan */ /* nemo-bookmarks-window.h - interface for bookmark-editing window. */ #ifndef NEMO_BOOKMARKS_WINDOW_H #define NEMO_BOOKMARKS_WINDOW_H #include #include "nemo-bookmark-list.h" GtkWindow *create_bookmarks_window (NemoBookmarkList *bookmarks, GObject *undo_manager_source); void nemo_bookmarks_window_save_geometry (GtkWindow *window); void edit_bookmarks_dialog_set_signals (GObject *undo_manager_source); #endif /* NEMO_BOOKMARKS_WINDOW_H */ nemo-4.4.2/src/nemo-config-base-widget.c000066400000000000000000000110651357442400300200110ustar00rootroot00000000000000/* nemo-config-base-widget.c */ /* A base widget class for extension/action/script config widgets. * This is usually part of a NemoPluginManagerWidget */ #include #include "nemo-config-base-widget.h" #include G_DEFINE_TYPE (NemoConfigBaseWidget, nemo_config_base_widget, GTK_TYPE_BIN); static void nemo_config_base_widget_class_init (NemoConfigBaseWidgetClass *klass) { } static void nemo_config_base_widget_init (NemoConfigBaseWidget *self) { GtkStyleContext *context; GtkWidget *box; GtkWidget *w; GtkWidget *toolbar_item; GtkWidget *frame = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (self), frame); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); context = gtk_widget_get_style_context (frame); gtk_style_context_add_class (context, "view"); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (frame), box); w = gtk_toolbar_new (); context = gtk_widget_get_style_context (w); gtk_style_context_add_class (context, "primary-toolbar"); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0); toolbar_item = GTK_WIDGET (gtk_tool_item_new ()); gtk_container_add (GTK_CONTAINER (w), toolbar_item); w = gtk_label_new (NULL); gtk_container_add (GTK_CONTAINER (toolbar_item), w); self->label = w; w = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0); self->listbox = gtk_list_box_new (); gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_NONE); gtk_container_add (GTK_CONTAINER (w), self->listbox); w = gtk_toolbar_new (); context = gtk_widget_get_style_context (w); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLBAR); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0); toolbar_item = GTK_WIDGET (gtk_tool_item_new ()); gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolbar_item), TRUE); gtk_container_add (GTK_CONTAINER (w), toolbar_item); w = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_add (GTK_CONTAINER (toolbar_item), w); self->buttonbox = w; self->disable_button = gtk_button_new_with_label (_("Disable all")); gtk_container_add (GTK_CONTAINER (w), self->disable_button); self->enable_button = gtk_button_new_with_label (_("Enable all")); gtk_container_add (GTK_CONTAINER (w), self->enable_button); gtk_widget_show_all (GTK_WIDGET (self)); } /** * nemo_config_base_widget_get_label: * @widget: a #NemoConfigBaseWidget * * Returns: (transfer none): the label #GtkWidget */ GtkWidget * nemo_config_base_widget_get_label (NemoConfigBaseWidget *widget) { return widget->label; } /** * nemo_config_base_widget_get_listbox: * @widget: a #NemoConfigBaseWidget * * Returns: (transfer none): the listbox #GtkWidget */ GtkWidget * nemo_config_base_widget_get_listbox (NemoConfigBaseWidget *widget) { return widget->listbox; } /** * nemo_config_base_widget_get_buttonbox: * @widget: a #NemoConfigBaseWidget * * Returns: (transfer none): the buttonbox #GtkWidget */ GtkWidget * nemo_config_base_widget_get_buttonbox (NemoConfigBaseWidget *widget) { return widget->buttonbox; } /** * nemo_config_base_widget_get_enable_button: * @widget: a #NemoConfigBaseWidget * * Returns: (transfer none): the enable button #GtkWidget */ GtkWidget * nemo_config_base_widget_get_enable_button (NemoConfigBaseWidget *widget) { return widget->enable_button; } /** * nemo_config_base_widget_get_disable_button: * @widget: a #NemoConfigBaseWidget * * Returns: (transfer none): the disable button #GtkWidget */ GtkWidget * nemo_config_base_widget_get_disable_button (NemoConfigBaseWidget *widget) { return widget->disable_button; } /** * nemo_config_base_widget_set_default_buttons_sensitive: * @widget: a #NemoConfigBaseWidget * @sensitive: TRUE or FALSE * * Set the enable/disable buttons sensitive or not */ void nemo_config_base_widget_set_default_buttons_sensitive (NemoConfigBaseWidget *widget, gboolean sensitive) { gtk_widget_set_sensitive (widget->enable_button, sensitive); gtk_widget_set_sensitive (widget->disable_button, sensitive); } /** * nemo_config_base_widget_clear_list: * @widget: a #NemoConfigBaseWidget * * Clear the listbox and destroy all children */ void nemo_config_base_widget_clear_list (NemoConfigBaseWidget *widget) { gtk_container_foreach (GTK_CONTAINER (widget->listbox), (GtkCallback) gtk_widget_destroy, NULL); } nemo-4.4.2/src/nemo-config-base-widget.h000066400000000000000000000043521357442400300200170ustar00rootroot00000000000000/* nemo-config-base-widget.h */ /* A base widget class for extension/action/script config widgets. * This is usually part of a NemoPluginManagerWidget */ #ifndef __NEMO_CONFIG_BASE_WIDGET_H__ #define __NEMO_CONFIG_BASE_WIDGET_H__ #include #include #include #include "nemo-window-private.h" G_BEGIN_DECLS #define NEMO_TYPE_CONFIG_BASE_WIDGET (nemo_config_base_widget_get_type()) #define NEMO_CONFIG_BASE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_CONFIG_BASE_WIDGET, NemoConfigBaseWidget)) #define NEMO_CONFIG_BASE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_CONFIG_BASE_WIDGET, NemoConfigBaseWidgetClass)) #define NEMO_IS_CONFIG_BASE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_CONFIG_BASE_WIDGET)) #define NEMO_IS_CONFIG_BASE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_CONFIG_BASE_WIDGET)) #define NEMO_CONFIG_BASE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_CONFIG_BASE_WIDGET, NemoConfigBaseWidgetClass)) typedef struct _NemoConfigBaseWidget NemoConfigBaseWidget; typedef struct _NemoConfigBaseWidgetClass NemoConfigBaseWidgetClass; struct _NemoConfigBaseWidget { GtkBin parent; GtkWidget *label; GtkWidget *listbox; GtkWidget *buttonbox; GtkWidget *enable_button; GtkWidget *disable_button; }; struct _NemoConfigBaseWidgetClass { GtkBinClass parent_class; }; GType nemo_config_base_widget_get_type (void); GtkWidget *nemo_config_base_widget_get_label (NemoConfigBaseWidget *widget); GtkWidget *nemo_config_base_widget_get_listbox (NemoConfigBaseWidget *widget); GtkWidget *nemo_config_base_widget_get_buttonbox (NemoConfigBaseWidget *widget); GtkWidget *nemo_config_base_widget_get_enable_button (NemoConfigBaseWidget *widget); GtkWidget *nemo_config_base_widget_get_disable_button (NemoConfigBaseWidget *widget); void nemo_config_base_widget_set_default_buttons_sensitive (NemoConfigBaseWidget *widget, gboolean sensitive); void nemo_config_base_widget_clear_list (NemoConfigBaseWidget *widget); NemoWindow *nemo_config_base_widget_get_view_window (NemoConfigBaseWidget *widget, NemoWindow *view_window); G_END_DECLS #endif /* __NEMO_CONFIG_BASE_WIDGET_H__ */ nemo-4.4.2/src/nemo-connect-server-dialog-main.c000066400000000000000000000104561357442400300214720ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-connect-server-main.c - Start the "Connect to Server" dialog. * Nemo * * Copyright (C) 2005 Vincent Untz * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: * Vincent Untz * Cosimo Cecchi */ #include #include #include #include #include #include #include #include #include "nemo-connect-server-dialog.h" static GSimpleAsyncResult *display_location_res = NULL; static gboolean just_print_uri = FALSE; static void main_dialog_destroyed (GtkWidget *widget, gpointer user_data) { /* this only happens when user clicks "cancel" * on the main dialog or when we are all done. */ gtk_main_quit (); } gboolean nemo_connect_server_dialog_display_location_finish (NemoConnectServerDialog *self, GAsyncResult *res, GError **error) { if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { return FALSE; } return TRUE; } void nemo_connect_server_dialog_display_location_async (NemoConnectServerDialog *self, GFile *location, GAsyncReadyCallback callback, gpointer user_data) { GError *error; GdkAppLaunchContext *launch_context; gchar *uri; display_location_res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, nemo_connect_server_dialog_display_location_async); error = NULL; uri = g_file_get_uri (location); if (just_print_uri) { g_print ("%s\n", uri); } else { launch_context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (self))); gdk_app_launch_context_set_screen (launch_context, gtk_widget_get_screen (GTK_WIDGET (self))); g_app_info_launch_default_for_uri (uri, G_APP_LAUNCH_CONTEXT (launch_context), &error); g_object_unref (launch_context); } if (error != NULL) { g_simple_async_result_set_from_error (display_location_res, error); g_error_free (error); } g_simple_async_result_complete_in_idle (display_location_res); g_free (uri); g_object_unref (display_location_res); display_location_res = NULL; } int main (int argc, char *argv[]) { GtkWidget *dialog; GOptionContext *context; GError *error; const GOptionEntry options[] = { { "print-uri", 0, 0, G_OPTION_ARG_NONE, &just_print_uri, N_("Print but do not open the URI"), NULL }, { NULL } }; bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); error = NULL; /* Translators: This is the --help description for the connect to server app, the initial newlines are between the command line arg and the description */ context = g_option_context_new (N_("\n\nAdd connect to server mount")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_critical ("Failed to parse arguments: %s", error->message); g_error_free (error); g_option_context_free (context); exit (1); } g_option_context_free (context); nemo_global_preferences_init (); gtk_window_set_default_icon_name (NEMO_ICON_FOLDER); dialog = nemo_connect_server_dialog_new (NULL); g_signal_connect (dialog, "destroy", G_CALLBACK (main_dialog_destroyed), NULL); gtk_widget_show (dialog); gtk_main (); return 0; } nemo-4.4.2/src/nemo-connect-server-dialog-nonmain.c000066400000000000000000000046551357442400300222110ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2005 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include "nemo-connect-server-dialog.h" #include /* This file contains the glue for the calls from the connect to server dialog * to the main nemo binary. A different version of this glue is in * nemo-connect-server-dialog-main.c for the standalone version. */ static GSimpleAsyncResult *display_location_res = NULL; static void window_go_to_cb (NemoWindow *window, GError *error, gpointer user_data) { if (error != NULL) { g_simple_async_result_set_from_error (display_location_res, error); } g_simple_async_result_complete (display_location_res); g_object_unref (display_location_res); display_location_res = NULL; } gboolean nemo_connect_server_dialog_display_location_finish (NemoConnectServerDialog *self, GAsyncResult *res, GError **error) { if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { return FALSE; } return TRUE; } void nemo_connect_server_dialog_display_location_async (NemoConnectServerDialog *self, GFile *location, GAsyncReadyCallback callback, gpointer user_data) { NemoWindow *window; GtkWidget *widget; widget = GTK_WIDGET (self); display_location_res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, nemo_connect_server_dialog_display_location_async); window = nemo_application_create_window (nemo_application_get_singleton (), gtk_widget_get_screen (widget)); nemo_window_go_to_full (window, location, window_go_to_cb, self); } nemo-4.4.2/src/nemo-connect-server-dialog.c000066400000000000000000001146631357442400300205550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include "nemo-connect-server-dialog.h" #include #include #include #include #include #include "nemo-bookmark-list.h" #include "nemo-connect-server-operation.h" #include "nemo-window.h" #include #include /* TODO: * - name entry + pre-fill * - NetworkManager integration */ struct _NemoConnectServerDialogDetails { GtkWidget *primary_grid; GtkWidget *user_details; GtkWidget *port_spinbutton; GtkWidget *info_bar; GtkWidget *info_bar_content; GtkWidget *type_combo; GtkWidget *server_entry; GtkWidget *share_entry; GtkWidget *folder_entry; GtkWidget *domain_entry; GtkWidget *user_entry; GtkWidget *password_entry; GtkWidget *remember_checkbox; GtkWidget *connect_button; GtkSizeGroup *labels_size_group; GtkSizeGroup *contents_size_group; GList *iconized_entries; GSimpleAsyncResult *fill_details_res; GAskPasswordFlags fill_details_flags; GMountOperation *fill_operation; gboolean last_password_set; gulong password_sensitive_id; gboolean should_destroy; GCancellable *mount_cancellable; }; G_DEFINE_TYPE (NemoConnectServerDialog, nemo_connect_server_dialog, GTK_TYPE_DIALOG) static void sensitive_entry_changed_callback (GtkEditable *editable, GtkWidget *widget); static void iconized_entry_changed_cb (GtkEditable *entry, NemoConnectServerDialog *dialog); enum { RESPONSE_CONNECT }; struct MethodInfo { const char *scheme; guint flags; guint default_port; }; /* A collection of flags for MethodInfo.flags */ enum { /* Widgets to display in connect_dialog_setup_for_type */ SHOW_SHARE = (1 << 0), SHOW_PORT = (1 << 1), SHOW_USER = (1 << 2), SHOW_DOMAIN = (1 << 3), IS_ANONYMOUS = (1 << 4) }; /* Remember to fill in descriptions below */ static struct MethodInfo methods[] = { /* FIXME: we need to alias ssh to sftp */ { "sftp", SHOW_PORT | SHOW_USER, 22 }, { "ftp", SHOW_PORT | SHOW_USER, 21 }, { "ftp", IS_ANONYMOUS | SHOW_PORT, 21 }, { "smb", SHOW_SHARE | SHOW_USER | SHOW_DOMAIN, 0 }, { "dav", SHOW_PORT | SHOW_USER, 80 }, /* FIXME: hrm, shouldn't it work? */ { "davs", SHOW_PORT | SHOW_USER, 443 }, }; /* To get around non constant gettext strings */ static const char* get_method_description (struct MethodInfo *meth) { if (strcmp (meth->scheme, "sftp") == 0) { return _("SSH"); } else if (strcmp (meth->scheme, "ftp") == 0) { if (meth->flags & IS_ANONYMOUS) { return _("Public FTP"); } else { return _("FTP (with login)"); } } else if (strcmp (meth->scheme, "smb") == 0) { return _("Windows share"); } else if (strcmp (meth->scheme, "dav") == 0) { return _("WebDAV (HTTP)"); } else if (strcmp (meth->scheme, "davs") == 0) { return _("Secure WebDAV (HTTPS)"); /* No descriptive text */ } else { return meth->scheme; } } static void connect_dialog_restore_info_bar (NemoConnectServerDialog *dialog, GtkMessageType message_type) { if (dialog->details->info_bar_content != NULL) { gtk_widget_destroy (dialog->details->info_bar_content); dialog->details->info_bar_content = NULL; } gtk_info_bar_set_message_type (GTK_INFO_BAR (dialog->details->info_bar), message_type); } static void connect_dialog_set_connecting (NemoConnectServerDialog *dialog) { GtkWidget *hbox; GtkWidget *widget; GtkWidget *content_area; gint width, height; connect_dialog_restore_info_bar (dialog, GTK_MESSAGE_INFO); gtk_widget_show (dialog->details->info_bar); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (dialog->details->info_bar)); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_add (GTK_CONTAINER (content_area), hbox); gtk_widget_show (hbox); dialog->details->info_bar_content = hbox; widget = gtk_spinner_new (); gtk_icon_size_lookup (GTK_ICON_SIZE_SMALL_TOOLBAR, &width, &height); gtk_widget_set_size_request (widget, width, height); gtk_spinner_start (GTK_SPINNER (widget)); gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6); gtk_widget_show (widget); widget = gtk_label_new (_("Connecting...")); gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6); gtk_widget_show (widget); gtk_widget_set_sensitive (dialog->details->connect_button, FALSE); } static void connect_dialog_gvfs_error (NemoConnectServerDialog *dialog) { GtkWidget *hbox, *image, *content_area, *label; connect_dialog_restore_info_bar (dialog, GTK_MESSAGE_ERROR); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (dialog->details->info_bar)); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_add (GTK_CONTAINER (content_area), hbox); gtk_widget_show (hbox); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 6); gtk_widget_show (image); label = gtk_label_new (_("Can't load the supported server method list.\n" "Please check your gvfs installation.")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6); gtk_widget_show (label); gtk_widget_set_sensitive (dialog->details->connect_button, FALSE); gtk_widget_set_sensitive (dialog->details->primary_grid, FALSE); gtk_widget_show (dialog->details->info_bar); } static void iconized_entry_restore (gpointer data, gpointer user_data) { GtkEntry *entry; NemoConnectServerDialog *dialog; entry = data; dialog = user_data; gtk_entry_set_icon_from_stock (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL); g_signal_handlers_disconnect_by_func (entry, iconized_entry_changed_cb, dialog); } static void iconized_entry_changed_cb (GtkEditable *entry, NemoConnectServerDialog *dialog) { dialog->details->iconized_entries = g_list_remove (dialog->details->iconized_entries, entry); iconized_entry_restore (entry, dialog); } static void iconize_entry (NemoConnectServerDialog *dialog, GtkWidget *entry) { if (!g_list_find (dialog->details->iconized_entries, entry)) { dialog->details->iconized_entries = g_list_prepend (dialog->details->iconized_entries, entry); gtk_entry_set_icon_from_stock (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_WARNING); gtk_widget_grab_focus (entry); g_signal_connect (entry, "changed", G_CALLBACK (iconized_entry_changed_cb), dialog); } } static void connect_dialog_set_info_bar_error (NemoConnectServerDialog *dialog, GError *error) { GtkWidget *content_area, *label, *entry, *hbox, *icon; gchar *str; const gchar *folder, *server; connect_dialog_restore_info_bar (dialog, GTK_MESSAGE_WARNING); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (dialog->details->info_bar)); entry = NULL; switch (error->code) { case G_IO_ERROR_FAILED_HANDLED: return; case G_IO_ERROR_NOT_FOUND: folder = gtk_entry_get_text (GTK_ENTRY (dialog->details->folder_entry)); server = gtk_entry_get_text (GTK_ENTRY (dialog->details->server_entry)); str = g_strdup_printf (_("The folder \"%s\" cannot be opened on \"%s\"."), folder, server); label = gtk_label_new (str); entry = dialog->details->folder_entry; g_free (str); break; case G_IO_ERROR_HOST_NOT_FOUND: server = gtk_entry_get_text (GTK_ENTRY (dialog->details->server_entry)); str = g_strdup_printf (_("The server at \"%s\" cannot be found."), server); label = gtk_label_new (str); entry = dialog->details->server_entry; g_free (str); break; case G_IO_ERROR_FAILED: default: label = gtk_label_new (error->message); break; } gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_widget_show (dialog->details->info_bar); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (content_area), hbox, FALSE, FALSE, 6); gtk_widget_show (hbox); icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 6); gtk_widget_show (icon); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6); gtk_widget_show (label); if (entry != NULL) { iconize_entry (dialog, entry); } dialog->details->info_bar_content = hbox; gtk_button_set_label (GTK_BUTTON (dialog->details->connect_button), _("Try Again")); gtk_widget_set_sensitive (dialog->details->connect_button, TRUE); } static void connect_dialog_finish_fill (NemoConnectServerDialog *dialog) { GAskPasswordFlags flags; GMountOperation *op; flags = dialog->details->fill_details_flags; op = G_MOUNT_OPERATION (dialog->details->fill_operation); if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { g_mount_operation_set_password (op, gtk_entry_get_text (GTK_ENTRY (dialog->details->password_entry))); } if (flags & G_ASK_PASSWORD_NEED_USERNAME) { g_mount_operation_set_username (op, gtk_entry_get_text (GTK_ENTRY (dialog->details->user_entry))); } if (flags & G_ASK_PASSWORD_NEED_DOMAIN) { g_mount_operation_set_domain (op, gtk_entry_get_text (GTK_ENTRY (dialog->details->domain_entry))); } if (flags & G_ASK_PASSWORD_SAVING_SUPPORTED && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->details->remember_checkbox))) { g_mount_operation_set_password_save (op, G_PASSWORD_SAVE_PERMANENTLY); } connect_dialog_set_connecting (dialog); g_simple_async_result_set_op_res_gboolean (dialog->details->fill_details_res, TRUE); g_simple_async_result_complete (dialog->details->fill_details_res); g_object_unref (dialog->details->fill_details_res); dialog->details->fill_details_res = NULL; g_object_unref (dialog->details->fill_operation); dialog->details->fill_operation = NULL; } static void connect_dialog_request_additional_details (NemoConnectServerDialog *self, GAskPasswordFlags flags, const gchar *default_user, const gchar *default_domain) { GtkWidget *content_area, *label, *hbox, *icon; self->details->fill_details_flags = flags; connect_dialog_restore_info_bar (self, GTK_MESSAGE_WARNING); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (self->details->info_bar)); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (content_area), hbox, FALSE, FALSE, 6); gtk_widget_show (hbox); icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 6); gtk_widget_show (icon); label = gtk_label_new (_("Please verify your user details.")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6); gtk_widget_show (label); if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { iconize_entry (self, self->details->password_entry); } if (flags & G_ASK_PASSWORD_NEED_USERNAME) { if (default_user != NULL && g_strcmp0 (default_user, "") != 0) { gtk_entry_set_text (GTK_ENTRY (self->details->user_entry), default_user); } else { iconize_entry (self, self->details->user_entry); } } if (flags & G_ASK_PASSWORD_NEED_DOMAIN) { if (default_domain != NULL && g_strcmp0 (default_domain, "") != 0) { gtk_entry_set_text (GTK_ENTRY (self->details->domain_entry), default_domain); } else { iconize_entry (self, self->details->domain_entry); } } self->details->info_bar_content = hbox; gtk_widget_set_sensitive (self->details->connect_button, TRUE); gtk_button_set_label (GTK_BUTTON (self->details->connect_button), _("Continue")); if (!(flags & G_ASK_PASSWORD_SAVING_SUPPORTED)) { g_signal_handler_disconnect (self->details->password_entry, self->details->password_sensitive_id); self->details->password_sensitive_id = 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->details->remember_checkbox), FALSE); gtk_widget_set_sensitive (self->details->remember_checkbox, FALSE); } } static void display_location_async_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NemoConnectServerDialog *dialog; GError *error; dialog = NEMO_CONNECT_SERVER_DIALOG (source); error = NULL; nemo_connect_server_dialog_display_location_finish (dialog, res, &error); if (error != NULL) { connect_dialog_set_info_bar_error (dialog, error); g_error_free (error); } else { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void mount_enclosing_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { GFile *location; NemoConnectServerDialog *dialog; GError *error; error = NULL; location = G_FILE (source); dialog = user_data; g_file_mount_enclosing_volume_finish (location, res, &error); if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED)) { /* volume is mounted, show it */ nemo_connect_server_dialog_display_location_async (dialog, location, display_location_async_cb, NULL); } else { if (dialog->details->should_destroy) { gtk_widget_destroy (GTK_WIDGET (dialog)); } else { connect_dialog_set_info_bar_error (dialog, error); } } g_clear_object (&dialog->details->mount_cancellable); if (error != NULL) { g_error_free (error); } } static void connect_dialog_present_uri_async (NemoConnectServerDialog *self, GFile *location) { GMountOperation *op; self->details->mount_cancellable = g_cancellable_new (); op = nemo_connect_server_operation_new (self); g_file_mount_enclosing_volume (location, 0, op, self->details->mount_cancellable, mount_enclosing_ready_cb, self); g_object_unref (op); } static void connect_dialog_connect_to_server (NemoConnectServerDialog *dialog) { struct MethodInfo *meth; GFile *location; int index; GtkTreeIter iter; char *user, *initial_path, *server, *folder, *domain, *port_str; char *t, *uri; char *temp, *stripped_server; double port; /* Get our method info */ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->details->type_combo), &iter); gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->details->type_combo)), &iter, 0, &index, -1); g_assert (index < (int)G_N_ELEMENTS (methods) && index >= 0); meth = &(methods[index]); server = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->server_entry), 0, -1); temp = g_strconcat (meth->scheme, "://", NULL); if (g_str_has_prefix (server, temp)) { stripped_server = g_strdup (server + strlen (temp)); g_free (server); server = stripped_server; } g_free (temp); user = NULL; initial_path = g_strdup (""); domain = NULL; folder = NULL; /* FTP special case */ if (meth->flags & IS_ANONYMOUS) { user = g_strdup ("anonymous"); /* SMB special case */ } else if (strcmp (meth->scheme, "smb") == 0) { g_free (initial_path); t = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->share_entry), 0, -1); initial_path = g_strconcat ("/", t, NULL); g_free (t); } /* username */ if (!user) { t = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->user_entry), 0, -1); user = g_uri_escape_string (t, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, FALSE); g_free (t); } /* domain */ domain = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->domain_entry), 0, -1); if (strlen (domain) != 0 && strcmp(meth->scheme, "smb") == 0) { t = user; user = g_strconcat (domain , ";" , t, NULL); g_free (t); } /* folder */ folder = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->folder_entry), 0, -1); t = folder; if (folder[0] != 0 && folder[0] != '/') { folder = g_strconcat (initial_path, "/", t, NULL); } else { folder = g_strconcat (initial_path, "", t, NULL); } g_free (t); t = folder; folder = g_uri_escape_string (t, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); g_free (t); /* port */ port = gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->details->port_spinbutton)); if (port != 0 && port != meth->default_port) { port_str = g_strdup_printf ("%d", (int) port); } else { port_str = NULL; } /* final uri */ uri = g_strdup_printf ("%s://%s%s%s%s%s%s", meth->scheme, (user != NULL) ? user : "", (user != NULL && user[0] != 0) ? "@" : "", server, (port_str != NULL) ? ":" : "", (port_str != NULL) ? port_str : "", (folder != NULL) ? folder : ""); g_free (initial_path); g_free (server); g_free (folder); g_free (user); g_free (domain); g_free (port_str); location = g_file_new_for_uri (uri); g_free (uri); connect_dialog_set_connecting (dialog); connect_dialog_present_uri_async (dialog, location); g_object_unref (location); } static void connect_to_server_or_finish_fill (NemoConnectServerDialog *dialog) { if (dialog->details->fill_details_res != NULL) { connect_dialog_finish_fill (dialog); } else { connect_dialog_connect_to_server (dialog); } } static gboolean connect_dialog_abort_mount_operation (NemoConnectServerDialog *dialog) { gboolean retval = FALSE; if (dialog->details->mount_cancellable != NULL) { g_cancellable_cancel (dialog->details->mount_cancellable); retval = TRUE; } else if (dialog->details->fill_details_res != NULL) { g_simple_async_result_set_op_res_gboolean (dialog->details->fill_details_res, FALSE); g_simple_async_result_complete (dialog->details->fill_details_res); g_object_unref (dialog->details->fill_details_res); dialog->details->fill_details_res = NULL; if (dialog->details->fill_operation) { g_object_unref (dialog->details->fill_operation); dialog->details->fill_operation = NULL; } retval = TRUE; } return retval; } static void connect_dialog_destroy (NemoConnectServerDialog *dialog) { if (connect_dialog_abort_mount_operation (dialog)) { dialog->details->should_destroy = TRUE; gtk_widget_hide (GTK_WIDGET (dialog)); } else { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void connect_dialog_response_cb (NemoConnectServerDialog *dialog, int response_id, gpointer data) { GError *error; switch (response_id) { case RESPONSE_CONNECT: connect_to_server_or_finish_fill (dialog); break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CANCEL: connect_dialog_destroy (dialog); break; case GTK_RESPONSE_HELP : error = NULL; gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (dialog)), "help:gnome-help/nemo-connect", gtk_get_current_event_time (), &error); if (error) { eel_show_error_dialog (_("There was an error displaying help."), error->message, GTK_WINDOW (dialog)); g_error_free (error); } break; default : g_assert_not_reached (); } } static void connect_dialog_cleanup (NemoConnectServerDialog *dialog) { /* hide the infobar */ gtk_widget_hide (dialog->details->info_bar); /* set the connect button label back to 'Connect' */ gtk_button_set_label (GTK_BUTTON (dialog->details->connect_button), _("C_onnect")); /* if there was a pending mount operation, cancel it. */ connect_dialog_abort_mount_operation (dialog); /* restore password checkbox sensitivity */ if (dialog->details->password_sensitive_id == 0) { dialog->details->password_sensitive_id = g_signal_connect (dialog->details->password_entry, "changed", G_CALLBACK (sensitive_entry_changed_callback), dialog->details->remember_checkbox); sensitive_entry_changed_callback (GTK_EDITABLE (dialog->details->password_entry), dialog->details->remember_checkbox); } /* remove icons on the entries */ g_list_foreach (dialog->details->iconized_entries, (GFunc) iconized_entry_restore, dialog); g_list_free (dialog->details->iconized_entries); dialog->details->iconized_entries = NULL; dialog->details->last_password_set = FALSE; } static void connect_dialog_setup_for_type (NemoConnectServerDialog *dialog) { struct MethodInfo *meth; int index;; GtkTreeIter iter; connect_dialog_cleanup (dialog); /* get our method info */ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->details->type_combo), &iter)) { /* there are no entries in the combo, something is wrong * with our GVfs installation. */ connect_dialog_gvfs_error (dialog); return; } gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->details->type_combo)), &iter, 0, &index, -1); g_assert (index < (int)G_N_ELEMENTS (methods) && index >= 0); meth = &(methods[index]); if (g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_LAST_SERVER_CONNECT_METHOD) != index) { g_settings_set_int (nemo_preferences, NEMO_PREFERENCES_LAST_SERVER_CONNECT_METHOD, index); } g_object_set (dialog->details->share_entry, "visible", (meth->flags & SHOW_SHARE) != 0, NULL); g_object_set (dialog->details->port_spinbutton, "sensitive", (meth->flags & SHOW_PORT) != 0, "value", (gdouble) meth->default_port, NULL); g_object_set (dialog->details->user_details, "visible", (meth->flags & SHOW_USER) != 0 || (meth->flags & SHOW_DOMAIN) != 0, NULL); g_object_set (dialog->details->user_entry, "visible", (meth->flags & SHOW_USER) != 0, NULL); g_object_set (dialog->details->password_entry, "visible", (meth->flags & SHOW_USER) != 0, NULL); g_object_set (dialog->details->domain_entry, "visible", (meth->flags & SHOW_DOMAIN) != 0, NULL); } static void sensitive_entry_changed_callback (GtkEditable *editable, GtkWidget *widget) { guint length; length = gtk_entry_get_text_length (GTK_ENTRY (editable)); gtk_widget_set_sensitive (widget, length > 0); } static void bind_visibility (NemoConnectServerDialog *dialog, GtkWidget *source, GtkWidget *dest) { g_object_bind_property (source, "visible", dest, "visible", G_BINDING_DEFAULT); } static void nemo_connect_server_dialog_init (NemoConnectServerDialog *dialog) { GtkWidget *label; GtkWidget *alignment; GtkWidget *content_area; GtkWidget *combo, *grid; GtkWidget *hbox, *connect_button, *checkbox; GtkListStore *store; GtkCellRenderer *renderer; gchar *str; guint i; dialog->details = G_TYPE_INSTANCE_GET_PRIVATE (dialog, NEMO_TYPE_CONNECT_SERVER_DIALOG, NemoConnectServerDialogDetails); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); /* set dialog properties */ gtk_window_set_title (GTK_WINDOW (dialog), _("Connect to Server")); gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); gtk_box_set_spacing (GTK_BOX (content_area), 2); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); /* create the size group */ dialog->details->labels_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); dialog->details->contents_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /* infobar */ dialog->details->info_bar = gtk_info_bar_new (); gtk_info_bar_set_message_type (GTK_INFO_BAR (dialog->details->info_bar), GTK_MESSAGE_INFO); gtk_box_pack_start (GTK_BOX (content_area), dialog->details->info_bar, FALSE, FALSE, 6); /* server settings label */ label = gtk_label_new (NULL); str = g_strdup_printf ("%s", _("Server Details")); gtk_label_set_markup (GTK_LABEL (label), str); g_free (str); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (content_area), label, FALSE, FALSE, 6); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_widget_show (label); /* server settings alignment */ alignment = gtk_alignment_new (0, 0, 0, 0); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0); gtk_box_pack_start (GTK_BOX (content_area), alignment, TRUE, TRUE, 0); gtk_widget_show (alignment); grid = gtk_grid_new (); gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_grid_set_column_spacing (GTK_GRID (grid), 3); gtk_container_add (GTK_CONTAINER (alignment), grid); gtk_widget_show (grid); dialog->details->primary_grid = grid; /* first row: server entry + port spinbutton */ label = gtk_label_new_with_mnemonic (_("_Server:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_widget_show (label); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_widget_show (hbox); gtk_grid_attach_next_to (GTK_GRID (grid), hbox, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, hbox); dialog->details->server_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->server_entry), TRUE); gtk_box_pack_start (GTK_BOX (hbox), dialog->details->server_entry, FALSE, FALSE, 0); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->server_entry); gtk_widget_show (dialog->details->server_entry); /* port */ label = gtk_label_new_with_mnemonic (_("_Port:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); dialog->details->port_spinbutton = gtk_spin_button_new_with_range (0.0, 65535.0, 1.0); g_object_set (dialog->details->port_spinbutton, "digits", 0, "numeric", TRUE, "update-policy", GTK_UPDATE_IF_VALID, NULL); gtk_box_pack_start (GTK_BOX (hbox), dialog->details->port_spinbutton, FALSE, FALSE, 0); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->port_spinbutton); gtk_widget_show (dialog->details->port_spinbutton); /* second row: type combobox */ label = gtk_label_new_with_mnemonic (_("_Type:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_widget_show (label); dialog->details->type_combo = combo = gtk_combo_box_new (); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->type_combo); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->type_combo); gint last = g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_LAST_SERVER_CONNECT_METHOD); /* each row contains: method index, textual description */ store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING); gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store)); g_object_unref (store); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 1); for (i = 0; i < G_N_ELEMENTS (methods); i++) { GtkTreeIter iter; const gchar * const *supported; guint j; /* skip methods that don't have corresponding gvfs uri schemes */ supported = g_vfs_get_supported_uri_schemes (g_vfs_get_default ()); if (methods[i].scheme != NULL) { gboolean found; found = FALSE; for (j = 0; supported[j] != NULL; j++) { if (strcmp (methods[i].scheme, supported[j]) == 0) { found = TRUE; break; } } if (!found) { continue; } } gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, (int)i, 1, get_method_description (&(methods[i])), -1); if ((int)i == last) { gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter); } } if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) < 0) { /* default method not available, use any other */ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); } gtk_widget_show (combo); gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo); gtk_grid_attach_next_to (GTK_GRID (grid), combo, label, GTK_POS_RIGHT, 1, 1); g_signal_connect_swapped (combo, "changed", G_CALLBACK (connect_dialog_setup_for_type), dialog); /* third row: share entry */ label = gtk_label_new_with_mnemonic (_("Sh_are:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); dialog->details->share_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->share_entry), TRUE); gtk_grid_attach_next_to (GTK_GRID (grid), dialog->details->share_entry, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->share_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->share_entry); bind_visibility (dialog, dialog->details->share_entry, label); /* fourth row: folder entry */ label = gtk_label_new_with_mnemonic (_("_Folder:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->share_entry); gtk_widget_show (label); dialog->details->folder_entry = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (dialog->details->folder_entry), "/"); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->folder_entry), TRUE); gtk_grid_attach_next_to (GTK_GRID (grid), dialog->details->folder_entry, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->folder_entry); gtk_widget_show (dialog->details->folder_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->folder_entry); /* user details label */ label = gtk_label_new (NULL); str = g_strdup_printf ("%s", _("User Details")); gtk_label_set_markup (GTK_LABEL (label), str); g_free (str); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_box_pack_start (GTK_BOX (content_area), label, FALSE, FALSE, 6); /* user details alignment */ alignment = gtk_alignment_new (0, 0, 0, 0); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0); gtk_box_pack_start (GTK_BOX (content_area), alignment, TRUE, TRUE, 0); bind_visibility (dialog, alignment, label); dialog->details->user_details = alignment; grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_grid_set_column_spacing (GTK_GRID (grid), 3); gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); gtk_container_add (GTK_CONTAINER (alignment), grid); gtk_widget_show (grid); /* first row: domain entry */ label = gtk_label_new_with_mnemonic (_("_Domain name:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); dialog->details->domain_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->domain_entry), TRUE); gtk_size_group_add_widget (dialog->details->labels_size_group, label); gtk_grid_attach_next_to (GTK_GRID (grid), dialog->details->domain_entry, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->domain_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->domain_entry); bind_visibility (dialog, dialog->details->domain_entry, label); /* second row: username entry */ label = gtk_label_new_with_mnemonic (_("_User name:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); dialog->details->user_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->user_entry), TRUE); gtk_grid_attach_next_to (GTK_GRID (grid), dialog->details->user_entry, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->user_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->user_entry); bind_visibility (dialog, dialog->details->user_entry, label); /* third row: password entry */ label = gtk_label_new_with_mnemonic (_("Pass_word:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (dialog->details->labels_size_group, label); dialog->details->password_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dialog->details->password_entry), TRUE); gtk_entry_set_visibility (GTK_ENTRY (dialog->details->password_entry), FALSE); gtk_grid_attach_next_to (GTK_GRID (grid), dialog->details->password_entry, label, GTK_POS_RIGHT, 1, 1); gtk_size_group_add_widget (dialog->details->contents_size_group, dialog->details->password_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->details->password_entry); bind_visibility (dialog, dialog->details->password_entry, label); /* fourth row: remember checkbox */ checkbox = gtk_check_button_new_with_mnemonic (_("_Remember this password")); gtk_grid_attach_next_to (GTK_GRID (grid), checkbox, dialog->details->password_entry, GTK_POS_BOTTOM, 1, 1); dialog->details->remember_checkbox = checkbox; bind_visibility (dialog, dialog->details->password_entry, checkbox); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); connect_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("C_onnect"), RESPONSE_CONNECT); gtk_dialog_set_default_response (GTK_DIALOG (dialog), RESPONSE_CONNECT); dialog->details->connect_button = connect_button; g_signal_connect (dialog->details->server_entry, "changed", G_CALLBACK (sensitive_entry_changed_callback), connect_button); sensitive_entry_changed_callback (GTK_EDITABLE (dialog->details->server_entry), connect_button); g_signal_connect (dialog, "response", G_CALLBACK (connect_dialog_response_cb), dialog); connect_dialog_setup_for_type (dialog); } static void nemo_connect_server_dialog_finalize (GObject *object) { NemoConnectServerDialog *dialog; dialog = NEMO_CONNECT_SERVER_DIALOG (object); connect_dialog_abort_mount_operation (dialog); if (dialog->details->iconized_entries != NULL) { g_list_free (dialog->details->iconized_entries); dialog->details->iconized_entries = NULL; } G_OBJECT_CLASS (nemo_connect_server_dialog_parent_class)->finalize (object); } static void nemo_connect_server_dialog_class_init (NemoConnectServerDialogClass *class) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (class); oclass->finalize = nemo_connect_server_dialog_finalize; g_type_class_add_private (class, sizeof (NemoConnectServerDialogDetails)); } GtkWidget * nemo_connect_server_dialog_new (NemoWindow *window) { GtkWidget *dialog; dialog = gtk_widget_new (NEMO_TYPE_CONNECT_SERVER_DIALOG, NULL); if (window) { gtk_window_set_screen (GTK_WINDOW (dialog), gtk_window_get_screen (GTK_WINDOW (window))); } return dialog; } gboolean nemo_connect_server_dialog_fill_details_finish (NemoConnectServerDialog *self, GAsyncResult *result) { return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)); } void nemo_connect_server_dialog_fill_details_async (NemoConnectServerDialog *self, GMountOperation *operation, const gchar *default_user, const gchar *default_domain, GAskPasswordFlags flags, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *fill_details_res; const gchar *str; GAskPasswordFlags set_flags; if (g_cancellable_is_cancelled (self->details->mount_cancellable)) { g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data, G_IO_ERROR, G_IO_ERROR_CANCELLED, "%s", _("Operation cancelled")); return; } fill_details_res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, nemo_connect_server_dialog_fill_details_async); self->details->fill_details_res = fill_details_res; set_flags = (flags & G_ASK_PASSWORD_NEED_PASSWORD) | (flags & G_ASK_PASSWORD_NEED_USERNAME) | (flags & G_ASK_PASSWORD_NEED_DOMAIN); if (set_flags & G_ASK_PASSWORD_NEED_PASSWORD) { /* provide the password */ str = gtk_entry_get_text (GTK_ENTRY (self->details->password_entry)); if (str != NULL && g_strcmp0 (str, "") != 0 && !self->details->last_password_set) { g_mount_operation_set_password (G_MOUNT_OPERATION (operation), str); set_flags ^= G_ASK_PASSWORD_NEED_PASSWORD; if (flags & G_ASK_PASSWORD_SAVING_SUPPORTED && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->details->remember_checkbox))) { g_mount_operation_set_password_save (G_MOUNT_OPERATION (operation), G_PASSWORD_SAVE_PERMANENTLY); } self->details->last_password_set = TRUE; } } if (set_flags & G_ASK_PASSWORD_NEED_USERNAME) { /* see if the default username is different from ours */ str = gtk_entry_get_text (GTK_ENTRY (self->details->user_entry)); if (str != NULL && g_strcmp0 (str, "") != 0 && g_strcmp0 (str, default_user) != 0) { g_mount_operation_set_username (G_MOUNT_OPERATION (operation), str); set_flags ^= G_ASK_PASSWORD_NEED_USERNAME; } } if (set_flags & G_ASK_PASSWORD_NEED_DOMAIN) { /* see if the default domain is different from ours */ str = gtk_entry_get_text (GTK_ENTRY (self->details->domain_entry)); if (str != NULL && g_strcmp0 (str, "") && g_strcmp0 (str, default_domain) != 0) { g_mount_operation_set_domain (G_MOUNT_OPERATION (operation), str); set_flags ^= G_ASK_PASSWORD_NEED_DOMAIN; } } if (set_flags != 0) { set_flags |= (flags & G_ASK_PASSWORD_SAVING_SUPPORTED); self->details->fill_operation = g_object_ref (operation); connect_dialog_request_additional_details (self, set_flags, default_user, default_domain); } else { g_simple_async_result_set_op_res_gboolean (fill_details_res, TRUE); g_simple_async_result_complete (fill_details_res); g_object_unref (self->details->fill_details_res); self->details->fill_details_res = NULL; } } nemo-4.4.2/src/nemo-connect-server-dialog.h000066400000000000000000000055201357442400300205510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef NEMO_CONNECT_SERVER_DIALOG_H #define NEMO_CONNECT_SERVER_DIALOG_H #include #include #include "nemo-application.h" #include "nemo-window.h" #define NEMO_TYPE_CONNECT_SERVER_DIALOG\ (nemo_connect_server_dialog_get_type ()) #define NEMO_CONNECT_SERVER_DIALOG(obj)\ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_CONNECT_SERVER_DIALOG,\ NemoConnectServerDialog)) #define NEMO_CONNECT_SERVER_DIALOG_CLASS(klass)\ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_CONNECT_SERVER_DIALOG,\ NemoConnectServerDialogClass)) #define NEMO_IS_CONNECT_SERVER_DIALOG(obj)\ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_CONNECT_SERVER_DIALOG) typedef struct _NemoConnectServerDialog NemoConnectServerDialog; typedef struct _NemoConnectServerDialogClass NemoConnectServerDialogClass; typedef struct _NemoConnectServerDialogDetails NemoConnectServerDialogDetails; struct _NemoConnectServerDialog { GtkDialog parent; NemoConnectServerDialogDetails *details; }; struct _NemoConnectServerDialogClass { GtkDialogClass parent_class; }; GType nemo_connect_server_dialog_get_type (void); GtkWidget* nemo_connect_server_dialog_new (NemoWindow *window); void nemo_connect_server_dialog_display_location_async (NemoConnectServerDialog *self, GFile *location, GAsyncReadyCallback callback, gpointer user_data); gboolean nemo_connect_server_dialog_display_location_finish (NemoConnectServerDialog *self, GAsyncResult *result, GError **error); void nemo_connect_server_dialog_fill_details_async (NemoConnectServerDialog *self, GMountOperation *operation, const gchar *default_user, const gchar *default_domain, GAskPasswordFlags flags, GAsyncReadyCallback callback, gpointer user_data); gboolean nemo_connect_server_dialog_fill_details_finish (NemoConnectServerDialog *self, GAsyncResult *result); #endif /* NEMO_CONNECT_SERVER_DIALOG_H */ nemo-4.4.2/src/nemo-connect-server-operation.c000066400000000000000000000103301357442400300213000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Cosimo Cecchi */ #include #include "nemo-connect-server-operation.h" #include "nemo-connect-server-dialog.h" G_DEFINE_TYPE (NemoConnectServerOperation, nemo_connect_server_operation, GTK_TYPE_MOUNT_OPERATION); enum { PROP_DIALOG = 1, NUM_PROPERTIES }; struct _NemoConnectServerOperationDetails { NemoConnectServerDialog *dialog; }; static void fill_details_async_cb (GObject *source, GAsyncResult *result, gpointer user_data) { NemoConnectServerDialog *dialog; NemoConnectServerOperation *self; gboolean res; self = user_data; dialog = NEMO_CONNECT_SERVER_DIALOG (source); res = nemo_connect_server_dialog_fill_details_finish (dialog, result); if (!res) { g_mount_operation_reply (G_MOUNT_OPERATION (self), G_MOUNT_OPERATION_ABORTED); } else { g_mount_operation_reply (G_MOUNT_OPERATION (self), G_MOUNT_OPERATION_HANDLED); } } static void nemo_connect_server_operation_ask_password (GMountOperation *op, const gchar *message, const gchar *default_user, const gchar *default_domain, GAskPasswordFlags flags) { NemoConnectServerOperation *self; self = NEMO_CONNECT_SERVER_OPERATION (op); nemo_connect_server_dialog_fill_details_async (self->details->dialog, G_MOUNT_OPERATION (self), default_user, default_domain, flags, fill_details_async_cb, self); } static void nemo_connect_server_operation_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoConnectServerOperation *self; self = NEMO_CONNECT_SERVER_OPERATION (object); switch (property_id) { case PROP_DIALOG: self->details->dialog = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_connect_server_operation_dispose (GObject *object) { NemoConnectServerOperation *self = NEMO_CONNECT_SERVER_OPERATION (object); g_clear_object (&self->details->dialog); G_OBJECT_CLASS (nemo_connect_server_operation_parent_class)->dispose (object); } static void nemo_connect_server_operation_class_init (NemoConnectServerOperationClass *klass) { GMountOperationClass *mount_op_class; GObjectClass *object_class; GParamSpec *pspec; object_class = G_OBJECT_CLASS (klass); object_class->set_property = nemo_connect_server_operation_set_property; object_class->dispose = nemo_connect_server_operation_dispose; mount_op_class = G_MOUNT_OPERATION_CLASS (klass); mount_op_class->ask_password = nemo_connect_server_operation_ask_password; pspec = g_param_spec_object ("dialog", "The connect dialog", "The connect to server dialog", NEMO_TYPE_CONNECT_SERVER_DIALOG, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DIALOG, pspec); g_type_class_add_private (klass, sizeof (NemoConnectServerOperationDetails)); } static void nemo_connect_server_operation_init (NemoConnectServerOperation *self) { self->details = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_CONNECT_SERVER_OPERATION, NemoConnectServerOperationDetails); } GMountOperation * nemo_connect_server_operation_new (NemoConnectServerDialog *dialog) { return g_object_new (NEMO_TYPE_CONNECT_SERVER_OPERATION, "dialog", dialog, NULL); } nemo-4.4.2/src/nemo-connect-server-operation.h000066400000000000000000000041341357442400300213120ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Cosimo Cecchi */ #ifndef __NEMO_CONNECT_SERVER_OPERATION_H__ #define __NEMO_CONNECT_SERVER_OPERATION_H__ #include #include #include "nemo-connect-server-dialog.h" #define NEMO_TYPE_CONNECT_SERVER_OPERATION\ (nemo_connect_server_operation_get_type ()) #define NEMO_CONNECT_SERVER_OPERATION(obj)\ (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ NEMO_TYPE_CONNECT_SERVER_OPERATION,\ NemoConnectServerOperation)) #define NEMO_CONNECT_SERVER_OPERATION_CLASS(klass)\ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_CONNECT_SERVER_OPERATION,\ NemoConnectServerOperationClass)) #define NEMO_IS_CONNECT_SERVER_OPERATION(obj)\ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_CONNECT_SERVER_OPERATION) typedef struct _NemoConnectServerOperationDetails NemoConnectServerOperationDetails; typedef struct { GtkMountOperation parent; NemoConnectServerOperationDetails *details; } NemoConnectServerOperation; typedef struct { GtkMountOperationClass parent_class; } NemoConnectServerOperationClass; GType nemo_connect_server_operation_get_type (void); GMountOperation * nemo_connect_server_operation_new (NemoConnectServerDialog *dialog); #endif /* __NEMO_CONNECT_SERVER_OPERATION_H__ */ nemo-4.4.2/src/nemo-convert-metadata.c000066400000000000000000000220501357442400300176050ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-convert-metadata.c - Convert old metadata format to gvfs metadata. * * Copyright (C) 2009 Alexander Larsson * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: * Alexander Larsson */ #include #include #include #include #include #include #include static gboolean quiet = FALSE; static xmlNodePtr xml_get_children (xmlNodePtr parent) { if (parent == NULL) { return NULL; } return parent->children; } static xmlNodePtr xml_get_root_children (xmlDocPtr document) { return xml_get_children (xmlDocGetRootElement (document)); } static char * get_uri_from_nemo_metafile_name (const char *filename) { GString *s; char c; char *base_name, *p; int len; base_name = g_path_get_basename (filename); len = strlen (base_name); if (len <= 4 || strcmp (base_name + len - 4, ".xml") != 0) { g_free (base_name); return NULL; } base_name[len-4] = 0; s = g_string_new (NULL); p = base_name; while (*p) { c = *p++; if (c == '%') { c = g_ascii_xdigit_value (p[0]) << 4 | g_ascii_xdigit_value (p[1]); p += 2; } g_string_append_c (s, c); } g_free (base_name); return g_string_free (s, FALSE); } static struct { const char *old_key; const char *new_key; } metadata_keys[] = { {"default_component", "metadata::" NEMO_METADATA_KEY_DEFAULT_VIEW}, {"background_color", "metadata::" NEMO_METADATA_KEY_LOCATION_BACKGROUND_COLOR}, {"background_tile_image", "metadata::" NEMO_METADATA_KEY_LOCATION_BACKGROUND_IMAGE}, {"icon_view_zoom_level", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL}, {"icon_view_auto_layout", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT}, {"icon_view_sort_by", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_SORT_BY}, {"icon_view_sort_reversed", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED}, {"icon_view_keep_aligned", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED}, {"icon_view_layout_timestamp", "metadata::" NEMO_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP}, {"list_view_zoom_level", "metadata::" NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL}, {"list_view_sort_column", "metadata::" NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN}, {"list_view_sort_reversed", "metadata::" NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED}, {"list_view_visible_columns", "metadata::" NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS}, {"list_view_column_order", "metadata::" NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER}, {"compact_view_zoom_level", "metadata::" NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL}, {"window_geometry", "metadata::" NEMO_METADATA_KEY_WINDOW_GEOMETRY}, {"window_scroll_position", "metadata::" NEMO_METADATA_KEY_WINDOW_SCROLL_POSITION}, {"window_show_hidden_files", "metadata::" NEMO_METADATA_KEY_WINDOW_SHOW_HIDDEN_FILES}, {"window_maximized", "metadata::" NEMO_METADATA_KEY_WINDOW_MAXIMIZED}, {"window_sticky", "metadata::" NEMO_METADATA_KEY_WINDOW_STICKY}, {"window_keep_above", "metadata::" NEMO_METADATA_KEY_WINDOW_KEEP_ABOVE}, {"sidebar_background_color", "metadata::" NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR}, {"sidebar_background_tile_image", "metadata::" NEMO_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE}, {"sidebar_buttons", "metadata::" NEMO_METADATA_KEY_SIDEBAR_BUTTONS}, {"annotation", "metadata::" NEMO_METADATA_KEY_ANNOTATION}, {"icon_position", "metadata::" NEMO_METADATA_KEY_ICON_POSITION}, {"icon_position_timestamp", "metadata::" NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP}, {"icon_scale", "metadata::" NEMO_METADATA_KEY_ICON_SCALE}, {"custom_icon", "metadata::" NEMO_METADATA_KEY_CUSTOM_ICON}, {"keyword", "metadata::" NEMO_METADATA_KEY_EMBLEMS}, {"show_thumbnails", "metadata::" NEMO_METADATA_KEY_SHOW_THUMBNAILS}, }; static const char * convert_key_name (const char *old_key) { guint i; for (i = 0; i < G_N_ELEMENTS (metadata_keys); i++) { if (strcmp (metadata_keys[i].old_key, old_key) == 0) { return metadata_keys[i].new_key; } } return NULL; } static void parse_xml_node (GFile *file, xmlNodePtr filenode) { xmlNodePtr node; xmlAttrPtr attr; xmlChar *property; const char *new_key; GHashTable *list_keys; GList *keys, *l; GHashTableIter iter; GFileInfo *info; int i; char **strv; GError *error; info = g_file_info_new (); for (attr = filenode->properties; attr != NULL; attr = attr->next) { if (strcmp ((char *)attr->name, "name") == 0 || strcmp ((char *)attr->name, "timestamp") == 0) { continue; } new_key = convert_key_name ((const gchar *) attr->name); if (new_key) { property = xmlGetProp (filenode, attr->name); if (property) { g_file_info_set_attribute_string (info, new_key, (const gchar *) property); xmlFree (property); } } } list_keys = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); for (node = filenode->children; node != NULL; node = node->next) { for (attr = node->properties; attr != NULL; attr = attr->next) { new_key = convert_key_name ((const gchar *) node->name); if (new_key) { property = xmlGetProp (node, attr->name); if (property) { keys = g_hash_table_lookup (list_keys, new_key); keys = g_list_append (keys, property); g_hash_table_replace (list_keys, (char *)new_key, keys); } } } } g_hash_table_iter_init (&iter, list_keys); while (g_hash_table_iter_next (&iter, (void **)&new_key, (void **)&keys)) { strv = g_new0 (char *, g_list_length (keys) + 1); for (l = keys, i = 0; l != NULL; l = l->next, i++) { strv[i] = l->data; } g_file_info_set_attribute_stringv (info, new_key, strv); g_free (strv); g_list_foreach (keys, (GFunc)xmlFree, NULL); g_list_free (keys); } g_hash_table_destroy (list_keys); if (info) { error = NULL; if (!g_file_set_attributes_from_info (file, info, 0, NULL, &error)) { char *uri; uri = g_file_get_uri (file); if (!quiet) { g_print ("error setting info for %s: %s\n", uri, error->message); } g_free (uri); g_error_free (error); } g_object_unref (info); } } static void convert_xml_file (xmlDocPtr xml, GFile *dir) { xmlNodePtr node; xmlChar *name; char *unescaped_name; GFile *file; for (node = xml_get_root_children (xml); node != NULL; node = node->next) { if (strcmp ((char *)node->name, "file") == 0) { name = xmlGetProp (node, (xmlChar *)"name"); unescaped_name = g_uri_unescape_string ((char *)name, "/"); xmlFree (name); if (unescaped_name == NULL) { continue; } if (strcmp (unescaped_name, ".") == 0) { file = g_object_ref (dir); } else { file = g_file_get_child (dir, unescaped_name); } parse_xml_node (file, node); g_object_unref (file); g_free (unescaped_name); } } } static void convert_nemo_file (char *file) { GFile *dir; char *uri; gchar *contents; gsize length; xmlDocPtr xml; if (!g_file_get_contents (file, &contents, &length, NULL)) { if (!quiet) { g_print ("failed to load %s\n", file); } return; } uri = get_uri_from_nemo_metafile_name (file); if (uri == NULL) { g_free (contents); return; } dir = g_file_new_for_uri (uri); g_free (uri); xml = xmlParseMemory (contents, length); g_free (contents); if (xml == NULL) { return; } convert_xml_file (xml, dir); xmlFreeDoc (xml); } static GOptionEntry entries[] = { { "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't show errors", NULL }, { NULL } }; int main (int argc, char *argv[]) { GOptionContext *context; GError *error = NULL; int i; context = g_option_context_new (" - convert nemo metadata"); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); return 1; } if (argc < 2) { GDir *dir; char *metafile_dir; char *file; const char *entry; /* Convert all metafiles */ metafile_dir = g_build_filename (g_get_home_dir (), ".nemo/metafiles", NULL); dir = g_dir_open (metafile_dir, 0, NULL); if (dir) { while ((entry = g_dir_read_name (dir)) != NULL) { file = g_build_filename (metafile_dir, entry, NULL); if (g_str_has_suffix (file, ".xml")) convert_nemo_file (file); g_free (file); } g_dir_close (dir); } g_free (metafile_dir); } else { for (i = 1; i < argc; i++) { convert_nemo_file (argv[i]); } } return 0; } nemo-4.4.2/src/nemo-desktop-application.c000066400000000000000000000316321357442400300203270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-application: main Nemo application class. * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2010, Cosimo Cecchi * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee , * Darin Adler * Cosimo Cecchi * */ #include #include "nemo-desktop-application.h" #include "nemo-desktop-icon-view.h" #include "nemo-desktop-icon-grid-view.h" #include "nemo-icon-view.h" #include "nemo-list-view.h" #include "nemo-freedesktop-dbus.h" #include "nemo-desktop-manager.h" #include "nemo-image-properties-page.h" #include "nemo-previewer.h" #include "nemo-progress-ui-handler.h" #include "nemo-window-bookmarks.h" #include "nemo-window-private.h" #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_APPLICATION #include #include #include #include #include #include #include #include #include #include G_DEFINE_TYPE (NemoDesktopApplication, nemo_desktop_application, NEMO_TYPE_APPLICATION); struct _NemoDesktopApplicationPriv { NemoDesktopManager *desktop_manager; NemoFreedesktopDBus *fdb_manager; }; static void nemo_desktop_application_init (NemoDesktopApplication *application) { application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application, NEMO_TYPE_DESKTOP_APPLICATION, NemoDesktopApplicationPriv); } static void nemo_desktop_application_finalize (GObject *object) { NemoDesktopApplication *app = NEMO_DESKTOP_APPLICATION (object); g_clear_object (&app->priv->fdb_manager); G_OBJECT_CLASS (nemo_desktop_application_parent_class)->finalize (object); } static void init_desktop (NemoDesktopApplication *self) { /* Initialize the desktop link monitor singleton */ nemo_desktop_link_monitor_get (); nemo_desktop_metadata_init (); self->priv->desktop_manager = nemo_desktop_manager_get (); } /* from libwnck/xutils.c, comes as LGPLv2+ */ static char * latin1_to_utf8 (const char *latin1) { GString *str; const char *p; str = g_string_new (NULL); p = latin1; while (*p) { g_string_append_unichar (str, (gunichar) *p); ++p; } return g_string_free (str, FALSE); } /* derived from libwnck/xutils.c, comes as LGPLv2+ */ static void _get_wmclass (Display *xdisplay, Window xwindow, char **res_class, char **res_name) { XClassHint ch; ch.res_name = NULL; ch.res_class = NULL; gdk_error_trap_push (); XGetClassHint (xdisplay, xwindow, &ch); gdk_error_trap_pop_ignored (); if (res_class) *res_class = NULL; if (res_name) *res_name = NULL; if (ch.res_name) { if (res_name) *res_name = latin1_to_utf8 (ch.res_name); XFree (ch.res_name); } if (ch.res_class) { if (res_class) *res_class = latin1_to_utf8 (ch.res_class); XFree (ch.res_class); } } static gboolean desktop_handler_is_ignored (GdkWindow *window, gchar **ignored) { gboolean ret; Window xw; Display *xd; guint i; if (ignored == NULL) { return FALSE; } ret = FALSE; xw = gdk_x11_window_get_xid (GDK_X11_WINDOW (window)); xd = gdk_x11_display_get_xdisplay (gdk_display_get_default ()); for (i = 0; i < g_strv_length (ignored); i++) { gchar *wmclass, *wm_class_casefolded, *match_string_casefolded; _get_wmclass (xd, xw, &wmclass, NULL); if (wmclass != NULL) { wm_class_casefolded = g_utf8_casefold (wmclass, -1); match_string_casefolded = g_utf8_casefold (ignored[i], -1); if (g_strstr_len (wm_class_casefolded, -1, match_string_casefolded) != NULL) { ret = TRUE; } g_free (wm_class_casefolded); g_free (match_string_casefolded); g_free (wmclass); } if (ret == TRUE) break; } return ret; } static gboolean desktop_already_managed (void) { GdkScreen *screen; GList *windows, *iter; gboolean ret; screen = gdk_screen_get_default (); windows = gdk_screen_get_window_stack (screen); ret = FALSE; for (iter = windows; iter != NULL; iter = iter->next) { GdkWindow *window = GDK_WINDOW (iter->data); if (gdk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_DESKTOP) { GSettings *desktop_preferences = g_settings_new("org.nemo.desktop"); gchar **ignored = g_settings_get_strv (desktop_preferences, NEMO_PREFERENCES_DESKTOP_IGNORED_DESKTOP_HANDLERS); if (!desktop_handler_is_ignored (window, ignored)) { ret = TRUE; } g_strfreev (ignored); g_object_unref (desktop_preferences); break; } } g_list_free_full (windows, (GDestroyNotify) g_object_unref); if (ret) { g_warning ("Desktop already managed by another application, skipping desktop setup.\n" "To change this, modify org.nemo.desktop 'ignored-desktop-handlers'.\n"); } return ret; } static gboolean nemo_desktop_application_local_command_line (GApplication *application, gchar ***arguments, gint *exit_status) { GFile **files; gint len; gboolean version = FALSE; gboolean kill_shell = FALSE; gboolean debug = FALSE; const GOptionEntry options[] = { { "version", '\0', 0, G_OPTION_ARG_NONE, &version, N_("Show the version of the program."), NULL }, { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Enable debugging code. Example usage: 'NEMO_DEBUG=Desktop,Actions nemo-desktop --debug'. Use NEMO_DEBUG=all for more topics.", NULL }, { "quit", 'q', 0, G_OPTION_ARG_NONE, &kill_shell, N_("Quit Nemo Desktop."), NULL }, { NULL } }; GOptionContext *context; GError *error = NULL; gint argc = 0; gchar **argv = NULL; *exit_status = EXIT_SUCCESS; context = g_option_context_new (_("\n\nManage the desktop with the file manager")); g_option_context_add_main_entries (context, options, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); argv = *arguments; argc = g_strv_length (argv); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("Could not parse arguments: %s\n", error->message); g_error_free (error); *exit_status = EXIT_FAILURE; goto out; } if (version) { g_print ("nemo-desktop " VERSION "\n"); goto out; } if (debug) { g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); } if (geteuid () == 0) { g_printerr ("nemo-desktop cannot be run as root, please try again as a normal user\n"); goto out; } g_application_register (application, NULL, &error); if (error != NULL) { g_printerr ("Could not register the application: %s\n", error->message); g_error_free (error); *exit_status = EXIT_FAILURE; goto out; } if (kill_shell) { g_printerr ("Killing nemo-desktop, as requested\n"); g_action_group_activate_action (G_ACTION_GROUP (application), "quit", NULL); goto out; } if (desktop_already_managed ()) { goto out; } files = g_malloc0 (2 * sizeof (GFile *)); len = 1; files[0] = g_file_new_for_uri (EEL_DESKTOP_URI); files[1] = NULL; g_application_open (application, files, len, ""); g_object_unref (files[0]); g_free (files); out: g_option_context_free (context); return TRUE; } static void nemo_desktop_application_continue_startup (NemoApplication *app) { /* Check the user's Desktop and config directories and post warnings * if there are problems. */ nemo_application_check_required_directory (app, nemo_get_desktop_directory ()); nemo_application_check_required_directory (app, nemo_get_user_directory ()); NEMO_DESKTOP_APPLICATION (app)->priv->fdb_manager = nemo_freedesktop_dbus_new (); /* register views */ nemo_desktop_icon_view_register (); nemo_desktop_icon_grid_view_register (); nemo_icon_view_register (); } static void nemo_desktop_application_continue_quit (NemoApplication *app) { NemoDesktopApplication *self = NEMO_DESKTOP_APPLICATION (app); g_clear_object (&self->priv->desktop_manager); } static void nemo_desktop_application_open (GApplication *app, GFile **files, gint n_files, const gchar *geometry) { NemoDesktopApplication *self = NEMO_DESKTOP_APPLICATION (app); DEBUG ("Open called on the GApplication instance; %d files", n_files); if (self->priv->desktop_manager == NULL) { init_desktop (self); } /* FIXME: how to do this? */ } static void nemo_desktop_application_open_location (NemoApplication *application, GFile *location, GFile *selection, const char *startup_id, const gboolean open_in_tabs) { GAppInfo *appinfo; GError *error = NULL; GList *sel_list = NULL; appinfo = g_app_info_get_default_for_type ("inode/directory", TRUE); if (!appinfo) { g_warning ("Cannot launch file browser, no mimetype handler for inode/directory"); return; } if (selection != NULL) { sel_list = g_list_prepend (sel_list, selection); } else if (location != NULL) { sel_list = g_list_prepend (sel_list, location); } if (!g_app_info_launch (appinfo, sel_list, NULL, &error)) { gchar *uri; uri = g_file_get_uri (selection); g_warning ("Could not launch file browser to display file: %s\n", uri); g_free (uri); g_clear_error (&error); } if (sel_list != NULL) { g_list_free (sel_list); } g_clear_object (&appinfo); } static NemoWindow * nemo_desktop_application_create_window (NemoApplication *application, GdkScreen *screen) { return NULL; } static void nemo_desktop_application_class_init (NemoDesktopApplicationClass *class) { GObjectClass *object_class; GApplicationClass *application_class; NemoApplicationClass *nemo_app_class; object_class = G_OBJECT_CLASS (class); object_class->finalize = nemo_desktop_application_finalize; application_class = G_APPLICATION_CLASS (class); application_class->open = nemo_desktop_application_open; application_class->local_command_line = nemo_desktop_application_local_command_line; nemo_app_class = NEMO_APPLICATION_CLASS (class); nemo_app_class->continue_startup = nemo_desktop_application_continue_startup; nemo_app_class->create_window = nemo_desktop_application_create_window; nemo_app_class->continue_quit = nemo_desktop_application_continue_quit; nemo_app_class->open_location = nemo_desktop_application_open_location; g_type_class_add_private (class, sizeof (NemoDesktopApplicationPriv)); } NemoApplication * nemo_desktop_application_get_singleton (void) { return nemo_application_initialize_singleton (NEMO_TYPE_DESKTOP_APPLICATION, "application-id", "org.NemoDesktop", "flags", G_APPLICATION_HANDLES_OPEN, "register-session", TRUE, NULL); } nemo-4.4.2/src/nemo-desktop-application.h000066400000000000000000000044431357442400300203340ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-application: main Nemo application class. * * Copyright (C) 2000 Red Hat, Inc. * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __NEMO_DESKTOP_APPLICATION_H__ #define __NEMO_DESKTOP_APPLICATION_H__ #include #include #include #include #include "nemo-window.h" #include "nemo-application.h" #define NEMO_TYPE_DESKTOP_APPLICATION nemo_desktop_application_get_type() #define NEMO_DESKTOP_APPLICATION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_APPLICATION, NemoDesktopApplication)) #define NEMO_DESKTOP_APPLICATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_APPLICATION, NemoDesktopApplicationClass)) #define NEMO_IS_DESKTOP_APPLICATION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_APPLICATION)) #define NEMO_IS_DESKTOP_APPLICATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_APPLICATION)) #define NEMO_DESKTOP_APPLICATION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_APPLICATION, NemoDesktopApplicationClass)) typedef struct _NemoDesktopApplicationPriv NemoDesktopApplicationPriv; typedef struct { NemoApplication parent; NemoDesktopApplicationPriv *priv; } NemoDesktopApplication; typedef struct { NemoApplicationClass parent_class; } NemoDesktopApplicationClass; GType nemo_desktop_application_get_type (void); NemoApplication *nemo_desktop_application_get_singleton (void); #endif /* __NEMO_DESKTOP_APPLICATION_H__ */ nemo-4.4.2/src/nemo-desktop-icon-grid-view.c000066400000000000000000001177001357442400300206500ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-desktop-icon-view.c - implementation of icon view for managing the desktop. Copyright (C) 2000, 2001 Eazel, Inc.mou The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Mike Engber Gene Z. Ragan Miguel de Icaza */ #include #include "nemo-desktop-icon-grid-view.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-desktop-manager.h" #include "nemo-desktop-window.h" #include "nemo-desktop-overlay.h" #include "nemo-icon-view-grid-container.h" #include "nemo-view-factory.h" #include "nemo-view.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Timeout to check the desktop directory for updates */ #define RESCAN_TIMEOUT 4 struct NemoDesktopIconGridViewDetails { GdkWindow *root_window; GtkActionGroup *desktop_action_group; guint desktop_merge_id; /* For the desktop rescanning */ gulong delayed_init_signal; guint reload_desktop_timeout; gboolean pending_rescan; gboolean updating_menus; }; typedef struct { const char *action; const char *metadata_text; const NemoFileSortType sort_type; } DesktopSortCriterion; static const DesktopSortCriterion sort_criteria[] = { { "Desktop Sort by Name", "name", NEMO_FILE_SORT_BY_DISPLAY_NAME }, { "Desktop Sort by Size", "size", NEMO_FILE_SORT_BY_SIZE }, { "Desktop Sort by Type", "detailed_type", NEMO_FILE_SORT_BY_DETAILED_TYPE }, { "Desktop Sort by Date", "modification date", NEMO_FILE_SORT_BY_MTIME } }; static void real_merge_menus (NemoView *view); static void real_update_menus (NemoView *view); static void nemo_desktop_icon_grid_view_update_icon_container_fonts (NemoDesktopIconGridView *view); static void font_changed_callback (gpointer callback_data); static void nemo_desktop_icon_grid_view_constructed (GObject *object); G_DEFINE_TYPE (NemoDesktopIconGridView, nemo_desktop_icon_grid_view, NEMO_TYPE_ICON_VIEW) static char *desktop_directory; static time_t desktop_dir_modify_time; #define get_icon_container(w) nemo_icon_view_get_icon_container(NEMO_ICON_VIEW (w)) static void desktop_directory_changed_callback (gpointer callback_data) { g_free (desktop_directory); desktop_directory = nemo_get_desktop_directory (); } static void update_margins (NemoDesktopIconGridView *icon_view) { NemoIconContainer *icon_container; gint current_monitor; gint l, r, t, b; icon_container = get_icon_container (icon_view); g_object_get (NEMO_DESKTOP_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (icon_view))), "monitor", ¤t_monitor, NULL); nemo_desktop_manager_get_margins (nemo_desktop_manager_get (), current_monitor, &l, &r, &t, &b); nemo_icon_container_set_margins (icon_container, l, r, t, b); } static GdkFilterReturn gdk_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XEvent *xevent = gdk_xevent; NemoDesktopIconGridView *icon_view; icon_view = NEMO_DESKTOP_ICON_GRID_VIEW (data); switch (xevent->type) { case PropertyNotify: if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_NET_WORKAREA")) { update_margins (icon_view); } break; default: break; } return GDK_FILTER_CONTINUE; } static const char * real_get_id (NemoView *view) { return NEMO_DESKTOP_ICON_GRID_VIEW_IID; } static gboolean should_show_file_on_current_monitor (NemoView *view, NemoFile *file) { gint current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (view)); gint file_monitor = nemo_file_get_monitor_number (file); NemoDesktopManager *dm = nemo_desktop_manager_get (); if (current_monitor == file_monitor) { return TRUE; } if (nemo_desktop_manager_get_primary_only (dm)) { return TRUE; } if (file_monitor > -1 && !g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_SHOW_ORPHANED_DESKTOP_ICONS)) { return FALSE; } if (file_monitor == -1) { /* New file, no previous metadata - this should go on the primary monitor */ return nemo_desktop_manager_get_monitor_is_primary (dm, current_monitor); } if (!nemo_desktop_manager_get_monitor_is_active (dm, file_monitor)) { nemo_file_set_is_desktop_orphan (file, TRUE); if (nemo_desktop_manager_get_monitor_is_primary (dm, current_monitor)) { return TRUE; } } return FALSE; } static void nemo_desktop_icon_grid_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { /* This used to assert that 'directory == nemo_view_get_model (view)', but that * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens. * It seems that somehow we get a files_changed event sent to the view from a directory * that isn't the model, but the code disables the monitor and signal callback handlers when * changing directories. Maybe we can get some more information when this happens. * Further discussion in bug #368178. */ if (directory != nemo_view_get_model (view)) { char *file_uri, *dir_uri, *model_uri; file_uri = nemo_file_get_uri (file); dir_uri = nemo_directory_get_uri (directory); model_uri = nemo_directory_get_uri (nemo_view_get_model (view)); g_warning ("nemo_icon_view_remove_file() - directory not icon view model, shouldn't happen.\n" "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n" "If you see this, please add this info to http://bugzilla.gnome.org/show_bug.cgi?id=368178", file, file_uri, directory, dir_uri, nemo_view_get_model (view), model_uri, nemo_view_get_loading (view)); g_free (file_uri); g_free (dir_uri); g_free (model_uri); } if (nemo_icon_container_remove (get_icon_container (view), NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_unref (file); } } static void nemo_desktop_icon_grid_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; NemoIconContainer *icon_container; g_assert (directory == nemo_view_get_model (view)); if (!should_show_file_on_current_monitor (view, file)) { return; } icon_view = NEMO_ICON_VIEW (view); icon_container = get_icon_container (icon_view); if (nemo_icon_container_add (icon_container, NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_ref (file); } } static void nemo_desktop_icon_grid_view_file_changed (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; g_assert (directory == nemo_view_get_model (view)); g_return_if_fail (view != NULL); icon_view = NEMO_ICON_VIEW (view); if (!should_show_file_on_current_monitor (view, file)) { nemo_desktop_icon_grid_view_remove_file (view, file, directory); } else { nemo_icon_container_request_update (get_icon_container (icon_view), NEMO_ICON_CONTAINER_ICON_DATA (file)); } } static void unrealized_callback (GtkWidget *widget, NemoDesktopIconGridView *desktop_icon_grid_view) { g_return_if_fail (desktop_icon_grid_view->details->root_window != NULL); gdk_window_remove_filter (desktop_icon_grid_view->details->root_window, gdk_filter_func, desktop_icon_grid_view); desktop_icon_grid_view->details->root_window = NULL; } static void realized_callback (GtkWidget *widget, NemoDesktopIconGridView *desktop_icon_grid_view) { GdkWindow *root_window; GdkScreen *screen; g_return_if_fail (desktop_icon_grid_view->details->root_window == NULL); screen = gtk_widget_get_screen (widget); root_window = gdk_screen_get_root_window (screen); desktop_icon_grid_view->details->root_window = root_window; update_margins (desktop_icon_grid_view); /* Setup the property filter */ gdk_window_set_events (root_window, GDK_PROPERTY_CHANGE_MASK); gdk_window_add_filter (root_window, gdk_filter_func, desktop_icon_grid_view); } static void nemo_desktop_icon_grid_view_dispose (GObject *object) { NemoDesktopIconGridView *icon_view; GtkUIManager *ui_manager; icon_view = NEMO_DESKTOP_ICON_GRID_VIEW (object); /* Remove desktop rescan timeout. */ if (icon_view->details->reload_desktop_timeout != 0) { g_source_remove (icon_view->details->reload_desktop_timeout); icon_view->details->reload_desktop_timeout = 0; } ui_manager = nemo_view_get_ui_manager (NEMO_VIEW (icon_view)); if (ui_manager != NULL) { nemo_ui_unmerge_ui (ui_manager, &icon_view->details->desktop_merge_id, &icon_view->details->desktop_action_group); } g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, font_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_preferences, desktop_directory_changed_callback, NULL); g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences, nemo_view_update_menus, icon_view); G_OBJECT_CLASS (nemo_desktop_icon_grid_view_parent_class)->dispose (object); } static void nemo_desktop_icon_grid_view_class_init (NemoDesktopIconGridViewClass *class) { NemoViewClass *vclass; vclass = NEMO_VIEW_CLASS (class); G_OBJECT_CLASS (class)->dispose = nemo_desktop_icon_grid_view_dispose; G_OBJECT_CLASS (class)->constructed = nemo_desktop_icon_grid_view_constructed; NEMO_ICON_VIEW_CLASS (class)->use_grid_container = TRUE; vclass->merge_menus = real_merge_menus; vclass->update_menus = real_update_menus; vclass->get_view_id = real_get_id; vclass->add_file = nemo_desktop_icon_grid_view_add_file; vclass->file_changed = nemo_desktop_icon_grid_view_file_changed; vclass->remove_file = nemo_desktop_icon_grid_view_remove_file; #if GTK_CHECK_VERSION(3, 21, 0) GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class); gtk_widget_class_set_css_name (wclass, "nemo-desktop-icon-view"); #endif g_type_class_add_private (class, sizeof (NemoDesktopIconGridViewDetails)); } static void nemo_desktop_icon_grid_view_handle_middle_click (NemoIconContainer *icon_container, GdkEventButton *event, NemoDesktopIconGridView *desktop_icon_grid_view) { XButtonEvent x_event; GdkDevice *keyboard = NULL, *pointer = NULL, *cur; GdkDeviceManager *manager; GList *list, *l; manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (icon_container))); list = gdk_device_manager_list_devices (manager, GDK_DEVICE_TYPE_MASTER); for (l = list; l != NULL; l = l->next) { cur = l->data; if (pointer == NULL && (gdk_device_get_source (cur) == GDK_SOURCE_MOUSE)) { pointer = cur; } if (keyboard == NULL && (gdk_device_get_source (cur) == GDK_SOURCE_KEYBOARD)) { keyboard = cur; } if (pointer != NULL && keyboard != NULL) { break; } } g_list_free (list); /* During a mouse click we have the pointer and keyboard grab. * We will send a fake event to the root window which will cause it * to try to get the grab so we need to let go ourselves. */ if (pointer != NULL) { gdk_device_ungrab (pointer, GDK_CURRENT_TIME); } if (keyboard != NULL) { gdk_device_ungrab (keyboard, GDK_CURRENT_TIME); } /* Stop the event because we don't want anyone else dealing with it. */ gdk_flush (); g_signal_stop_emission_by_name (icon_container, "middle_click"); /* build an X event to represent the middle click. */ x_event.type = ButtonPress; x_event.send_event = True; x_event.display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); x_event.window = GDK_ROOT_WINDOW (); x_event.root = GDK_ROOT_WINDOW (); x_event.subwindow = 0; x_event.time = event->time; x_event.x = event->x; x_event.y = event->y; x_event.x_root = event->x_root; x_event.y_root = event->y_root; x_event.state = event->state; x_event.button = event->button; x_event.same_screen = True; /* Send it to the root window, the window manager will handle it. */ XSendEvent (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (), True, ButtonPressMask, (XEvent *) &x_event); } static void desktop_icon_container_realize (GtkWidget *widget, NemoDesktopIconGridView *desktop_icon_grid_view) { GdkWindow *bin_window; GdkRGBA transparent = { 0, 0, 0, 0 }; bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); gdk_window_set_background_rgba (bin_window, &transparent); } static gboolean do_desktop_rescan (gpointer data) { NemoDesktopIconGridView *desktop_icon_grid_view; struct stat buf; desktop_icon_grid_view = NEMO_DESKTOP_ICON_GRID_VIEW (data); if (desktop_icon_grid_view->details->pending_rescan) { return TRUE; } if (stat (desktop_directory, &buf) == -1) { return TRUE; } if (buf.st_ctime == desktop_dir_modify_time) { return TRUE; } desktop_icon_grid_view->details->pending_rescan = TRUE; nemo_directory_force_reload (nemo_view_get_model (NEMO_VIEW (desktop_icon_grid_view))); return TRUE; } static void done_loading (NemoDirectory *model, NemoDesktopIconGridView *desktop_icon_grid_view) { struct stat buf; desktop_icon_grid_view->details->pending_rescan = FALSE; if (stat (desktop_directory, &buf) == -1) { return; } desktop_dir_modify_time = buf.st_ctime; } /* This function is used because the NemoDirectory model does not * exist always in the desktop_icon_grid_view, so we wait until it has been * instantiated. */ static void delayed_init (NemoDesktopIconGridView *desktop_icon_grid_view) { /* Keep track of the load time. */ g_signal_connect_object (nemo_view_get_model (NEMO_VIEW (desktop_icon_grid_view)), "done_loading", G_CALLBACK (done_loading), desktop_icon_grid_view, 0); /* Monitor desktop directory. */ desktop_icon_grid_view->details->reload_desktop_timeout = g_timeout_add_seconds (RESCAN_TIMEOUT, do_desktop_rescan, desktop_icon_grid_view); g_signal_handler_disconnect (desktop_icon_grid_view, desktop_icon_grid_view->details->delayed_init_signal); desktop_icon_grid_view->details->delayed_init_signal = 0; desktop_icon_grid_view->details->updating_menus = FALSE; } static void font_changed_callback (gpointer callback_data) { g_return_if_fail (NEMO_IS_DESKTOP_ICON_GRID_VIEW (callback_data)); nemo_desktop_icon_grid_view_update_icon_container_fonts (NEMO_DESKTOP_ICON_GRID_VIEW (callback_data)); } static void nemo_desktop_icon_grid_view_update_icon_container_fonts (NemoDesktopIconGridView *icon_view) { NemoIconContainer *icon_container; char *font; icon_container = get_icon_container (icon_view); g_assert (icon_container != NULL); font = g_settings_get_string (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_FONT); nemo_icon_container_set_font (icon_container, font); g_free (font); } static void nemo_desktop_icon_grid_view_init (NemoDesktopIconGridView *desktop_icon_grid_view) { desktop_icon_grid_view->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_icon_grid_view, NEMO_TYPE_DESKTOP_ICON_GRID_VIEW, NemoDesktopIconGridViewDetails); } static void nemo_desktop_icon_grid_view_constructed (GObject *object) { NemoDesktopIconGridView *desktop_icon_grid_view; NemoIconContainer *icon_container; GtkAllocation allocation; GtkAdjustment *hadj, *vadj; desktop_icon_grid_view = NEMO_DESKTOP_ICON_GRID_VIEW (object); G_OBJECT_CLASS (nemo_desktop_icon_grid_view_parent_class)->constructed (G_OBJECT (desktop_icon_grid_view)); if (desktop_directory == NULL) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_directory_changed_callback), NULL); desktop_directory_changed_callback (NULL); } icon_container = get_icon_container (desktop_icon_grid_view); nemo_icon_container_set_use_drop_shadows (icon_container, TRUE); nemo_icon_view_grid_container_set_sort_desktop (NEMO_ICON_VIEW_GRID_CONTAINER (icon_container), TRUE); /* Do a reload on the desktop if we don't have FAM, a smarter * way to keep track of the items on the desktop. */ if (!nemo_monitor_active ()) { desktop_icon_grid_view->details->delayed_init_signal = g_signal_connect_object (desktop_icon_grid_view, "begin_loading", G_CALLBACK (delayed_init), desktop_icon_grid_view, 0); } nemo_icon_container_set_is_fixed_size (icon_container, TRUE); nemo_icon_container_set_is_desktop (icon_container, TRUE); nemo_icon_container_set_keep_aligned (icon_container, TRUE); NEMO_ICON_VIEW_GRID_CONTAINER (icon_container)->horizontal = FALSE; nemo_icon_container_set_store_layout_timestamps (icon_container, TRUE); /* Set allocation to be at 0, 0 */ gtk_widget_get_allocation (GTK_WIDGET (icon_container), &allocation); allocation.x = 0; allocation.y = 0; gtk_widget_set_allocation (GTK_WIDGET (icon_container), &allocation); gtk_widget_queue_resize (GTK_WIDGET (icon_container)); hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (icon_container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (icon_container)); gtk_adjustment_set_value (hadj, 0); gtk_adjustment_set_value (vadj, 0); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (desktop_icon_grid_view), GTK_SHADOW_NONE); nemo_view_ignore_hidden_file_preferences (NEMO_VIEW (desktop_icon_grid_view)); nemo_view_set_show_foreign (NEMO_VIEW (desktop_icon_grid_view), FALSE); g_signal_connect_object (icon_container, "middle_click", G_CALLBACK (nemo_desktop_icon_grid_view_handle_middle_click), desktop_icon_grid_view, 0); g_signal_connect_object (icon_container, "realize", G_CALLBACK (desktop_icon_container_realize), desktop_icon_grid_view, 0); g_signal_connect_object (desktop_icon_grid_view, "realize", G_CALLBACK (realized_callback), desktop_icon_grid_view, 0); g_signal_connect_object (desktop_icon_grid_view, "unrealize", G_CALLBACK (unrealized_callback), desktop_icon_grid_view, 0); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_FONT, G_CALLBACK (font_changed_callback), desktop_icon_grid_view); nemo_desktop_icon_grid_view_update_icon_container_fonts (desktop_icon_grid_view); g_signal_connect_swapped (gnome_lockdown_preferences, "changed::" NEMO_PREFERENCES_LOCKDOWN_COMMAND_LINE, G_CALLBACK (nemo_view_update_menus), desktop_icon_grid_view); } static void action_empty_trash_conditional_callback (GtkAction *action, gpointer data) { g_assert (NEMO_IS_VIEW (data)); nemo_file_operations_empty_trash (GTK_WIDGET (data)); } static void clear_orphan_states (NemoDesktopIconGridView *view) { GList *icons; for (icons = get_icon_container (view)->details->icons; icons != NULL; icons = icons->next) { NemoFile *file; NemoIcon *icon; icon = icons->data; file = NEMO_FILE (icon->data); nemo_file_set_is_desktop_orphan (file, FALSE); } } static void action_auto_arrange_callback (GtkAction *action, NemoDesktopIconGridView *view) { gboolean new; g_assert (NEMO_IS_VIEW (view)); if (view->details->updating_menus) { return; } new = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); clear_orphan_states (view); nemo_icon_view_set_sort_reversed (NEMO_ICON_VIEW (view), FALSE, TRUE); nemo_icon_container_set_auto_layout (get_icon_container (view), new); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } static void action_reverse_sort_callback (GtkAction *action, NemoDesktopIconGridView *view) { NemoIconContainer *container; gboolean new; g_assert (NEMO_IS_VIEW (view)); if (view->details->updating_menus) { return; } container = get_icon_container (view); new = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); clear_orphan_states (view); container->details->needs_resort = TRUE; nemo_icon_view_set_sort_reversed (NEMO_ICON_VIEW (view), new, TRUE); nemo_icon_container_sort (get_icon_container (view)); nemo_icon_container_redo_layout (container); nemo_view_update_menus (NEMO_VIEW (view)); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } static void set_sort_type (NemoDesktopIconGridView *view, GtkAction *action, NemoFileSortType type) { if (view->details->updating_menus) { return; } clear_orphan_states (view); nemo_icon_view_set_sort_reversed (NEMO_ICON_VIEW (view), FALSE, TRUE); nemo_icon_view_set_sort_criterion_by_sort_type (NEMO_ICON_VIEW (view), type); nemo_icon_container_redo_layout (get_icon_container (view)); nemo_view_update_menus (NEMO_VIEW (view)); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } static void action_show_overlay (GtkAction *action, NemoDesktopIconGridView *view) { nemo_desktop_manager_show_desktop_overlay (nemo_desktop_manager_get (), nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (view))); } static void set_direction (NemoDesktopIconGridView *view, gboolean horizontal) { NemoFile *file; NemoIconContainer *container; if (view->details->updating_menus) { return; } clear_orphan_states (view); container = get_icon_container (view); file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); nemo_icon_container_set_horizontal_layout (container, horizontal); container->details->needs_resort = TRUE; nemo_icon_view_set_sort_reversed (NEMO_ICON_VIEW (view), FALSE, TRUE); nemo_icon_container_sort (get_icon_container (view)); nemo_icon_container_redo_layout (get_icon_container (view)); nemo_icon_view_set_directory_horizontal_layout (NEMO_ICON_VIEW (view), file, horizontal); nemo_view_update_menus (NEMO_VIEW (view)); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } static void action_layout_direction_callback (GtkAction *action, GtkRadioAction *current, NemoDesktopIconGridView *view) { NemoDesktopLayoutDirection direction; direction = gtk_radio_action_get_current_value (current); switch (direction) { case DESKTOP_ARRANGE_HORIZONTAL: set_direction (view, TRUE); break; case DESKTOP_ARRANGE_VERTICAL: set_direction (view, FALSE); break; default: break; } } static void action_desktop_size_callback (GtkAction *action, GtkRadioAction *current, NemoDesktopIconGridView *view) { NemoZoomLevel level; NemoIconContainer *container; if (view->details->updating_menus) { return; } container = get_icon_container (view); level = gtk_radio_action_get_current_value (current); nemo_view_zoom_to_level (NEMO_VIEW (view), level); clear_orphan_states (view); /* TODO: Instead of switching back to defaults, re-align the existing icons * into the new slots. This is complicated, due to how the redo_layout_internal * function works. */ container->details->needs_resort = TRUE; container->details->auto_layout = TRUE; nemo_icon_container_redo_layout (container); nemo_view_update_menus (NEMO_VIEW (view)); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } static void action_sort_order_callback (GtkAction *action, GtkRadioAction *current, NemoDesktopIconGridView *view) { NemoFileSortType type; g_assert (NEMO_IS_VIEW (view)); if (view->details->updating_menus) { return; } type = gtk_radio_action_get_current_value (current); set_sort_type (view, action, type); } static gboolean trash_link_is_selection (NemoView *view) { GList *selection; NemoDesktopLink *link; gboolean result; result = FALSE; selection = nemo_view_get_selection (view); if ((g_list_length (selection) == 1) && NEMO_IS_DESKTOP_ICON_FILE (selection->data)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (selection->data)); /* link may be NULL if the link was recently removed (unmounted) */ if (link != NULL && nemo_desktop_link_get_link_type (link) == NEMO_DESKTOP_LINK_TRASH) { result = TRUE; } if (link) { g_object_unref (link); } } nemo_file_list_free (selection); return result; } static void real_update_menus (NemoView *view) { NemoDesktopIconGridView *desktop_view; NemoIconContainer *container; NemoFile *file; char *label; gboolean include_empty_trash; gboolean horizontal_layout; gboolean auto_arrange, reversed; gint i; GtkUIManager *ui_manager; GtkAction *action; GList *groups, *l; g_assert (NEMO_IS_DESKTOP_ICON_GRID_VIEW (view)); container = get_icon_container (view); desktop_view = NEMO_DESKTOP_ICON_GRID_VIEW (view); desktop_view->details->updating_menus = TRUE; NEMO_VIEW_CLASS (nemo_desktop_icon_grid_view_parent_class)->update_menus (view); /* Empty Trash */ include_empty_trash = trash_link_is_selection (view); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, NEMO_ACTION_EMPTY_TRASH_CONDITIONAL); gtk_action_set_visible (action, include_empty_trash); if (include_empty_trash) { label = g_strdup (_("E_mpty Trash")); g_object_set (action , "label", label, NULL); gtk_action_set_sensitive (action, !nemo_trash_monitor_is_empty ()); g_free (label); } file = nemo_view_get_directory_as_file (NEMO_VIEW (desktop_view)); horizontal_layout = nemo_icon_view_get_directory_horizontal_layout (NEMO_ICON_VIEW (desktop_view), file); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Horizontal Layout"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), horizontal_layout); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Vertical Layout"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !horizontal_layout); auto_arrange = nemo_icon_container_is_auto_layout (container); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Autoarrange"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), auto_arrange); reversed = nemo_icon_view_get_directory_sort_reversed (NEMO_ICON_VIEW (desktop_view), file); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Reverse Sort"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), reversed); gchar *order; order = nemo_icon_view_get_directory_sort_by (NEMO_ICON_VIEW (desktop_view), file); for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) { action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, sort_criteria[i].action); if (g_strcmp0 (order, sort_criteria[i].metadata_text) == 0) { gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), sort_criteria[i].sort_type); break; } } g_free (order); /* Update zoom radio */ switch (nemo_view_get_zoom_level (NEMO_VIEW (desktop_view))) { case NEMO_ZOOM_LEVEL_SMALLER: action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Smaller"); break; case NEMO_ZOOM_LEVEL_SMALL: action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Small"); break; case NEMO_ZOOM_LEVEL_LARGE: action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Large"); break; case NEMO_ZOOM_LEVEL_LARGER: action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Larger"); break; case NEMO_ZOOM_LEVEL_STANDARD: case NEMO_ZOOM_LEVEL_NULL: case NEMO_ZOOM_LEVEL_SMALLEST: case NEMO_ZOOM_LEVEL_LARGEST: default: action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, "Desktop Normal"); break; } gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); desktop_view->details->updating_menus = FALSE; ui_manager = nemo_view_get_ui_manager (view); groups = gtk_ui_manager_get_action_groups (ui_manager); /* These actions are set up in NemoIconView, but we want to replace it all with the * desktop submenu. This could be avoided by creating an additional subclass of NemoIconView * to implement these things, but this is simpler for now. */ for (l = groups; l != NULL; l = l->next) { GtkActionGroup *group; group = GTK_ACTION_GROUP (l->data); action = gtk_action_group_get_action (group, NEMO_ACTION_CLEAN_UP); if (action != NULL) { gtk_action_set_visible (action, FALSE); } action = gtk_action_group_get_action (group, NEMO_ACTION_KEEP_ALIGNED); if (action != NULL) { gtk_action_set_visible (action, FALSE); } action = gtk_action_group_get_action (group, NEMO_ACTION_ARRANGE_ITEMS); if (action != NULL) { gtk_action_set_visible (action, FALSE); } } } static const GtkToggleActionEntry desktop_grid_toggle_entries[] = { /* name, stock id */ { "Desktop Autoarrange", NULL, /* label, accelerator */ N_("Auto-arrange"), NULL, /* tooltip */ NULL, G_CALLBACK (action_auto_arrange_callback), 0 }, /* name, stock id */ { "Desktop Reverse Sort", NULL, /* label, accelerator */ N_("Reverse sort"), NULL, /* tooltip */ NULL, G_CALLBACK (action_reverse_sort_callback), 0 } }; static const GtkRadioActionEntry desktop_size_radio_entries[] = { { "Desktop Smaller", NULL, N_("Smaller"), NULL, NULL, NEMO_ZOOM_LEVEL_SMALLER }, { "Desktop Small", NULL, N_("Small"), NULL, NULL, NEMO_ZOOM_LEVEL_SMALL }, { "Desktop Normal", NULL, N_("Normal"), NULL, NULL, NEMO_ZOOM_LEVEL_STANDARD }, { "Desktop Large", NULL, N_("Large"), NULL, NULL, NEMO_ZOOM_LEVEL_LARGE }, { "Desktop Larger", NULL, N_("Larger"), NULL, NULL, NEMO_ZOOM_LEVEL_LARGER }, }; static const GtkRadioActionEntry desktop_direction_radio_entries[] = { { "Vertical Layout", NULL, N_("_Vertical"), NULL, NULL, DESKTOP_ARRANGE_VERTICAL }, { "Horizontal Layout", NULL, N_("_Horizontal"), NULL, NULL, DESKTOP_ARRANGE_HORIZONTAL } }; static const GtkRadioActionEntry desktop_sort_radio_entries[] = { { "Desktop Sort by Name", NULL, N_("Name"), NULL, NULL, NEMO_FILE_SORT_BY_DISPLAY_NAME }, { "Desktop Sort by Size", NULL, N_("Size"), NULL, NULL, NEMO_FILE_SORT_BY_SIZE }, { "Desktop Sort by Type", NULL, N_("Type"), NULL, NULL, NEMO_FILE_SORT_BY_DETAILED_TYPE }, { "Desktop Sort by Date", NULL, N_("Date"), NULL, NULL, NEMO_FILE_SORT_BY_MTIME } }; static const GtkActionEntry desktop_grid_entries[] = { /* name, stock id, label */ { "Desktop Submenu", NULL, N_("_Sort") }, /* name, stock id, label */ { "Desktop Zoom", NULL, N_("_Icon Size") }, /* name, stock id */ { "Empty Trash Conditional", NULL, /* label, accelerator */ N_("Empty Trash"), NULL, /* tooltip */ N_("Delete all items in the Trash"), G_CALLBACK (action_empty_trash_conditional_callback) }, { "Show Desktop Overlay", NULL, N_("_Customize"), NULL, N_("Adjust the desktop layout for this monitor"), G_CALLBACK (action_show_overlay) }, }; static void real_merge_menus (NemoView *view) { NemoDesktopIconGridView *desktop_view; GtkUIManager *ui_manager; GtkActionGroup *action_group; NEMO_VIEW_CLASS (nemo_desktop_icon_grid_view_parent_class)->merge_menus (view); desktop_view = NEMO_DESKTOP_ICON_GRID_VIEW (view); ui_manager = nemo_view_get_ui_manager (view); action_group = gtk_action_group_new ("DesktopViewActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); desktop_view->details->desktop_action_group = action_group; gtk_action_group_add_actions (action_group, desktop_grid_entries, G_N_ELEMENTS (desktop_grid_entries), view); gtk_action_group_add_toggle_actions (action_group, desktop_grid_toggle_entries, G_N_ELEMENTS (desktop_grid_toggle_entries), view); gtk_action_group_add_radio_actions (action_group, desktop_size_radio_entries, G_N_ELEMENTS (desktop_size_radio_entries), -1, G_CALLBACK (action_desktop_size_callback), view); gtk_action_group_add_radio_actions (action_group, desktop_direction_radio_entries, G_N_ELEMENTS (desktop_direction_radio_entries), -1, G_CALLBACK (action_layout_direction_callback), view); gtk_action_group_add_radio_actions (action_group, desktop_sort_radio_entries, G_N_ELEMENTS (desktop_sort_radio_entries), -1, G_CALLBACK (action_sort_order_callback), view); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui manager */ desktop_view->details->desktop_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-desktop-icon-grid-view-ui.xml", NULL); } static NemoView * nemo_desktop_icon_grid_view_create (NemoWindowSlot *slot) { NemoIconView *view; view = g_object_new (NEMO_TYPE_DESKTOP_ICON_GRID_VIEW, "window-slot", slot, "supports-zooming", TRUE, "supports-auto-layout", TRUE, "is-desktop", TRUE, "supports-keep-aligned", TRUE, "supports-labels-beside-icons", FALSE, NULL); return NEMO_VIEW (view); } static gboolean nemo_desktop_icon_grid_view_supports_uri (const char *uri, GFileType file_type, const char *mime_type) { if (g_str_has_prefix (uri, EEL_DESKTOP_URI)) { return TRUE; } return FALSE; } static NemoViewInfo nemo_desktop_icon_grid_view = { (char *)NEMO_DESKTOP_ICON_GRID_VIEW_IID, (char *)"Desktop Grid View", (char *)"_Desktop", (char *)N_("The desktop view encountered an error."), (char *)N_("The desktop view encountered an error while starting up."), (char *)"Display this location with the desktop grid view.", nemo_desktop_icon_grid_view_create, nemo_desktop_icon_grid_view_supports_uri }; void nemo_desktop_icon_grid_view_register (void) { nemo_desktop_icon_grid_view.error_label = _(nemo_desktop_icon_grid_view.error_label); nemo_desktop_icon_grid_view.startup_error_label = _(nemo_desktop_icon_grid_view.startup_error_label); nemo_view_factory_register (&nemo_desktop_icon_grid_view); } /* CHEATING: These should be part of NemoIconView and our subclasses should implement it but only * one subclass will ever support it and we'll eventually get rid of the other */ GtkActionGroup * nemo_desktop_icon_grid_view_get_action_group (NemoDesktopIconGridView *view) { return view->details->desktop_action_group; } void nemo_desktop_icon_grid_view_set_grid_adjusts (NemoDesktopIconGridView *view, gint h_adjust, gint v_adjust) { NemoIconContainer *container; NemoFile *file; if (view->details->updating_menus) { return; } container = get_icon_container (view); clear_orphan_states (view); file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); nemo_icon_container_set_grid_adjusts (container, h_adjust, v_adjust); container->details->needs_resort = TRUE; container->details->auto_layout = TRUE; nemo_icon_view_set_directory_grid_adjusts (NEMO_ICON_VIEW (view), file, h_adjust, v_adjust); nemo_icon_container_redo_layout (container); nemo_view_update_menus (NEMO_VIEW (view)); nemo_icon_container_store_layout_timestamps_now (get_icon_container (view)); } nemo-4.4.2/src/nemo-desktop-icon-grid-view.h000066400000000000000000000051561357442400300206560ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-icon-view.h - interface for icon view of directory. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Mike Engber */ #ifndef NEMO_DESKTOP_ICON_GRID_VIEW_H #define NEMO_DESKTOP_ICON_GRID_VIEW_H #include "nemo-icon-view.h" #define NEMO_TYPE_DESKTOP_ICON_GRID_VIEW nemo_desktop_icon_grid_view_get_type() #define NEMO_DESKTOP_ICON_GRID_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_ICON_GRID_VIEW, NemoDesktopIconGridView)) #define NEMO_DESKTOP_ICON_GRID_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_ICON_GRID_VIEW, NemoDesktopIconGridViewClass)) #define NEMO_IS_DESKTOP_ICON_GRID_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_ICON_GRID_VIEW)) #define NEMO_IS_DESKTOP_ICON_GRID_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_ICON_GRID_VIEW)) #define NEMO_DESKTOP_ICON_GRID_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_ICON_GRID_VIEW, NemoDesktopIconGridViewClass)) typedef struct NemoDesktopIconGridViewDetails NemoDesktopIconGridViewDetails; typedef struct { NemoIconView parent; NemoDesktopIconGridViewDetails *details; } NemoDesktopIconGridView; typedef struct { NemoIconViewClass parent_class; } NemoDesktopIconGridViewClass; /* GObject support */ GType nemo_desktop_icon_grid_view_get_type (void); void nemo_desktop_icon_grid_view_register (void); GtkActionGroup *nemo_desktop_icon_grid_view_get_action_group (NemoDesktopIconGridView *view); void nemo_desktop_icon_grid_view_set_grid_adjusts (NemoDesktopIconGridView *view, gint h_adjust, gint v_adjust); #endif /* NEMO_DESKTOP_ICON_GRID_VIEW_H */ nemo-4.4.2/src/nemo-desktop-icon-view.c000066400000000000000000000614711357442400300177300ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-desktop-icon-view.c - implementation of icon view for managing the desktop. Copyright (C) 2000, 2001 Eazel, Inc.mou The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Mike Engber Gene Z. Ragan Miguel de Icaza */ #include #include "nemo-desktop-icon-view.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-desktop-manager.h" #include "nemo-desktop-window.h" #include "nemo-icon-view-container.h" #include "nemo-view-factory.h" #include "nemo-view.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Timeout to check the desktop directory for updates */ #define RESCAN_TIMEOUT 4 struct NemoDesktopIconViewDetails { GdkWindow *root_window; GtkActionGroup *desktop_action_group; guint desktop_merge_id; /* For the desktop rescanning */ gulong delayed_init_signal; guint reload_desktop_timeout; gboolean pending_rescan; }; static void default_zoom_level_changed (gpointer user_data); static void real_merge_menus (NemoView *view); static void real_update_menus (NemoView *view); static void nemo_desktop_icon_view_update_icon_container_fonts (NemoDesktopIconView *view); static void font_changed_callback (gpointer callback_data); static void nemo_desktop_icon_view_constructed (GObject *object); G_DEFINE_TYPE (NemoDesktopIconView, nemo_desktop_icon_view, NEMO_TYPE_ICON_VIEW) static char *desktop_directory; static time_t desktop_dir_modify_time; #define get_icon_container(w) nemo_icon_view_get_icon_container(NEMO_ICON_VIEW (w)) static void desktop_directory_changed_callback (gpointer callback_data) { g_free (desktop_directory); desktop_directory = nemo_get_desktop_directory (); } static void update_margins (NemoDesktopIconView *icon_view) { NemoIconContainer *icon_container; gint current_monitor; gint l, r, t, b; icon_container = get_icon_container (icon_view); g_object_get (NEMO_DESKTOP_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (icon_view))), "monitor", ¤t_monitor, NULL); nemo_desktop_manager_get_margins (nemo_desktop_manager_get (), current_monitor, &l, &r, &t, &b); nemo_icon_container_set_margins (icon_container, l, r, t, b); } static GdkFilterReturn gdk_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XEvent *xevent = gdk_xevent; NemoDesktopIconView *icon_view; icon_view = NEMO_DESKTOP_ICON_VIEW (data); switch (xevent->type) { case PropertyNotify: if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_NET_WORKAREA")) { update_margins (icon_view); } break; default: break; } return GDK_FILTER_CONTINUE; } static const char * real_get_id (NemoView *view) { return NEMO_DESKTOP_ICON_VIEW_ID; } static gboolean should_show_file_on_current_monitor (NemoView *view, NemoFile *file) { gint current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (view)); gint file_monitor = nemo_file_get_monitor_number (file); NemoDesktopManager *dm = nemo_desktop_manager_get (); if (current_monitor == file_monitor) { return TRUE; } if (nemo_desktop_manager_get_primary_only (dm)) { return TRUE; } if (file_monitor > -1 && !g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_SHOW_ORPHANED_DESKTOP_ICONS)) { return FALSE; } if (file_monitor == -1) { /* New file, no previous metadata - this should go on the primary monitor */ return nemo_desktop_manager_get_monitor_is_primary (dm, current_monitor); } if (!nemo_desktop_manager_get_monitor_is_active (dm, file_monitor)) { nemo_file_set_is_desktop_orphan (file, TRUE); if (nemo_desktop_manager_get_monitor_is_primary (dm, current_monitor)) { return TRUE; } } return FALSE; } static void real_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; NemoIconContainer *icon_container; g_assert (directory == nemo_view_get_model (view)); if (!should_show_file_on_current_monitor (view, file)) { return; } icon_view = NEMO_ICON_VIEW (view); icon_container = get_icon_container (icon_view); if (nemo_icon_container_add (icon_container, NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_ref (file); } } static void unrealized_callback (GtkWidget *widget, NemoDesktopIconView *desktop_icon_view) { g_return_if_fail (desktop_icon_view->details->root_window != NULL); gdk_window_remove_filter (desktop_icon_view->details->root_window, gdk_filter_func, desktop_icon_view); desktop_icon_view->details->root_window = NULL; } static void realized_callback (GtkWidget *widget, NemoDesktopIconView *desktop_icon_view) { GdkWindow *root_window; GdkScreen *screen; g_return_if_fail (desktop_icon_view->details->root_window == NULL); screen = gtk_widget_get_screen (widget); root_window = gdk_screen_get_root_window (screen); desktop_icon_view->details->root_window = root_window; update_margins (desktop_icon_view); /* Setup the property filter */ gdk_window_set_events (root_window, GDK_PROPERTY_CHANGE_MASK); gdk_window_add_filter (root_window, gdk_filter_func, desktop_icon_view); } static void nemo_desktop_icon_view_dispose (GObject *object) { NemoDesktopIconView *icon_view; GtkUIManager *ui_manager; icon_view = NEMO_DESKTOP_ICON_VIEW (object); /* Remove desktop rescan timeout. */ if (icon_view->details->reload_desktop_timeout != 0) { g_source_remove (icon_view->details->reload_desktop_timeout); icon_view->details->reload_desktop_timeout = 0; } ui_manager = nemo_view_get_ui_manager (NEMO_VIEW (icon_view)); if (ui_manager != NULL) { nemo_ui_unmerge_ui (ui_manager, &icon_view->details->desktop_merge_id, &icon_view->details->desktop_action_group); } g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, default_zoom_level_changed, icon_view); g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, font_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_preferences, desktop_directory_changed_callback, NULL); g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences, nemo_view_update_menus, icon_view); G_OBJECT_CLASS (nemo_desktop_icon_view_parent_class)->dispose (object); } static void nemo_desktop_icon_view_class_init (NemoDesktopIconViewClass *class) { NemoViewClass *vclass; vclass = NEMO_VIEW_CLASS (class); G_OBJECT_CLASS (class)->dispose = nemo_desktop_icon_view_dispose; G_OBJECT_CLASS (class)->constructed = nemo_desktop_icon_view_constructed; NEMO_ICON_VIEW_CLASS (class)->use_grid_container = FALSE; vclass->merge_menus = real_merge_menus; vclass->update_menus = real_update_menus; vclass->get_view_id = real_get_id; vclass->add_file = real_add_file; #if GTK_CHECK_VERSION(3, 21, 0) GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class); gtk_widget_class_set_css_name (wclass, "nemo-desktop-icon-view"); #endif g_type_class_add_private (class, sizeof (NemoDesktopIconViewDetails)); } static void nemo_desktop_icon_view_handle_middle_click (NemoIconContainer *icon_container, GdkEventButton *event, NemoDesktopIconView *desktop_icon_view) { XButtonEvent x_event; GdkDevice *keyboard = NULL, *pointer = NULL, *cur; GdkDeviceManager *manager; GList *list, *l; manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (icon_container))); list = gdk_device_manager_list_devices (manager, GDK_DEVICE_TYPE_MASTER); for (l = list; l != NULL; l = l->next) { cur = l->data; if (pointer == NULL && (gdk_device_get_source (cur) == GDK_SOURCE_MOUSE)) { pointer = cur; } if (keyboard == NULL && (gdk_device_get_source (cur) == GDK_SOURCE_KEYBOARD)) { keyboard = cur; } if (pointer != NULL && keyboard != NULL) { break; } } g_list_free (list); /* During a mouse click we have the pointer and keyboard grab. * We will send a fake event to the root window which will cause it * to try to get the grab so we need to let go ourselves. */ if (pointer != NULL) { gdk_device_ungrab (pointer, GDK_CURRENT_TIME); } if (keyboard != NULL) { gdk_device_ungrab (keyboard, GDK_CURRENT_TIME); } /* Stop the event because we don't want anyone else dealing with it. */ gdk_flush (); g_signal_stop_emission_by_name (icon_container, "middle_click"); /* build an X event to represent the middle click. */ x_event.type = ButtonPress; x_event.send_event = True; x_event.display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); x_event.window = GDK_ROOT_WINDOW (); x_event.root = GDK_ROOT_WINDOW (); x_event.subwindow = 0; x_event.time = event->time; x_event.x = event->x; x_event.y = event->y; x_event.x_root = event->x_root; x_event.y_root = event->y_root; x_event.state = event->state; x_event.button = event->button; x_event.same_screen = True; /* Send it to the root window, the window manager will handle it. */ XSendEvent (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (), True, ButtonPressMask, (XEvent *) &x_event); } static void desktop_icon_container_realize (GtkWidget *widget, NemoDesktopIconView *desktop_icon_view) { GdkWindow *bin_window; GdkRGBA transparent = { 0, 0, 0, 0 }; bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); gdk_window_set_background_rgba (bin_window, &transparent); } static NemoZoomLevel get_default_zoom_level (void) { NemoZoomLevel default_zoom_level; default_zoom_level = g_settings_get_enum (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL); return CLAMP (default_zoom_level, NEMO_ZOOM_LEVEL_SMALLEST, NEMO_ZOOM_LEVEL_LARGEST); } static void default_zoom_level_changed (gpointer user_data) { NemoZoomLevel new_level; NemoDesktopIconView *desktop_icon_view; desktop_icon_view = NEMO_DESKTOP_ICON_VIEW (user_data); new_level = get_default_zoom_level (); nemo_icon_container_set_zoom_level (get_icon_container (desktop_icon_view), new_level); } static gboolean do_desktop_rescan (gpointer data) { NemoDesktopIconView *desktop_icon_view; struct stat buf; desktop_icon_view = NEMO_DESKTOP_ICON_VIEW (data); if (desktop_icon_view->details->pending_rescan) { return TRUE; } if (stat (desktop_directory, &buf) == -1) { return TRUE; } if (buf.st_ctime == desktop_dir_modify_time) { return TRUE; } desktop_icon_view->details->pending_rescan = TRUE; nemo_directory_force_reload (nemo_view_get_model (NEMO_VIEW (desktop_icon_view))); return TRUE; } static void done_loading (NemoDirectory *model, NemoDesktopIconView *desktop_icon_view) { struct stat buf; desktop_icon_view->details->pending_rescan = FALSE; if (stat (desktop_directory, &buf) == -1) { return; } desktop_dir_modify_time = buf.st_ctime; } /* This function is used because the NemoDirectory model does not * exist always in the desktop_icon_view, so we wait until it has been * instantiated. */ static void delayed_init (NemoDesktopIconView *desktop_icon_view) { /* Keep track of the load time. */ g_signal_connect_object (nemo_view_get_model (NEMO_VIEW (desktop_icon_view)), "done_loading", G_CALLBACK (done_loading), desktop_icon_view, 0); /* Monitor desktop directory. */ desktop_icon_view->details->reload_desktop_timeout = g_timeout_add_seconds (RESCAN_TIMEOUT, do_desktop_rescan, desktop_icon_view); g_signal_handler_disconnect (desktop_icon_view, desktop_icon_view->details->delayed_init_signal); desktop_icon_view->details->delayed_init_signal = 0; } static void font_changed_callback (gpointer callback_data) { g_return_if_fail (NEMO_IS_DESKTOP_ICON_VIEW (callback_data)); nemo_desktop_icon_view_update_icon_container_fonts (NEMO_DESKTOP_ICON_VIEW (callback_data)); } static void nemo_desktop_icon_view_update_icon_container_fonts (NemoDesktopIconView *icon_view) { NemoIconContainer *icon_container; char *font; icon_container = get_icon_container (icon_view); g_assert (icon_container != NULL); font = g_settings_get_string (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_FONT); nemo_icon_container_set_font (icon_container, font); g_free (font); } static void nemo_desktop_icon_view_init (NemoDesktopIconView *desktop_icon_view) { desktop_icon_view->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_icon_view, NEMO_TYPE_DESKTOP_ICON_VIEW, NemoDesktopIconViewDetails); } static void nemo_desktop_icon_view_constructed (GObject *object) { NemoDesktopIconView *desktop_icon_view; NemoIconContainer *icon_container; GtkAllocation allocation; GtkAdjustment *hadj, *vadj; desktop_icon_view = NEMO_DESKTOP_ICON_VIEW (object); G_OBJECT_CLASS (nemo_desktop_icon_view_parent_class)->constructed (G_OBJECT (desktop_icon_view)); if (desktop_directory == NULL) { g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_directory_changed_callback), NULL); desktop_directory_changed_callback (NULL); } icon_container = get_icon_container (desktop_icon_view); nemo_icon_container_set_use_drop_shadows (icon_container, TRUE); nemo_icon_view_container_set_sort_desktop (NEMO_ICON_VIEW_CONTAINER (icon_container), TRUE); /* Do a reload on the desktop if we don't have FAM, a smarter * way to keep track of the items on the desktop. */ if (!nemo_monitor_active ()) { desktop_icon_view->details->delayed_init_signal = g_signal_connect_object (desktop_icon_view, "begin_loading", G_CALLBACK (delayed_init), desktop_icon_view, 0); } nemo_icon_container_set_is_fixed_size (icon_container, TRUE); nemo_icon_container_set_is_desktop (icon_container, TRUE); nemo_icon_container_set_store_layout_timestamps (icon_container, TRUE); /* Set allocation to be at 0, 0 */ gtk_widget_get_allocation (GTK_WIDGET (icon_container), &allocation); allocation.x = 0; allocation.y = 0; gtk_widget_set_allocation (GTK_WIDGET (icon_container), &allocation); gtk_widget_queue_resize (GTK_WIDGET (icon_container)); hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (icon_container)); vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (icon_container)); gtk_adjustment_set_value (hadj, 0); gtk_adjustment_set_value (vadj, 0); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (desktop_icon_view), GTK_SHADOW_NONE); nemo_view_ignore_hidden_file_preferences (NEMO_VIEW (desktop_icon_view)); nemo_view_set_show_foreign (NEMO_VIEW (desktop_icon_view), FALSE); /* Set our default layout mode */ nemo_icon_container_set_layout_mode (icon_container, gtk_widget_get_direction (GTK_WIDGET(icon_container)) == GTK_TEXT_DIR_RTL ? NEMO_ICON_LAYOUT_T_B_R_L : NEMO_ICON_LAYOUT_T_B_L_R); g_signal_connect_object (icon_container, "middle_click", G_CALLBACK (nemo_desktop_icon_view_handle_middle_click), desktop_icon_view, 0); g_signal_connect_object (icon_container, "realize", G_CALLBACK (desktop_icon_container_realize), desktop_icon_view, 0); g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, G_CALLBACK (default_zoom_level_changed), desktop_icon_view); g_signal_connect_object (desktop_icon_view, "realize", G_CALLBACK (realized_callback), desktop_icon_view, 0); g_signal_connect_object (desktop_icon_view, "unrealize", G_CALLBACK (unrealized_callback), desktop_icon_view, 0); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_FONT, G_CALLBACK (font_changed_callback), desktop_icon_view); default_zoom_level_changed (desktop_icon_view); nemo_desktop_icon_view_update_icon_container_fonts (desktop_icon_view); g_signal_connect_swapped (gnome_lockdown_preferences, "changed::" NEMO_PREFERENCES_LOCKDOWN_COMMAND_LINE, G_CALLBACK (nemo_view_update_menus), desktop_icon_view); } static void action_stretch_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_ICON_VIEW (callback_data)); nemo_icon_container_show_stretch_handles (get_icon_container (callback_data)); } static void action_unstretch_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_ICON_VIEW (callback_data)); nemo_icon_container_unstretch (get_icon_container (callback_data)); } static void action_empty_trash_conditional_callback (GtkAction *action, gpointer data) { g_assert (NEMO_IS_VIEW (data)); nemo_file_operations_empty_trash (GTK_WIDGET (data)); } static gboolean trash_link_is_selection (NemoView *view) { GList *selection; NemoDesktopLink *link; gboolean result; result = FALSE; selection = nemo_view_get_selection (view); if ((g_list_length (selection) == 1) && NEMO_IS_DESKTOP_ICON_FILE (selection->data)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (selection->data)); /* link may be NULL if the link was recently removed (unmounted) */ if (link != NULL && nemo_desktop_link_get_link_type (link) == NEMO_DESKTOP_LINK_TRASH) { result = TRUE; } if (link) { g_object_unref (link); } } nemo_file_list_free (selection); return result; } static void real_update_menus (NemoView *view) { NemoDesktopIconView *desktop_view; NemoIconContainer *icon_container; char *label; gint selection_count; gboolean include_empty_trash; GtkAction *action; g_assert (NEMO_IS_DESKTOP_ICON_VIEW (view)); NEMO_VIEW_CLASS (nemo_desktop_icon_view_parent_class)->update_menus (view); desktop_view = NEMO_DESKTOP_ICON_VIEW (view); /* Empty Trash */ include_empty_trash = trash_link_is_selection (view); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, NEMO_ACTION_EMPTY_TRASH_CONDITIONAL); gtk_action_set_visible (action, include_empty_trash); if (include_empty_trash) { label = g_strdup (_("E_mpty Trash")); g_object_set (action , "label", label, NULL); gtk_action_set_sensitive (action, !nemo_trash_monitor_is_empty ()); g_free (label); } selection_count = nemo_view_get_selection_count (view); icon_container = get_icon_container (desktop_view); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, NEMO_ACTION_STRETCH); gtk_action_set_sensitive (action, selection_count == 1 && icon_container != NULL && !nemo_icon_container_has_stretch_handles (icon_container)); gtk_action_set_visible (action, TRUE); action = gtk_action_group_get_action (desktop_view->details->desktop_action_group, NEMO_ACTION_UNSTRETCH); g_object_set (action, "label", (selection_count > 1) ? _("Restore Icons' Original Si_zes") : _("Restore Icon's Original Si_ze"), NULL); gtk_action_set_sensitive (action, icon_container != NULL && nemo_icon_container_is_stretched (icon_container)); gtk_action_set_visible (action, TRUE); } static const GtkActionEntry desktop_view_entries[] = { /* name, stock id */ { "Stretch", NULL, /* label, accelerator */ N_("Resize Icon..."), NULL, /* tooltip */ N_("Make the selected icon resizable"), G_CALLBACK (action_stretch_callback) }, /* name, stock id */ { "Unstretch", NULL, /* label, accelerator */ N_("Restore Icons' Original Si_zes"), NULL, /* tooltip */ N_("Restore each selected icon to its original size"), G_CALLBACK (action_unstretch_callback) }, /* name, stock id */ { "Empty Trash Conditional", NULL, /* label, accelerator */ N_("Empty Trash"), NULL, /* tooltip */ N_("Delete all items in the Trash"), G_CALLBACK (action_empty_trash_conditional_callback) } }; static void real_merge_menus (NemoView *view) { NemoDesktopIconView *desktop_view; GtkUIManager *ui_manager; GtkActionGroup *action_group; NEMO_VIEW_CLASS (nemo_desktop_icon_view_parent_class)->merge_menus (view); desktop_view = NEMO_DESKTOP_ICON_VIEW (view); ui_manager = nemo_view_get_ui_manager (view); action_group = gtk_action_group_new ("DesktopViewActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); desktop_view->details->desktop_action_group = action_group; gtk_action_group_add_actions (action_group, desktop_view_entries, G_N_ELEMENTS (desktop_view_entries), view); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui manager */ desktop_view->details->desktop_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-desktop-icon-view-ui.xml", NULL); } static NemoView * nemo_desktop_icon_view_create (NemoWindowSlot *slot) { NemoIconView *view; view = g_object_new (NEMO_TYPE_DESKTOP_ICON_VIEW, "window-slot", slot, "supports-zooming", FALSE, "supports-auto-layout", FALSE, "is-desktop", TRUE, "supports-keep-aligned", TRUE, "supports-labels-beside-icons", FALSE, NULL); return NEMO_VIEW (view); } static gboolean nemo_desktop_icon_view_supports_uri (const char *uri, GFileType file_type, const char *mime_type) { if (g_str_has_prefix (uri, EEL_DESKTOP_URI)) { return TRUE; } return FALSE; } static NemoViewInfo nemo_desktop_icon_view = { (char *)NEMO_DESKTOP_ICON_VIEW_ID, (char *)"Desktop View", (char *)"_Desktop", (char *)N_("The desktop view encountered an error."), (char *)N_("The desktop view encountered an error while starting up."), (char *)"Display this location with the desktop view.", nemo_desktop_icon_view_create, nemo_desktop_icon_view_supports_uri }; void nemo_desktop_icon_view_register (void) { nemo_desktop_icon_view.error_label = _(nemo_desktop_icon_view.error_label); nemo_desktop_icon_view.startup_error_label = _(nemo_desktop_icon_view.startup_error_label); nemo_view_factory_register (&nemo_desktop_icon_view); } nemo-4.4.2/src/nemo-desktop-icon-view.h000066400000000000000000000043541357442400300177320ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-icon-view.h - interface for icon view of directory. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Mike Engber */ #ifndef NEMO_DESKTOP_ICON_VIEW_H #define NEMO_DESKTOP_ICON_VIEW_H #include "nemo-icon-view.h" #define NEMO_TYPE_DESKTOP_ICON_VIEW nemo_desktop_icon_view_get_type() #define NEMO_DESKTOP_ICON_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_ICON_VIEW, NemoDesktopIconView)) #define NEMO_DESKTOP_ICON_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_ICON_VIEW, NemoDesktopIconViewClass)) #define NEMO_IS_DESKTOP_ICON_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_ICON_VIEW)) #define NEMO_IS_DESKTOP_ICON_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_ICON_VIEW)) #define NEMO_DESKTOP_ICON_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_ICON_VIEW, NemoDesktopIconViewClass)) #define NEMO_DESKTOP_ICON_VIEW_ID "OAFIID:Nemo_File_Manager_Desktop_Icon_View" typedef struct NemoDesktopIconViewDetails NemoDesktopIconViewDetails; typedef struct { NemoIconView parent; NemoDesktopIconViewDetails *details; } NemoDesktopIconView; typedef struct { NemoIconViewClass parent_class; } NemoDesktopIconViewClass; /* GObject support */ GType nemo_desktop_icon_view_get_type (void); void nemo_desktop_icon_view_register (void); #endif /* NEMO_DESKTOP_ICON_VIEW_H */ nemo-4.4.2/src/nemo-desktop-item-properties.c000066400000000000000000000325251357442400300211560ustar00rootroot00000000000000/* * fm-ditem-page.c: Desktop item editing support * * Copyright (C) 2004 James Willcox * * This library 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 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 General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Authors: James Willcox * */ #include #include "nemo-desktop-item-properties.h" #include #include #include #include #include #include #include #include #define MAIN_GROUP "Desktop Entry" typedef struct ItemEntry { const char *field; const char *description; char *current_value; gboolean localized; gboolean filename; } ItemEntry; enum { TARGET_URI_LIST }; static const GtkTargetEntry target_table[] = { { "text/uri-list", 0, TARGET_URI_LIST } }; static gboolean _g_key_file_load_from_gfile (GKeyFile *key_file, GFile *file, GKeyFileFlags flags, GError **error) { char *data; gsize len; gboolean res; if (!g_file_load_contents (file, NULL, &data, &len, NULL, error)) { return FALSE; } res = g_key_file_load_from_data (key_file, data, len, flags, error); g_free (data); return res; } static gboolean _g_key_file_save_to_uri (GKeyFile *key_file, const char *uri, GError **error) { GFile *file; char *data; gsize len; data = g_key_file_to_data (key_file, &len, error); if (data == NULL) { return FALSE; } file = g_file_new_for_uri (uri); if (!g_file_replace_contents (file, data, len, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, error)) { g_object_unref (file); g_free (data); return FALSE; } g_object_unref (file); g_free (data); return TRUE; } static GKeyFile * _g_key_file_new_from_file (GFile *file, GKeyFileFlags flags, GError **error) { GKeyFile *key_file; key_file = g_key_file_new (); if (!_g_key_file_load_from_gfile (key_file, file, flags, error)) { g_key_file_free (key_file); key_file = NULL; } return key_file; } static GKeyFile * _g_key_file_new_from_uri (const char *uri, GKeyFileFlags flags, GError **error) { GKeyFile *key_file; GFile *file; file = g_file_new_for_uri (uri); key_file = _g_key_file_new_from_file (file, flags, error); g_object_unref (file); return key_file; } static ItemEntry * item_entry_new (const char *field, const char *description, gboolean localized, gboolean filename) { ItemEntry *entry; entry = g_new0 (ItemEntry, 1); entry->field = field; entry->description = description; entry->localized = localized; entry->filename = filename; return entry; } static void item_entry_free (ItemEntry *entry) { g_free (entry->current_value); g_free (entry); } static void nemo_desktop_item_properties_url_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint time, GtkEntry *entry) { char **uris; gboolean exactly_one; char *path; uris = g_strsplit ((gchar *) gtk_selection_data_get_data (selection_data), "\r\n", 0); exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); if (!exactly_one) { g_strfreev (uris); return; } path = g_filename_from_uri (uris[0], NULL, NULL); if (path != NULL) { gtk_entry_set_text (entry, path); g_free (path); } else { gtk_entry_set_text (entry, uris[0]); } g_strfreev (uris); } static void nemo_desktop_item_properties_exec_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint time, GtkEntry *entry) { char **uris; gboolean exactly_one; NemoFile *file; GKeyFile *key_file; char *uri, *type, *exec; uris = g_strsplit ((gchar *) gtk_selection_data_get_data (selection_data), "\r\n", 0); exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); if (!exactly_one) { g_strfreev (uris); return; } file = nemo_file_get_by_uri (uris[0]); if (file == NULL) { g_strfreev (uris); return; } uri = nemo_file_get_uri (file); if (nemo_file_is_mime_type (file, "application/x-desktop")) { key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL); if (key_file != NULL) { type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); if (type != NULL && strcmp (type, "Application") == 0) { exec = g_key_file_get_string (key_file, MAIN_GROUP, "Exec", NULL); if (exec != NULL) { g_free (uri); uri = exec; } } g_free (type); g_key_file_free (key_file); } } gtk_entry_set_text (entry, uri?uri:""); gtk_widget_grab_focus (GTK_WIDGET (entry)); g_free (uri); nemo_file_unref (file); g_strfreev (uris); } static void save_entry (GtkEntry *entry, GKeyFile *key_file, const char *uri) { GError *error; ItemEntry *item_entry; const char *val; gchar **languages; item_entry = g_object_get_data (G_OBJECT (entry), "item_entry"); val = gtk_entry_get_text (entry); if (strcmp (val, item_entry->current_value) == 0) { return; /* No actual change, don't update file */ } g_free (item_entry->current_value); item_entry->current_value = g_strdup (val); if (item_entry->localized) { languages = (gchar **) g_get_language_names (); g_key_file_set_locale_string (key_file, MAIN_GROUP, item_entry->field, languages[0], val); } else { g_key_file_set_string (key_file, MAIN_GROUP, item_entry->field, val); } error = NULL; if (!_g_key_file_save_to_uri (key_file, uri, &error)) { g_warning ("%s", error->message); g_error_free (error); } } static void entry_activate_cb (GtkWidget *entry, GtkWidget *container) { const char *uri; GKeyFile *key_file; uri = g_object_get_data (G_OBJECT (container), "uri"); key_file = g_object_get_data (G_OBJECT (container), "keyfile"); save_entry (GTK_ENTRY (entry), key_file, uri); } static gboolean entry_focus_out_cb (GtkWidget *entry, GdkEventFocus *event, GtkWidget *container) { const char *uri; GKeyFile *key_file; uri = g_object_get_data (G_OBJECT (container), "uri"); key_file = g_object_get_data (G_OBJECT (container), "keyfile"); save_entry (GTK_ENTRY (entry), key_file, uri); return FALSE; } static GtkWidget * build_grid (GtkWidget *container, GKeyFile *key_file, GtkSizeGroup *label_size_group, GList *entries) { GtkWidget *grid; GtkWidget *label; GtkWidget *entry; GList *l; char *val; grid = gtk_grid_new (); gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_grid_set_column_spacing (GTK_GRID (grid), 12); for (l = entries; l; l = l->next) { ItemEntry *item_entry = (ItemEntry *)l->data; char *label_text; label_text = g_strdup_printf ("%s:", item_entry->description); label = gtk_label_new (label_text); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); g_free (label_text); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_size_group_add_widget (label_size_group, label); entry = gtk_entry_new (); gtk_widget_set_hexpand (entry, TRUE); if (item_entry->localized) { val = g_key_file_get_locale_string (key_file, MAIN_GROUP, item_entry->field, NULL, NULL); } else { val = g_key_file_get_string (key_file, MAIN_GROUP, item_entry->field, NULL); } item_entry->current_value = g_strdup (val?val:""); gtk_entry_set_text (GTK_ENTRY (entry), item_entry->current_value); g_free (val); gtk_container_add (GTK_CONTAINER (grid), label); gtk_grid_attach_next_to (GTK_GRID (grid), entry, label, GTK_POS_RIGHT, 1, 1); g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), container); g_signal_connect (entry, "focus_out_event", G_CALLBACK (entry_focus_out_cb), container); g_object_set_data_full (G_OBJECT (entry), "item_entry", item_entry, (GDestroyNotify)item_entry_free); if (item_entry->filename) { gtk_drag_dest_set (GTK_WIDGET (entry), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target_table, G_N_ELEMENTS (target_table), GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (entry, "drag_data_received", G_CALLBACK (nemo_desktop_item_properties_url_drag_data_received), entry); } else if (strcmp (item_entry->field, "Exec") == 0) { gtk_drag_dest_set (GTK_WIDGET (entry), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target_table, G_N_ELEMENTS (target_table), GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (entry, "drag_data_received", G_CALLBACK (nemo_desktop_item_properties_exec_drag_data_received), entry); } } /* append dummy row */ label = gtk_label_new (""); gtk_container_add (GTK_CONTAINER (grid), label); gtk_size_group_add_widget (label_size_group, label); gtk_widget_show_all (grid); return grid; } static void create_page (GKeyFile *key_file, GtkWidget *box) { GtkWidget *grid; GList *entries; GtkSizeGroup *label_size_group; char *type; entries = NULL; type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); if (g_strcmp0 (type, "Link") == 0) { entries = g_list_prepend (entries, item_entry_new ("Comment", _("Comment"), TRUE, FALSE)); entries = g_list_prepend (entries, item_entry_new ("URL", _("URL"), FALSE, TRUE)); entries = g_list_prepend (entries, item_entry_new ("GenericName", _("Description"), TRUE, FALSE)); } else if (g_strcmp0 (type, "Application") == 0) { entries = g_list_prepend (entries, item_entry_new ("Comment", _("Comment"), TRUE, FALSE)); entries = g_list_prepend (entries, item_entry_new ("Exec", _("Command"), FALSE, FALSE)); entries = g_list_prepend (entries, item_entry_new ("GenericName", _("Description"), TRUE, FALSE)); } else { /* we only handle launchers and links */ /* ensure that we build an empty table with a dummy row at the end */ goto build_table; } g_free (type); build_table: label_size_group = g_object_get_data (G_OBJECT (box), "label-size-group"); grid = build_grid (box, key_file, label_size_group, entries); g_list_free (entries); gtk_box_pack_start (GTK_BOX (box), grid, FALSE, TRUE, 0); gtk_widget_show_all (GTK_WIDGET (box)); } static void ditem_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GKeyFile *key_file; GtkWidget *box; gsize file_size; char *file_contents; box = GTK_WIDGET (user_data); if (g_file_load_contents_finish (G_FILE (source_object), res, &file_contents, &file_size, NULL, NULL)) { key_file = g_key_file_new (); g_object_set_data_full (G_OBJECT (box), "keyfile", key_file, (GDestroyNotify)g_key_file_free); if (g_key_file_load_from_data (key_file, file_contents, file_size, 0, NULL)) { create_page (key_file, box); } g_free (file_contents); } g_object_unref (box); } static void nemo_desktop_item_properties_create_begin (const char *uri, GtkWidget *box) { GFile *location; location = g_file_new_for_uri (uri); g_object_set_data_full (G_OBJECT (box), "uri", g_strdup (uri), g_free); g_file_load_contents_async (location, NULL, ditem_read_cb, g_object_ref (box)); g_object_unref (location); } GtkWidget * nemo_desktop_item_properties_make_box (GtkSizeGroup *label_size_group, GList *files) { NemoFileInfo *info; char *uri; GtkWidget *box; g_assert (nemo_desktop_item_properties_should_show (files)); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); g_object_set_data_full (G_OBJECT (box), "label-size-group", label_size_group, (GDestroyNotify) g_object_unref); info = NEMO_FILE_INFO (files->data); uri = nemo_file_info_get_uri (info); nemo_desktop_item_properties_create_begin (uri, box); g_free (uri); return box; } gboolean nemo_desktop_item_properties_should_show (GList *files) { NemoFileInfo *info; if (!files || files->next) { return FALSE; } info = NEMO_FILE_INFO (files->data); if (!nemo_file_info_is_mime_type (info, "application/x-desktop")) { return FALSE; } return TRUE; } nemo-4.4.2/src/nemo-desktop-item-properties.h000066400000000000000000000030721357442400300211560ustar00rootroot00000000000000/* * fm-ditem-page.h - A property page for desktop items * * Copyright (C) 2004 James Willcox * * This library 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 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 General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Authors: James Willcox * */ #ifndef NEMO_DESKTOP_ITEM_PROPERTIES_H #define NEMO_DESKTOP_ITEM_PROPERTIES_H #include #include #include G_BEGIN_DECLS /* This is a mis-nomer. Launcher editables initially were displayed on separate * a property notebook page, which implemented the NemoPropertyPageProvider * interface. * * Nowadays, they are displayed on the "Basic" page, so just the setup * routines are left. */ GtkWidget *nemo_desktop_item_properties_make_box (GtkSizeGroup *label_size_group, GList *files); gboolean nemo_desktop_item_properties_should_show (GList *files); G_END_DECLS #endif /* NEMO_DESKTOP_ITEM_PROPERTIES_H */ nemo-4.4.2/src/nemo-desktop-main.c000066400000000000000000000061011357442400300167410ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee , * Darin Adler , * John Sullivan * */ /* nemo-main.c: Implementation of the routines that drive program lifecycle and main window creation/destruction. */ #include #include "nemo-desktop-application.h" #include #include #include #include #include #include #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #include #include #include #ifdef HAVE_EXEMPI #include #endif int main (int argc, char *argv[]) { gint retval; NemoApplication *application; #if defined (HAVE_MALLOPT) && defined(M_MMAP_THRESHOLD) /* Nemo uses lots and lots of small and medium size allocations, * and then a few large ones for the desktop background. By default * glibc uses a dynamic treshold for how large allocations should * be mmaped. Unfortunately this triggers quickly for nemo when * it does the desktop background allocations, raising the limit * such that a lot of temporary large allocations end up on the * heap and are thus not returned to the OS. To fix this we set * a hardcoded limit. I don't know what a good value is, but 128K * was the old glibc static limit, lets use that. */ mallopt (M_MMAP_THRESHOLD, 128 *1024); #endif /* This will be done by gtk+ later, but for now, force it to GNOME */ g_desktop_app_info_set_desktop_env ("GNOME"); if (g_getenv ("NEMO_DEBUG") != NULL) { eel_make_warnings_and_criticals_stop_in_debugger (); } /* Initialize gettext support */ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); g_set_prgname ("nemo-desktop"); gdk_set_allowed_backends ("x11"); #ifdef HAVE_EXEMPI xmp_init(); #endif /* Run the nemo-desktop application. */ application = nemo_desktop_application_get_singleton (); retval = g_application_run (G_APPLICATION (application), argc, argv); g_object_unref (application); eel_debug_shut_down (); return retval; } nemo-4.4.2/src/nemo-desktop-manager.c000066400000000000000000000706501357442400300174410ustar00rootroot00000000000000/* nemo-desktop-manager.c */ #include #define DEBUG_FLAG NEMO_DEBUG_DESKTOP #include #include "nemo-desktop-manager.h" #include "nemo-blank-desktop-window.h" #include "nemo-desktop-window.h" #include "nemo-application.h" #include "nemo-cinnamon-dbus.h" #include "nemo-desktop-overlay.h" #include #include #include "libnemo-private/nemo-action-manager.h" #include #include static gboolean layout_changed (NemoDesktopManager *manager); #define DESKTOPS_ON_PRIMARY "true::false" #define DESKTOPS_ON_ALL "true::true" #define DESKTOPS_ON_NON_PRIMARY "false::true" #define DESKTOPS_ON_NONE "false::false" #define DESKTOPS_DEFAULT DESKTOPS_ON_PRIMARY #define PRIMARY_MONITOR 0 typedef enum { RUN_STATE_INIT = 0, RUN_STATE_STARTUP, RUN_STATE_RUNNING, RUN_STATE_FALLBACK } RunState; typedef struct { NemoCinnamon *proxy; NemoActionManager *action_manager; NemoDesktopOverlay *overlay; GdkScreen *fallback_screen; GList *desktops; RunState current_run_state; guint desktop_on_primary_only : 1; guint other_desktop : 1; guint proxy_owned : 1; guint startup_complete : 1; guint update_layout_idle_id; guint failsafe_timeout_id; gulong scale_factor_changed_id; gulong name_owner_changed_id; gulong proxy_signals_id; gulong fallback_size_changed_id; } NemoDesktopManagerPrivate; struct _NemoDesktopManager { GtkWindow parent_object; NemoDesktopManagerPrivate *priv; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoDesktopManager, nemo_desktop_manager, G_TYPE_OBJECT); #define FETCH_PRIV(m) NemoDesktopManagerPrivate *priv = NEMO_DESKTOP_MANAGER (m)->priv; typedef struct { GtkWidget *window; gint monitor_num; gboolean shows_desktop; gboolean is_primary; } DesktopInfo; static const gchar * run_state_str (RunState state) { switch (state) { case RUN_STATE_INIT: return "RunState.INIT"; case RUN_STATE_STARTUP: return "RunState.STARTUP"; case RUN_STATE_RUNNING: return "RunState.RUNNING"; case RUN_STATE_FALLBACK: return "RunState.FALLBACK"; default: g_assert_not_reached (); } } static void free_info (DesktopInfo *info) { g_return_if_fail (info != NULL); g_clear_pointer (&info->window, gtk_widget_destroy); g_slice_free (DesktopInfo, info); } static RunState get_run_state (NemoDesktopManager *manager) { FETCH_PRIV (manager); gint ret; GError *error; if (priv->other_desktop) { ret = RUN_STATE_FALLBACK; goto out; } if (priv->proxy == NULL || !priv->proxy_owned) { if (priv->failsafe_timeout_id > 0) { ret = RUN_STATE_INIT; } else { ret = RUN_STATE_FALLBACK; } goto out; } error = NULL; if (!nemo_cinnamon_call_get_run_state_sync (priv->proxy, &ret, NULL, &error)) { DEBUG ("Attempting proxy call 'GetRunState' failed, resorting to fallback mode: %s", error ? error->message : NULL); g_clear_error (&error); ret = RUN_STATE_FALLBACK; goto out; } out: DEBUG ("Run state is %s", run_state_str (ret)); return (RunState) ret; } static gint get_n_monitors (NemoDesktopManager *manager) { FETCH_PRIV (manager); gsize n_monitors, i; const gint *indices G_GNUC_UNUSED; GVariant *monitors; GError *error; if (priv->current_run_state == RUN_STATE_FALLBACK) { DEBUG ("Currently in fallback mode, retrieving n_monitors via GdkScreen"); n_monitors = nemo_desktop_utils_get_num_monitors (); goto out; } error = NULL; if (!nemo_cinnamon_call_get_monitors_sync (priv->proxy, &monitors, NULL, &error)) { DEBUG ("Attempting proxy call 'GetMonitors' failed, retrieving n_monitors via GdkScreen: %s", error ? error->message : NULL); g_clear_error (&error); n_monitors = nemo_desktop_utils_get_num_monitors (); goto out; } DEBUG ("Proxy call to 'GetMonitors' succeeded"); indices = g_variant_get_fixed_array (monitors, &n_monitors, sizeof(gint)); g_variant_unref (monitors); out: if (DEBUGGING) { GString *string = g_string_new (NULL); for (i = 0; i < n_monitors; i++) { gchar *m = g_strdup_printf (" %lu", i); string = g_string_append (string, m); g_free (m); } DEBUG ("Found %lu monitor(s):%s", n_monitors, string->str); g_string_free (string, TRUE); } return n_monitors; } static void get_window_rect_for_monitor (NemoDesktopManager *manager, gint monitor, GdkRectangle *rect) { FETCH_PRIV (manager); GVariant *out_rect_var; GdkRectangle out_rect; gsize n_elem; gint scale_factor; GError *error; error = NULL; out_rect_var = NULL; if (priv->current_run_state == RUN_STATE_FALLBACK) { DEBUG ("Currently in fallback mode, retrieving n_monitors via GdkScreen"); nemo_desktop_utils_get_monitor_geometry (monitor, &out_rect); goto out; } if (!nemo_cinnamon_call_get_monitor_work_rect_sync (priv->proxy, monitor, &out_rect_var, NULL, &error)) { DEBUG ("Attempting proxy call 'GetMonitorWorkRect' failed, retrieving n_monitors via GdkScreen: %s", error ? error->message : NULL); g_clear_error (&error); nemo_desktop_utils_get_monitor_geometry (monitor, &out_rect); goto out; } out_rect = *( (GdkRectangle *) g_variant_get_fixed_array (out_rect_var, &n_elem, sizeof(gint)) ); /* GdkScreen sizes are scaled for hidpi already. But if we've gotten this far, we're using * Cinnamon-provided numbers, which aren't scaled. */ scale_factor = nemo_desktop_utils_get_scale_factor (); out_rect.x /= scale_factor; out_rect.y /= scale_factor; out_rect.width /= scale_factor; out_rect.height /= scale_factor; out: rect->x = out_rect.x; rect->y = out_rect.y; rect->width = out_rect.width; rect->height = out_rect.height; if (out_rect_var != NULL) { g_variant_unref (out_rect_var); } } static void close_all_windows (NemoDesktopManager *manager) { FETCH_PRIV (manager); g_list_foreach (priv->desktops, (GFunc) free_info, NULL); g_clear_pointer (&priv->desktops, g_list_free); } static void queue_update_layout (NemoDesktopManager *manager) { FETCH_PRIV (manager); if (priv->update_layout_idle_id > 0) { g_source_remove (priv->update_layout_idle_id); priv->update_layout_idle_id = 0; } priv->update_layout_idle_id = g_idle_add ((GSourceFunc) layout_changed, manager); } static void on_window_scale_changed (GtkWidget *window, GParamSpec *pspec, NemoDesktopManager *manager) { FETCH_PRIV (manager); priv->scale_factor_changed_id = 0; queue_update_layout (manager); } static void create_new_desktop_window (NemoDesktopManager *manager, gint monitor, gboolean primary, gboolean show_desktop) { FETCH_PRIV (manager); GtkWidget *window; DesktopInfo *info = g_slice_new0 (DesktopInfo); info->monitor_num = monitor; info->shows_desktop = show_desktop; info->is_primary = primary; if (show_desktop) { window = GTK_WIDGET (nemo_desktop_window_new (monitor)); } else { window = GTK_WIDGET (nemo_blank_desktop_window_new (monitor)); } info->window = window; if (priv->scale_factor_changed_id == 0) { priv->scale_factor_changed_id = g_signal_connect (window, "notify::scale-factor", G_CALLBACK (on_window_scale_changed), manager); } gtk_application_add_window (GTK_APPLICATION (nemo_application_get_singleton ()), GTK_WINDOW (window)); priv->desktops = g_list_append (priv->desktops, info); } static gboolean update_overlay_in_idle (NemoDesktopManager *manager) { FETCH_PRIV (manager); if (manager->priv->overlay) { nemo_desktop_overlay_update_in_place (priv->overlay); } return G_SOURCE_REMOVE; } static gboolean layout_changed (NemoDesktopManager *manager) { FETCH_PRIV (manager); gint n_monitors = 0; gint x_primary = 0; gboolean show_desktop_on_primary = FALSE; gboolean show_desktop_on_remaining = FALSE; priv->update_layout_idle_id = 0; close_all_windows (manager); gchar *pref = g_settings_get_string (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_LAYOUT); if (g_strcmp0 (pref, "") == 0) { g_settings_set_string (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_LAYOUT, DESKTOPS_DEFAULT); g_free (pref); layout_changed (manager); return G_SOURCE_REMOVE; } gchar **pref_split = g_strsplit (pref, "::", 2); if (g_strv_length (pref_split) != 2) { g_settings_set_string (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_LAYOUT, DESKTOPS_DEFAULT); g_free (pref); g_strfreev (pref_split); layout_changed (manager); return G_SOURCE_REMOVE; } n_monitors = get_n_monitors (manager); x_primary = 0; /* always */ show_desktop_on_primary = g_strcmp0 (pref_split[0], "true") == 0; show_desktop_on_remaining = g_strcmp0 (pref_split[1], "true") == 0; priv->desktop_on_primary_only = show_desktop_on_primary && !show_desktop_on_remaining; gint i = 0; gboolean primary_set = FALSE; for (i = 0; i < n_monitors; i++) { if (i == x_primary) { create_new_desktop_window (manager, i, show_desktop_on_primary, show_desktop_on_primary); primary_set = primary_set || show_desktop_on_primary; } else if (!nemo_desktop_utils_get_monitor_cloned (i, x_primary)) { gboolean set_layout_primary = !primary_set && !show_desktop_on_primary && show_desktop_on_remaining; create_new_desktop_window (manager, i, set_layout_primary, show_desktop_on_remaining); primary_set = primary_set || set_layout_primary; } } g_free (pref); g_strfreev (pref_split); /* This is hacky - it takes time for the actual view to load, even though the window is created * immediately. We need to force it to wait here, or else we'd need to monitor when the view is * created and run then. */ g_timeout_add (300, (GSourceFunc) update_overlay_in_idle, manager); return G_SOURCE_REMOVE; } static void on_bus_name_owner_changed (NemoDesktopManager *manager) { FETCH_PRIV (manager); gchar *name_owner; g_return_if_fail (priv->proxy != NULL); name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (priv->proxy)); priv->proxy_owned = name_owner != NULL; if (priv->proxy_owned) { if (priv->failsafe_timeout_id > 0) { g_source_remove (priv->failsafe_timeout_id); priv->failsafe_timeout_id = 0; } } DEBUG ("New name owner: %s", name_owner ? name_owner : "unowned"); g_free (name_owner); } static void on_run_state_changed (NemoDesktopManager *manager) { g_return_if_fail (NEMO_IS_DESKTOP_MANAGER (manager)); FETCH_PRIV (manager); RunState new_state; DEBUG ("New run state..."); /* If we're already running (showing icons,) there's no * change in behavior, we just keep showing. */ if (priv->current_run_state == RUN_STATE_RUNNING) { return; } new_state = get_run_state (manager); /* If our state is INIT, we're waiting for the proxy to * get picked up (cinnamon starting) and still within our * failsafe timeout, so we just return */ if (new_state == RUN_STATE_INIT) { priv->current_run_state = new_state; return; } /* If our state is STARTUP, RUNNING, or FAILSAFE, we can * cancel our failsafe timer. We've either gotten a proxy * owner, given up waiting, or are now running */ if (new_state > RUN_STATE_INIT) { if (priv->failsafe_timeout_id > 0) { g_source_remove (priv->failsafe_timeout_id); priv->failsafe_timeout_id = 0; } } /* RUNNING or FALLBACK is the final endpoint of the desktop startup * sequence. Either way we trigger the desktop to start and release * our hold on the GApplication (the windows created in layout_changed * will keep the application alive from here on out.) */ if (new_state == RUN_STATE_RUNNING || new_state == RUN_STATE_FALLBACK) { priv->current_run_state = new_state; layout_changed (manager); g_application_release (G_APPLICATION (nemo_application_get_singleton ())); } } static void on_monitors_changed (NemoDesktopManager *manager) { g_return_if_fail (NEMO_IS_DESKTOP_MANAGER (manager)); FETCH_PRIV (manager); GList *l; DEBUG ("Monitors or workarea changed"); if (get_run_state (manager) < RUN_STATE_RUNNING) { DEBUG ("...ignoring possibly bogus MonitorsChanged - we're not RUNNING or FALLBACK"); return; } if (((guint) get_n_monitors (manager)) != g_list_length (priv->desktops)) { queue_update_layout (manager); return; } for (l = priv->desktops; l != NULL; l = l->next) { DesktopInfo *info = (DesktopInfo *) l->data; if (NEMO_IS_DESKTOP_WINDOW (info->window)) { nemo_desktop_window_update_geometry (NEMO_DESKTOP_WINDOW (info->window)); } else if (NEMO_IS_BLANK_DESKTOP_WINDOW (info->window)) { nemo_blank_desktop_window_update_geometry (NEMO_BLANK_DESKTOP_WINDOW (info->window)); } } } static void on_overlay_adjustments_changed (NemoDesktopOverlay *overlay, NemoWindow *window, gint h_percent, gint v_percent, NemoDesktopManager *manager) { g_return_if_fail (NEMO_IS_DESKTOP_WINDOW (window)); nemo_desktop_window_set_grid_adjusts (NEMO_DESKTOP_WINDOW (window), h_percent, v_percent); } static void on_proxy_signal (GDBusProxy *proxy, gchar *sender, gchar *signal_name, GVariant *params, gpointer *user_data) { if (g_strcmp0 (signal_name, "RunStateChanged") == 0) { on_run_state_changed (NEMO_DESKTOP_MANAGER (user_data)); } else if (g_strcmp0 (signal_name, "MonitorsChanged") == 0) { on_monitors_changed (NEMO_DESKTOP_MANAGER (user_data)); } } static gboolean on_failsafe_timeout (NemoDesktopManager *manager) { g_return_val_if_fail (NEMO_IS_DESKTOP_MANAGER (manager), FALSE); FETCH_PRIV (manager); /* Our failsafe timeout is up, we'll zero out out id and trigger * on_run_state_changed. A combination of no proxy, no owner and * no timeout id will put us in FALLBACK mode */ g_warning ("nemo-desktop: Desktop failsafe timeout reached, applying fallback behavior"); priv->failsafe_timeout_id = 0; on_run_state_changed (manager); return G_SOURCE_REMOVE; } static void connect_fallback_signals (NemoDesktopManager *manager) { FETCH_PRIV (manager); priv->fallback_screen = gdk_screen_get_default (); priv->fallback_size_changed_id = g_signal_connect_swapped (priv->fallback_screen, "size_changed", G_CALLBACK (queue_update_layout), manager); } static void on_proxy_created (GObject *source, GAsyncResult *res, gpointer user_data) { NemoDesktopManager *manager = NEMO_DESKTOP_MANAGER (user_data); FETCH_PRIV (manager); priv->proxy = nemo_cinnamon_proxy_new_for_bus_finish (res, NULL); if (priv->proxy == NULL) { g_warning ("Cinnamon proxy unsuccessful, applying default behavior"); /* We should always end up with a proxy, as long as dbus itself is working.. */ priv->other_desktop = TRUE; return; } DEBUG ("Cinnamon proxy established, getting owner and state"); priv->name_owner_changed_id = g_signal_connect_swapped (priv->proxy, "notify::g-name-owner", G_CALLBACK (on_bus_name_owner_changed), manager); priv->proxy_signals_id = g_signal_connect (priv->proxy, "g-signal", G_CALLBACK (on_proxy_signal), manager); on_bus_name_owner_changed (manager); if (!priv->proxy_owned) { priv->failsafe_timeout_id = g_timeout_add_seconds (5, (GSourceFunc) on_failsafe_timeout, manager); } on_run_state_changed (manager); } static gboolean fallback_startup_idle_cb (NemoDesktopManager *manager) { on_run_state_changed (manager); return FALSE; } static gboolean is_cinnamon_desktop (void) { if (g_strcmp0 (g_getenv ("XDG_SESSION_DESKTOP"), "cinnamon") == 0) { return TRUE; } if (g_strstr_len (g_getenv ("DESKTOP_SESSION"), -1, "cinnamon") != NULL) { return TRUE; } return FALSE; } static void nemo_desktop_manager_dispose (GObject *object) { NemoDesktopManager *manager = NEMO_DESKTOP_MANAGER (object); FETCH_PRIV (manager); DEBUG ("Disposing NemoDesktopManager"); close_all_windows (manager); g_clear_object (&priv->overlay); g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, queue_update_layout, manager); g_signal_handlers_disconnect_by_func (nemo_preferences, queue_update_layout, manager); if (priv->fallback_size_changed_id > 0) { g_signal_handler_disconnect (priv->fallback_screen, priv->fallback_size_changed_id); priv->fallback_size_changed_id = 0; } G_OBJECT_CLASS (nemo_desktop_manager_parent_class)->dispose (object); } static void nemo_desktop_manager_finalize (GObject *object) { FETCH_PRIV (object); g_clear_object (&priv->action_manager); g_object_unref (priv->proxy); DEBUG ("Finalizing NemoDesktopManager"); G_OBJECT_CLASS (nemo_desktop_manager_parent_class)->finalize (object); } static void nemo_desktop_manager_class_init (NemoDesktopManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = nemo_desktop_manager_finalize; object_class->dispose = nemo_desktop_manager_dispose; } static void nemo_desktop_manager_init (NemoDesktopManager *manager) { NemoDesktopManagerPrivate *priv; manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, NEMO_TYPE_DESKTOP_MANAGER, NemoDesktopManagerPrivate); DEBUG ("Desktop Manager Initialization"); priv = manager->priv; priv->scale_factor_changed_id = 0; priv->desktops = NULL; priv->desktop_on_primary_only = FALSE; priv->action_manager = NULL; priv->update_layout_idle_id = 0; g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_SHOW_DESKTOP, G_CALLBACK (queue_update_layout), manager); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_LAYOUT, G_CALLBACK (queue_update_layout), manager); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_USE_DESKTOP_GRID, G_CALLBACK (queue_update_layout), manager); /* Monitor the preference to have the desktop */ /* point to the Unix home folder */ g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK (queue_update_layout), manager); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_ORPHANED_DESKTOP_ICONS, G_CALLBACK (queue_update_layout), manager); /* If we're a cinnamon session, increase the use count temporarily for the application, * and establish a proxy for org.Cinnamon. The hold prevents the GApplication from simply * exiting while waiting for the GAsyncReadyCallback. * * If we're not running cinnamon, */ g_application_hold (G_APPLICATION (nemo_application_get_singleton ())); if (is_cinnamon_desktop ()) { g_message ("nemo-desktop: session is cinnamon, establishing proxy"); nemo_cinnamon_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, "org.Cinnamon", "/org/Cinnamon", NULL, (GAsyncReadyCallback) on_proxy_created, manager); } else { g_message ("nemo-desktop: session is not cinnamon (checked XDG_SESSION_DESKTOP," "DESKTOP_SESSION environment variables.) Applying default behavior"); priv->other_desktop = TRUE; connect_fallback_signals (manager); /* Even though we start immediately when we can't do a proxy, we need to get out * of the desktop manager's init first, or else we have recursion problems. */ g_idle_add ((GSourceFunc) fallback_startup_idle_cb, manager); } } static NemoDesktopManager *_manager = NULL; NemoDesktopManager* nemo_desktop_manager_get (void) { if (_manager == NULL) { _manager = g_object_new (NEMO_TYPE_DESKTOP_MANAGER, NULL); } return _manager; } gboolean nemo_desktop_manager_has_desktop_windows (NemoDesktopManager *manager) { FETCH_PRIV (manager); GList *iter; gboolean ret = FALSE; g_return_val_if_fail (manager != NULL, FALSE); for (iter = priv->desktops; iter != NULL; iter = iter->next) { DesktopInfo *info = iter->data; if (info->shows_desktop) { ret = TRUE; break; } } return ret; } gboolean nemo_desktop_manager_get_monitor_is_active (NemoDesktopManager *manager, gint monitor) { FETCH_PRIV (manager); GList *iter; gboolean ret = FALSE; g_return_val_if_fail (manager != NULL, FALSE); for (iter = priv->desktops; iter != NULL; iter = iter->next) { DesktopInfo *info = iter->data; if (info->monitor_num == monitor) { ret = info->shows_desktop; break; } } return ret; } gboolean nemo_desktop_manager_get_monitor_is_primary (NemoDesktopManager *manager, gint monitor) { FETCH_PRIV (manager); GList *iter; gboolean ret = FALSE; g_return_val_if_fail (manager != NULL, FALSE); for (iter = priv->desktops; iter != NULL; iter = iter->next) { DesktopInfo *info = iter->data; if (info->monitor_num == monitor) { ret = info->is_primary; break; } } return ret; } gboolean nemo_desktop_manager_get_primary_only (NemoDesktopManager *manager) { FETCH_PRIV (manager); return priv->desktop_on_primary_only; } NemoActionManager * nemo_desktop_manager_get_action_manager (void) { g_return_val_if_fail (_manager != NULL, NULL); FETCH_PRIV (_manager); if (priv->action_manager == NULL) { priv->action_manager = nemo_action_manager_new (); } return priv->action_manager; } void nemo_desktop_manager_get_window_rect_for_monitor (NemoDesktopManager *manager, gint monitor, GdkRectangle *rect) { g_return_if_fail (manager != NULL); get_window_rect_for_monitor (manager, monitor, rect); } void nemo_desktop_manager_get_margins (NemoDesktopManager *manager, gint monitor, gint *left, gint *right, gint *top, gint *bottom) { FETCH_PRIV (manager); GdkRectangle work_rect, geometry; /* We don't use margins if we have reliable work area * info (e.g. having an active Cinnamon session) */ if (priv->proxy_owned && !priv->other_desktop) { *left = *right = *top = *bottom = 0; return; } /* _NET_WORKAREA only applies to the primary monitor - use it to adjust container margins on the primary icon container only. For any others, add a sane amount of padding for any likely chrome. */ if (monitor != nemo_desktop_utils_get_primary_monitor ()) { *left = *right = *top = *bottom = 25; return; } nemo_desktop_utils_get_monitor_geometry (monitor, &geometry); nemo_desktop_utils_get_monitor_work_rect (monitor, &work_rect); *left = work_rect.x - geometry.x; *right = (geometry.x + geometry.width) - (work_rect.x + work_rect.width); *top = work_rect.y - geometry.y; *bottom = (geometry.y + geometry.height) - (work_rect.y + work_rect.height); } GtkWindow * nemo_desktop_manager_get_window_for_monitor (NemoDesktopManager *manager, gint monitor) { GtkWindow *window; GList *iter; FETCH_PRIV (manager); window = NULL; for (iter = priv->desktops; iter != NULL; iter = iter->next) { DesktopInfo *info = iter->data; if (info->monitor_num == monitor) { window = GTK_WINDOW (info->window); break; } } return window; } void nemo_desktop_manager_get_overlay_info (NemoDesktopManager *manager, gint monitor, GtkActionGroup **action_group, gint *h_adjust, gint *v_adjust) { GtkWindow *window; window = nemo_desktop_manager_get_window_for_monitor (manager, monitor); if (NEMO_IS_DESKTOP_WINDOW (window) && nemo_desktop_window_get_grid_adjusts (NEMO_DESKTOP_WINDOW (window), h_adjust, v_adjust)) { *action_group = nemo_desktop_window_get_action_group (NEMO_DESKTOP_WINDOW (window)); } else { *action_group = NULL; } } void nemo_desktop_manager_show_desktop_overlay (NemoDesktopManager *manager, gint monitor) { FETCH_PRIV (manager); if (priv->overlay == NULL) { priv->overlay = nemo_desktop_overlay_new (); g_object_add_weak_pointer (G_OBJECT (priv->overlay), (gpointer) &priv->overlay); g_signal_connect (priv->overlay, "adjusts-changed", G_CALLBACK (on_overlay_adjustments_changed), manager); } nemo_desktop_overlay_show (priv->overlay, monitor); } gboolean nemo_desktop_manager_get_is_cinnamon (NemoDesktopManager *manager) { FETCH_PRIV (manager); return !priv->other_desktop; } nemo-4.4.2/src/nemo-desktop-manager.h000066400000000000000000000053441357442400300174440ustar00rootroot00000000000000/* nemo-desktop-manager.h */ #ifndef _NEMO_DESKTOP_MANAGER_H #define _NEMO_DESKTOP_MANAGER_H #include #include #include #include "nemo-window.h" G_BEGIN_DECLS #define NEMO_TYPE_DESKTOP_MANAGER nemo_desktop_manager_get_type () G_DECLARE_FINAL_TYPE (NemoDesktopManager, nemo_desktop_manager, NEMO, DESKTOP_MANAGER, GObject) typedef enum { DESKTOP_ARRANGE_VERTICAL, DESKTOP_ARRANGE_HORIZONTAL } NemoDesktopLayoutDirection; NemoDesktopManager* nemo_desktop_manager_get (void); gboolean nemo_desktop_manager_has_desktop_windows (NemoDesktopManager *manager); gboolean nemo_desktop_manager_get_monitor_is_active (NemoDesktopManager *manager, gint monitor); gboolean nemo_desktop_manager_get_monitor_is_primary (NemoDesktopManager *manager, gint monitor); gboolean nemo_desktop_manager_get_primary_only (NemoDesktopManager *manager); void nemo_desktop_manager_get_window_rect_for_monitor (NemoDesktopManager *manager, gint monitor, GdkRectangle *rect); gboolean nemo_desktop_manager_has_good_workarea_info (NemoDesktopManager *manager); void nemo_desktop_manager_get_margins (NemoDesktopManager *manager, gint monitor, gint *left, gint *right, gint *top, gint *bottom); GtkWindow *nemo_desktop_manager_get_window_for_monitor (NemoDesktopManager *manager, gint monitor); void nemo_desktop_manager_get_overlay_info (NemoDesktopManager *manager, gint monitor, GtkActionGroup **action_group, gint *h_adjust, gint *v_adjust); void nemo_desktop_manager_show_desktop_overlay (NemoDesktopManager *manager, gint initial_monitor); gboolean nemo_desktop_manager_get_is_cinnamon (NemoDesktopManager *manager); G_END_DECLS #endif /* _NEMO_DESKTOP_MANAGER_H */ nemo-4.4.2/src/nemo-desktop-overlay.c000066400000000000000000000503151357442400300175040ustar00rootroot00000000000000#include #include #include #include #include #include #include "nemo-desktop-overlay.h" #include "nemo-desktop-manager.h" #include typedef struct { GtkWindow *window; NemoDesktopManager *manager; gboolean is_cinnamon; GtkStack *stack; GtkStack *view_substack; GtkWidget *icon_size_combo; GtkWidget *direction_combo; GtkWidget *sort_combo; GtkBuilder *builder; GtkWindow *nemo_window; GtkActionGroup *action_group; gint monitor; guint adjust_changed_id; guint configure_event_id; gint h_percent; gint v_percent; gboolean syncing; } NemoDesktopOverlayPrivate; struct _NemoDesktopOverlay { GObject parent_object; NemoDesktopOverlayPrivate *priv; }; enum { ADJUSTS_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0, }; G_DEFINE_TYPE_WITH_PRIVATE (NemoDesktopOverlay, nemo_desktop_overlay, G_TYPE_OBJECT) static void show_view_page (NemoDesktopOverlay *overlay) { NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); GdkScreen *screen; GdkRectangle rect; gchar *plug_name; screen = gdk_screen_get_default (); plug_name = gdk_screen_get_monitor_plug_name (screen, priv->monitor); gdk_screen_get_monitor_geometry (screen, priv->monitor, &rect); if (plug_name) { gchar *title; title = g_strdup_printf (_("Current Monitor Layout (%s - %dx%d)"), plug_name, rect.width, rect.height); gtk_window_set_title (priv->window, title); g_free (title); } else { gchar *title; title = g_strdup_printf (_("Current Monitor Layout (%dx%d)"), rect.width, rect.height); gtk_window_set_title (priv->window, title); g_free (title); } g_free (plug_name); gtk_stack_set_visible_child_name (priv->stack, "view"); } static void sync_controls (NemoDesktopOverlay *overlay, gboolean same_monitor) { NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); GtkRange *range; GtkActionGroup *action_group; GtkAction *action; gint h_adjust, v_adjust, active_id; gboolean fake_group; const gchar *combo_id; priv->syncing = TRUE; if (!nemo_desktop_manager_get_monitor_is_active (priv->manager, priv->monitor)) { gtk_stack_set_visible_child_name (priv->view_substack, "substack_disabled"); priv->nemo_window = NULL; priv->action_group = gtk_action_group_new ("empty"); fake_group = TRUE; } else { gtk_stack_set_visible_child_name (priv->view_substack, "substack_enabled"); priv->nemo_window = nemo_desktop_manager_get_window_for_monitor (nemo_desktop_manager_get (), priv->monitor); nemo_desktop_manager_get_overlay_info (priv->manager, priv->monitor, &action_group, &h_adjust, &v_adjust); range = GTK_RANGE (gtk_builder_get_object (priv->builder, "horizontal_adjust_slider")); gtk_range_set_value (range, (double) h_adjust); range = GTK_RANGE (gtk_builder_get_object (priv->builder, "vertical_adjust_slider")); gtk_range_set_value (range, (double) v_adjust); /* Catch enabling of a particular monitor. If we were a blank window and now * we're a real desktop window, it makes sense to present the view settings to the user */ if (same_monitor && (action_group != priv->action_group)) { show_view_page (overlay); } priv->action_group = action_group; /* Sync combo boxes - we just need to access a single radio action for each group to get the active one. From that * we can set the active-id of the combobox */ /* Icon size */ action = gtk_action_group_get_action (priv->action_group, "Desktop Normal"); active_id = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); switch (active_id) { case NEMO_ZOOM_LEVEL_SMALLER: combo_id = "Desktop Smaller"; break; case NEMO_ZOOM_LEVEL_SMALL: combo_id = "Desktop Small"; break; case NEMO_ZOOM_LEVEL_LARGE: combo_id = "Desktop Large"; break; case NEMO_ZOOM_LEVEL_LARGER: combo_id = "Desktop Larger"; break; case NEMO_ZOOM_LEVEL_STANDARD: default: combo_id = "Desktop Normal"; break; } gtk_combo_box_set_active_id (GTK_COMBO_BOX (priv->icon_size_combo), combo_id); /* Layout direction */ action = gtk_action_group_get_action (priv->action_group, "Vertical Layout"); active_id = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); switch (active_id) { case DESKTOP_ARRANGE_HORIZONTAL: combo_id = "Horizontal Layout"; break; case DESKTOP_ARRANGE_VERTICAL: default: combo_id = "Vertical Layout"; break; } gtk_combo_box_set_active_id (GTK_COMBO_BOX (priv->direction_combo), combo_id); /* Sort type */ action = gtk_action_group_get_action (priv->action_group, "Vertical Layout"); active_id = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); switch (active_id) { case NEMO_FILE_SORT_BY_SIZE: combo_id = "Desktop Sort by Size"; break; case NEMO_FILE_SORT_BY_DETAILED_TYPE: combo_id = "Desktop Sort by Type"; break; case NEMO_FILE_SORT_BY_MTIME: combo_id = "Desktop Sort by Date"; break; case NEMO_FILE_SORT_BY_DISPLAY_NAME: default: combo_id = "Desktop Sort by Name"; break; } gtk_combo_box_set_active_id (GTK_COMBO_BOX (priv->sort_combo), combo_id); fake_group = FALSE; } /* Actual handling is done in NemoDesktopIconGridView */ /* Sync toggle switches */ action = gtk_action_group_get_action (priv->action_group, "Desktop Autoarrange"); gtk_activatable_set_related_action (GTK_ACTIVATABLE (gtk_builder_get_object (priv->builder, "auto_arrange_switch")), action); action = gtk_action_group_get_action (priv->action_group, "Desktop Reverse Sort"); gtk_activatable_set_related_action (GTK_ACTIVATABLE (gtk_builder_get_object (priv->builder, "reverse_sort_switch")), action); if (fake_group) { g_clear_object (&priv->action_group); } priv->syncing = FALSE; show_view_page (overlay); } static void signal_adjust_changed (NemoDesktopOverlay *overlay) { NemoDesktopOverlayPrivate *priv = overlay->priv; double h_val, v_val; gint h_percent, v_percent; h_val = gtk_range_get_value (GTK_RANGE (gtk_builder_get_object (priv->builder, "horizontal_adjust_slider"))); v_val = gtk_range_get_value (GTK_RANGE (gtk_builder_get_object (priv->builder, "vertical_adjust_slider"))); h_percent = CLAMP (floor (h_val), 0, 200); v_percent = CLAMP (floor (v_val), 0, 200); if (h_percent != priv->h_percent || v_percent != priv->v_percent) { priv->h_percent = h_percent; priv->v_percent = v_percent; g_signal_emit (overlay, signals[ADJUSTS_CHANGED], 0, priv->nemo_window, h_percent, v_percent); } } static gboolean signal_adjust_delay_timeout (gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); priv->adjust_changed_id = 0; signal_adjust_changed (overlay); return FALSE; } static void queue_changed_signal (NemoDesktopOverlay *overlay) { NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); if (priv->syncing) { return; } if (priv->adjust_changed_id > 0) { return; } priv->adjust_changed_id = g_timeout_add (50, (GSourceFunc) signal_adjust_delay_timeout, overlay); } static void on_horizontal_adjust_changed (GtkRange *range, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); queue_changed_signal (overlay); } static void on_vertical_adjust_changed (GtkRange *range, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); queue_changed_signal (overlay); } static void on_combo_changed (GtkComboBox *widget, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); const gchar *action_id; action_id = gtk_combo_box_get_active_id (widget); if (action_id) { GtkAction *action; action = gtk_action_group_get_action (priv->action_group, action_id); gtk_action_activate (action); } } static void on_global_prefs_link_button_clicked (GtkWidget *button, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); show_view_page (overlay); } static void on_view_prefs_button_clicked (GtkWidget *button, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); if (priv->is_cinnamon) { GError *error; error = NULL; if (!g_spawn_command_line_async ("cinnamon-settings desktop", &error)) { g_warning ("Could not spawn 'cinnamon-settings desktop': %s", error->message); g_error_free (error); } else { return; } } gtk_stack_set_visible_child_name (priv->stack, "global"); gtk_window_set_title (priv->window, _("Desktop Settings")); } static gboolean on_link_button_activate_link (GtkLinkButton *button, gpointer user_data) { /* Stop the link activation */ return GDK_EVENT_STOP; } static void on_grid_reset_button_clicked (GtkWidget *button, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); GtkRange *range; range = GTK_RANGE (gtk_builder_get_object (priv->builder, "horizontal_adjust_slider")); gtk_range_set_value (range, 100.0); range = GTK_RANGE (gtk_builder_get_object (priv->builder, "vertical_adjust_slider")); gtk_range_set_value (range, 100.0); } static gboolean on_close_window (GtkWidget *overlay_window, GdkEvent *event, gpointer user_data) { g_return_val_if_fail (NEMO_IS_DESKTOP_OVERLAY (user_data), GDK_EVENT_PROPAGATE); /* When the window is destroyed, kill the overlay instance also. * This will end up clearing the weak pointer made in nemo-desktop-icon-grid-view.c. */ g_object_unref (G_OBJECT (user_data)); return GDK_EVENT_PROPAGATE; } gboolean on_window_configure_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (user_data); NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); gint monitor; g_return_val_if_fail (gtk_widget_get_window (widget) != NULL, GDK_EVENT_PROPAGATE); monitor = gdk_screen_get_monitor_at_window (gdk_screen_get_default (), gtk_widget_get_window (widget)); if (monitor != priv->monitor) { priv->monitor = monitor; sync_controls (overlay, FALSE); } return GDK_EVENT_PROPAGATE; } static void nemo_desktop_overlay_init (NemoDesktopOverlay *overlay) { NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); GtkWindow *window; GtkWidget *widget; GtkWidget *prefs_box; overlay->priv = priv; priv->manager = nemo_desktop_manager_get (); priv->is_cinnamon = nemo_desktop_manager_get_is_cinnamon (priv->manager); priv->syncing = FALSE; priv->builder = gtk_builder_new (); gtk_builder_set_translation_domain (priv->builder, GETTEXT_PACKAGE); gtk_builder_add_from_resource (priv->builder, "/org/nemo/nemo-desktop-overlay.glade", NULL); window = GTK_WINDOW (gtk_builder_get_object (priv->builder, "overlay_window")); priv->window = window; /* Can't set this in glade, glade uses the icon-name property. This could be remedied * by watching property changes in XAppGtkWindow, but it's not that big a deal */ xapp_gtk_window_set_icon_name (XAPP_GTK_WINDOW (window), "preferences-desktop"); gtk_widget_add_events (GTK_WIDGET (window), GDK_STRUCTURE_MASK); prefs_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (prefs_box), 6); g_object_set (GTK_BOX (prefs_box), "margin-start", 80, "margin-end", 80, "margin-top", 15, "margin-bottom", 15, NULL); if (!priv->is_cinnamon) { widget = GTK_WIDGET (nemo_desktop_preferences_new ()); gtk_box_pack_start (GTK_BOX (prefs_box), widget, TRUE, TRUE, 0); widget = gtk_link_button_new_with_label ("", _("Current Monitor Preferences")); gtk_widget_set_tooltip_text (widget, ""); g_signal_connect (widget, "clicked", G_CALLBACK (on_global_prefs_link_button_clicked), overlay); g_signal_connect (widget, "activate-link", G_CALLBACK (on_link_button_activate_link), overlay); gtk_widget_set_hexpand (widget, TRUE); gtk_box_pack_end (GTK_BOX (prefs_box), widget, TRUE, FALSE, 0); gtk_widget_show_all (prefs_box); gtk_widget_queue_allocate (prefs_box); } priv->stack = GTK_STACK (gtk_builder_get_object (priv->builder, "stack")); gtk_stack_add_titled (priv->stack, prefs_box, "global", _("Show global desktop settings")); gtk_container_child_set (GTK_CONTAINER (priv->stack), prefs_box, "icon-name", "preferences-system-symbolic", NULL); priv->view_substack = GTK_STACK (gtk_builder_get_object (priv->builder, "view_substack")); widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "view_prefs_link_button")); gtk_button_set_label (GTK_BUTTON (widget), _("Desktop Settings")); widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "disabled_view_link_button")); gtk_button_set_label (GTK_BUTTON (widget), _("Desktop Settings")); priv->icon_size_combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "icon_size_combo")); priv->direction_combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "direction_combo")); priv->sort_combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "sort_combo")); gtk_builder_add_callback_symbols (priv->builder, "on_vertical_adjust_changed", G_CALLBACK (on_vertical_adjust_changed), "on_horizontal_adjust_changed", G_CALLBACK (on_horizontal_adjust_changed), "on_disabled_view_link_button_clicked", G_CALLBACK (on_view_prefs_button_clicked), "on_disabled_view_link_button_activate_link", G_CALLBACK (on_link_button_activate_link), "on_view_prefs_link_button_clicked", G_CALLBACK (on_view_prefs_button_clicked), "on_view_prefs_link_button_activate_link", G_CALLBACK (on_link_button_activate_link), "on_grid_reset_button_clicked", G_CALLBACK (on_grid_reset_button_clicked), "on_icon_size_combo_changed", G_CALLBACK (on_combo_changed), "on_direction_combo_changed", G_CALLBACK (on_combo_changed), "on_sort_combo_changed", G_CALLBACK (on_combo_changed), "on_close_window", G_CALLBACK (on_close_window), NULL); gtk_builder_connect_signals (priv->builder, overlay); } static void show_overlay (NemoDesktopOverlay *overlay, gint monitor) { NemoDesktopOverlayPrivate *priv = nemo_desktop_overlay_get_instance_private (overlay); gint root_x, root_y, parent_width, parent_height, default_width, default_height; gint old_monitor; old_monitor = priv->monitor; priv->monitor = monitor; priv->nemo_window = nemo_desktop_manager_get_window_for_monitor (priv->manager, monitor); if (old_monitor != monitor) { gtk_window_get_size (priv->window, &default_width, &default_height); gtk_window_get_position (GTK_WINDOW (priv->nemo_window), &root_x, &root_y); gtk_window_get_size (GTK_WINDOW (priv->nemo_window), &parent_width, &parent_height); gtk_window_move (priv->window, (root_x + (parent_width / 2) - (default_width / 2)), (root_y + (parent_height / 2) - (default_height / 2))); } sync_controls (overlay, old_monitor == monitor); if (priv->configure_event_id == 0) { priv->configure_event_id = g_signal_connect (GTK_WIDGET (priv->window), "configure-event", G_CALLBACK (on_window_configure_event), overlay); } gtk_window_present_with_time (priv->window, gdk_event_get_time (gtk_get_current_event ())); } static void nemo_desktop_overlay_dispose (GObject *object) { NemoDesktopOverlay *overlay = NEMO_DESKTOP_OVERLAY (object); g_clear_object (&overlay->priv->builder); if (overlay->priv->window) { gtk_widget_destroy (GTK_WIDGET (overlay->priv->window)); overlay->priv->window = NULL; } G_OBJECT_CLASS (nemo_desktop_overlay_parent_class)->dispose (object); } static void nemo_desktop_overlay_class_init (NemoDesktopOverlayClass *klass) { signals[ADJUSTS_CHANGED] = g_signal_new ("adjusts-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3, NEMO_TYPE_WINDOW, G_TYPE_INT, G_TYPE_INT); G_OBJECT_CLASS (klass)->dispose = nemo_desktop_overlay_dispose; } NemoDesktopOverlay * nemo_desktop_overlay_new (void) { return g_object_new (NEMO_TYPE_DESKTOP_OVERLAY, NULL); } void nemo_desktop_overlay_show (NemoDesktopOverlay *overlay, gint monitor) { g_return_if_fail (NEMO_IS_DESKTOP_OVERLAY (overlay)); show_overlay (overlay, monitor); } void nemo_desktop_overlay_update_in_place (NemoDesktopOverlay *overlay) { g_return_if_fail (NEMO_IS_DESKTOP_OVERLAY (overlay)); show_overlay (overlay, overlay->priv->monitor); }nemo-4.4.2/src/nemo-desktop-overlay.h000066400000000000000000000012001357442400300174760ustar00rootroot00000000000000#ifndef _NEMO_DESKTOP_OVERLAY_H_ #define _NEMO_DESKTOP_OVERLAY_H_ #include #include G_BEGIN_DECLS #define NEMO_TYPE_DESKTOP_OVERLAY (nemo_desktop_overlay_get_type ()) G_DECLARE_FINAL_TYPE (NemoDesktopOverlay, nemo_desktop_overlay, NEMO, DESKTOP_OVERLAY, GObject) NemoDesktopOverlay *nemo_desktop_overlay_new (void); void nemo_desktop_overlay_show (NemoDesktopOverlay *overlay, gint monitor); void nemo_desktop_overlay_update_in_place (NemoDesktopOverlay *overlay); G_END_DECLS #endif /* _NEMO_DESKTOP_OVERLAY_H_ */nemo-4.4.2/src/nemo-desktop-window.c000066400000000000000000000301731357442400300173320ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Darin Adler */ #include #include "nemo-desktop-window.h" #include "nemo-window-private.h" #include "nemo-actions.h" #include "nemo-desktop-manager.h" #include "nemo-icon-view.h" #include "nemo-desktop-icon-grid-view.h" #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_DESKTOP #include enum { PROP_MONITOR = 1, NUM_PROPERTIES }; struct NemoDesktopWindowDetails { gint monitor; gboolean loaded; }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoDesktopWindow, nemo_desktop_window, NEMO_TYPE_WINDOW); static void nemo_desktop_window_update_directory (NemoDesktopWindow *window) { GFile *location; g_assert (NEMO_IS_DESKTOP_WINDOW (window)); window->details->loaded = FALSE; location = g_file_new_for_uri (EEL_DESKTOP_URI); nemo_window_go_to (NEMO_WINDOW (window), location); window->details->loaded = TRUE; g_object_unref (location); } static void nemo_desktop_window_dispose (GObject *obj) { NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (obj); g_signal_handlers_disconnect_by_func (nemo_preferences, nemo_desktop_window_update_directory, window); G_OBJECT_CLASS (nemo_desktop_window_parent_class)->dispose (obj); } static void nemo_desktop_window_constructed (GObject *obj) { GtkActionGroup *action_group; GtkAction *action; AtkObject *accessible; NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (obj); NemoWindow *nwindow = NEMO_WINDOW (obj); G_OBJECT_CLASS (nemo_desktop_window_parent_class)->constructed (obj); g_object_set_data (G_OBJECT (window), "monitor_number", GINT_TO_POINTER (window->details->monitor)); gtk_widget_hide (nwindow->details->statusbar); gtk_widget_hide (nwindow->details->menubar); action_group = nemo_window_get_main_action_group (nwindow); /* Don't allow close action on desktop */ action = gtk_action_group_get_action (action_group, NEMO_ACTION_CLOSE); gtk_action_set_sensitive (action, FALSE); /* Don't allow new tab on desktop */ action = gtk_action_group_get_action (action_group, NEMO_ACTION_NEW_TAB); gtk_action_set_sensitive (action, FALSE); /* Set the accessible name so that it doesn't inherit the cryptic desktop URI. */ accessible = gtk_widget_get_accessible (GTK_WIDGET (window)); if (accessible) { atk_object_set_name (accessible, _("Desktop")); } nemo_desktop_window_update_geometry (window); gtk_window_set_resizable (GTK_WINDOW (window), FALSE); gtk_window_set_decorated (GTK_WINDOW (window), FALSE); gtk_widget_show (GTK_WIDGET (window)); } static void nemo_desktop_window_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (object); switch (property_id) { case PROP_MONITOR: g_value_set_int (value, window->details->monitor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_desktop_window_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (object); switch (property_id) { case PROP_MONITOR: window->details->monitor = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_desktop_window_init (NemoDesktopWindow *window) { window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_DESKTOP_WINDOW, NemoDesktopWindowDetails); g_object_set_data (G_OBJECT (window), "is_desktop_window", GINT_TO_POINTER (1)); /* Make it easier for themes authors to style the desktop window separately */ gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "nemo-desktop-window"); } NemoDesktopWindow * nemo_desktop_window_new (gint monitor) { GApplication *application; NemoDesktopWindow *window; application = g_application_get_default (); window = g_object_new (NEMO_TYPE_DESKTOP_WINDOW, "application", application, "disable-chrome", TRUE, "monitor", monitor, NULL); /* Stop wrong desktop window size in GTK 3.20*/ /* We don't want to set a default size, which the parent does, since this */ /* will cause the desktop window to open at the wrong size in gtk 3.20 */ #if GTK_CHECK_VERSION (3, 19, 0) gtk_window_set_default_size (GTK_WINDOW (window), -1, -1); #endif GdkRGBA transparent = {0, 0, 0, 0}; gtk_widget_override_background_color (GTK_WIDGET (window), 0, &transparent); /* Point window at the desktop folder. * Note that nemo_desktop_window_init is too early to do this. */ nemo_desktop_window_update_directory (window); return window; } static gboolean nemo_desktop_window_delete_event (GtkWidget *widget, GdkEventAny *event) { /* Returning true tells GTK+ not to delete the window. */ return TRUE; } static void map (GtkWidget *widget) { /* Chain up to realize our children */ GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->map (widget); gdk_window_lower (gtk_widget_get_window (widget)); GdkWindow *window; GdkRGBA transparent = { 0, 0, 0, 0 }; window = gtk_widget_get_window (widget); gdk_window_set_background_rgba (window, &transparent); } static void unrealize (GtkWidget *widget) { GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->unrealize (widget); } static void set_wmspec_desktop_hint (GdkWindow *window) { GdkAtom atom; atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE); gdk_property_change (window, gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE), gdk_x11_xatom_to_atom (XA_ATOM), 32, GDK_PROP_MODE_REPLACE, (guchar *) &atom, 1); } static void realize (GtkWidget *widget) { GdkVisual *visual; /* Make sure we get keyboard events */ gtk_widget_set_events (widget, gtk_widget_get_events (widget) | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (widget)); if (visual) { gtk_widget_set_visual (widget, visual); } /* Do the work of realizing. */ GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->realize (widget); /* This is the new way to set up the desktop window */ set_wmspec_desktop_hint (gtk_widget_get_window (widget)); } static NemoIconInfo * real_get_icon (NemoWindow *window, NemoWindowSlot *slot) { return nemo_icon_info_lookup_from_name (NEMO_ICON_DESKTOP, 48, gtk_widget_get_scale_factor (GTK_WIDGET (window))); } static void real_sync_title (NemoWindow *window, NemoWindowSlot *slot) { /* hardcode "Desktop" */ gtk_window_set_title (GTK_WINDOW (window), _("Desktop")); } static void real_window_close (NemoWindow *window) { /* stub, does nothing */ return; } static void nemo_desktop_window_class_init (NemoDesktopWindowClass *klass) { GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); NemoWindowClass *nclass = NEMO_WINDOW_CLASS (klass); GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->constructed = nemo_desktop_window_constructed; oclass->dispose = nemo_desktop_window_dispose; oclass->set_property = nemo_desktop_window_set_property; oclass->get_property = nemo_desktop_window_get_property; wclass->realize = realize; wclass->unrealize = unrealize; wclass->map = map; wclass->delete_event = nemo_desktop_window_delete_event; nclass->sync_title = real_sync_title; nclass->get_icon = real_get_icon; nclass->close = real_window_close; properties[PROP_MONITOR] = g_param_spec_int ("monitor", "Monitor number", "The monitor number this window is assigned to", G_MININT, G_MAXINT, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_type_class_add_private (klass, sizeof (NemoDesktopWindowDetails)); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } gboolean nemo_desktop_window_loaded (NemoDesktopWindow *window) { return window->details->loaded; } gint nemo_desktop_window_get_monitor (NemoDesktopWindow *window) { return window->details->monitor; } void nemo_desktop_window_update_geometry (NemoDesktopWindow *window) { GdkRectangle rect; nemo_desktop_manager_get_window_rect_for_monitor (nemo_desktop_manager_get (), window->details->monitor, &rect); DEBUG ("NemoDesktopWindow monitor:%d: x:%d, y:%d, w:%d, h:%d", window->details->monitor, rect.x, rect.y, rect.width, rect.height); gtk_window_move (GTK_WINDOW (window), rect.x, rect.y); gtk_widget_set_size_request (GTK_WIDGET (window), rect.width, rect.height); } gboolean nemo_desktop_window_get_grid_adjusts (NemoDesktopWindow *window, gint *h_adjust, gint *v_adjust) { NemoView *view; NemoWindowSlot *slot; NemoFile *file; slot = nemo_window_get_active_slot (NEMO_WINDOW (window)); view = nemo_window_slot_get_current_view (slot); g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); file = nemo_view_get_directory_as_file (view); nemo_icon_view_get_directory_grid_adjusts (NEMO_ICON_VIEW (view), file, h_adjust, v_adjust); return TRUE; } gboolean nemo_desktop_window_set_grid_adjusts (NemoDesktopWindow *window, gint h_adjust, gint v_adjust) { NemoView *view; NemoWindowSlot *slot; slot = nemo_window_get_active_slot (NEMO_WINDOW (window)); view = nemo_window_slot_get_current_view (slot); g_return_val_if_fail (NEMO_IS_DESKTOP_ICON_GRID_VIEW (view), FALSE); nemo_desktop_icon_grid_view_set_grid_adjusts (NEMO_DESKTOP_ICON_GRID_VIEW (view), h_adjust, v_adjust); return TRUE; } GtkActionGroup * nemo_desktop_window_get_action_group (NemoDesktopWindow *window) { NemoView *view; NemoWindowSlot *slot; slot = nemo_window_get_active_slot (NEMO_WINDOW (window)); view = nemo_window_slot_get_current_view (slot); g_return_val_if_fail (NEMO_IS_DESKTOP_ICON_GRID_VIEW (view), NULL); return nemo_desktop_icon_grid_view_get_action_group (NEMO_DESKTOP_ICON_GRID_VIEW (view)); }nemo-4.4.2/src/nemo-desktop-window.h000066400000000000000000000056671357442400300173510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Darin Adler */ /* nemo-desktop-window.h */ #ifndef NEMO_DESKTOP_WINDOW_H #define NEMO_DESKTOP_WINDOW_H #include "nemo-window.h" #define NEMO_TYPE_DESKTOP_WINDOW nemo_desktop_window_get_type() #define NEMO_DESKTOP_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_DESKTOP_WINDOW, NemoDesktopWindow)) #define NEMO_DESKTOP_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_DESKTOP_WINDOW, NemoDesktopWindowClass)) #define NEMO_IS_DESKTOP_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_DESKTOP_WINDOW)) #define NEMO_IS_DESKTOP_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_DESKTOP_WINDOW)) #define NEMO_DESKTOP_WINDOW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_DESKTOP_WINDOW, NemoDesktopWindowClass)) typedef struct NemoDesktopWindowDetails NemoDesktopWindowDetails; typedef struct { NemoWindow parent_spot; NemoDesktopWindowDetails *details; } NemoDesktopWindow; typedef struct { NemoWindowClass parent_spot; } NemoDesktopWindowClass; GType nemo_desktop_window_get_type (void); NemoDesktopWindow *nemo_desktop_window_new (gint monitor); gboolean nemo_desktop_window_loaded (NemoDesktopWindow *window); gint nemo_desktop_window_get_monitor (NemoDesktopWindow *window); void nemo_desktop_window_update_geometry (NemoDesktopWindow *window); gboolean nemo_desktop_window_get_grid_adjusts (NemoDesktopWindow *window, gint *h_adjust, gint *v_adjust); gboolean nemo_desktop_window_set_grid_adjusts (NemoDesktopWindow *window, gint h_adjust, gint v_adjust); GtkActionGroup * nemo_desktop_window_get_action_group (NemoDesktopWindow *window); #endif /* NEMO_DESKTOP_WINDOW_H */ nemo-4.4.2/src/nemo-empty-view.c000066400000000000000000000217471357442400300164710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-empty-view.c - implementation of empty view of directory. Copyright (C) 2006 Free Software Foundation, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Christian Neumair */ #include #include "nemo-empty-view.h" #include "nemo-view.h" #include "nemo-view-factory.h" #include #include #include struct NemoEmptyViewDetails { int number_of_files; }; static GList *nemo_empty_view_get_selection (NemoView *view); static GList *nemo_empty_view_get_selection_for_file_transfer (NemoView *view); static void nemo_empty_view_scroll_to_file (NemoView *view, const char *uri); G_DEFINE_TYPE (NemoEmptyView, nemo_empty_view, NEMO_TYPE_VIEW) static void nemo_empty_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { static GTimer *timer = NULL; static gdouble cumu = 0, elaps; NEMO_EMPTY_VIEW (view)->details->number_of_files++; GdkPixbuf *icon; if (!timer) timer = g_timer_new (); g_timer_start (timer); icon = nemo_file_get_icon_pixbuf (file, nemo_get_icon_size_for_zoom_level (NEMO_ZOOM_LEVEL_STANDARD), TRUE, 0, NEMO_FILE_ICON_FLAGS_NONE); elaps = g_timer_elapsed (timer, NULL); g_timer_stop (timer); g_object_unref (icon); cumu += elaps; g_message ("entire loading: %.3f, cumulative %.3f", elaps, cumu); } static void nemo_empty_view_begin_loading (NemoView *view) { } static void nemo_empty_view_clear (NemoView *view) { } static void nemo_empty_view_file_changed (NemoView *view, NemoFile *file, NemoDirectory *directory) { } static GList * nemo_empty_view_get_selection (NemoView *view) { return NULL; } static GList * nemo_empty_view_get_selection_for_file_transfer (NemoView *view) { return NULL; } static guint nemo_empty_view_get_item_count (NemoView *view) { return NEMO_EMPTY_VIEW (view)->details->number_of_files; } static gboolean nemo_empty_view_is_empty (NemoView *view) { return NEMO_EMPTY_VIEW (view)->details->number_of_files == 0; } static void nemo_empty_view_end_file_changes (NemoView *view) { } static void nemo_empty_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NEMO_EMPTY_VIEW (view)->details->number_of_files--; g_assert (NEMO_EMPTY_VIEW (view)->details->number_of_files >= 0); } static void nemo_empty_view_set_selection (NemoView *view, GList *selection) { nemo_view_notify_selection_changed (view); } static void nemo_empty_view_select_all (NemoView *view) { } static void nemo_empty_view_reveal_selection (NemoView *view) { } static void nemo_empty_view_merge_menus (NemoView *view) { NEMO_VIEW_CLASS (nemo_empty_view_parent_class)->merge_menus (view); } static void nemo_empty_view_update_menus (NemoView *view) { NEMO_VIEW_CLASS (nemo_empty_view_parent_class)->update_menus (view); } /* Reset sort criteria and zoom level to match defaults */ static void nemo_empty_view_reset_to_defaults (NemoView *view) { } static void nemo_empty_view_bump_zoom_level (NemoView *view, int zoom_increment) { } static NemoZoomLevel nemo_empty_view_get_zoom_level (NemoView *view) { return NEMO_ZOOM_LEVEL_STANDARD; } static void nemo_empty_view_zoom_to_level (NemoView *view, NemoZoomLevel zoom_level) { } static void nemo_empty_view_restore_default_zoom_level (NemoView *view) { } static gboolean nemo_empty_view_can_zoom_in (NemoView *view) { return FALSE; } static gboolean nemo_empty_view_can_zoom_out (NemoView *view) { return FALSE; } static void nemo_empty_view_start_renaming_file (NemoView *view, NemoFile *file, gboolean select_all) { } static void nemo_empty_view_click_policy_changed (NemoView *directory_view) { } static int nemo_empty_view_compare_files (NemoView *view, NemoFile *file1, NemoFile *file2) { if (file1 < file2) { return -1; } if (file1 > file2) { return +1; } return 0; } static gboolean nemo_empty_view_using_manual_layout (NemoView *view) { return FALSE; } static void nemo_empty_view_end_loading (NemoView *view, gboolean all_files_seen) { } static char * nemo_empty_view_get_first_visible_file (NemoView *view) { return NULL; } static void nemo_empty_view_scroll_to_file (NemoView *view, const char *uri) { } static void nemo_empty_view_sort_directories_first_changed (NemoView *view) { } static const char * nemo_empty_view_get_id (NemoView *view) { return NEMO_EMPTY_VIEW_ID; } static void nemo_empty_view_class_init (NemoEmptyViewClass *class) { NemoViewClass *nemo_view_class; g_type_class_add_private (class, sizeof (NemoEmptyViewDetails)); nemo_view_class = NEMO_VIEW_CLASS (class); nemo_view_class->add_file = nemo_empty_view_add_file; nemo_view_class->begin_loading = nemo_empty_view_begin_loading; nemo_view_class->bump_zoom_level = nemo_empty_view_bump_zoom_level; nemo_view_class->can_zoom_in = nemo_empty_view_can_zoom_in; nemo_view_class->can_zoom_out = nemo_empty_view_can_zoom_out; nemo_view_class->click_policy_changed = nemo_empty_view_click_policy_changed; nemo_view_class->clear = nemo_empty_view_clear; nemo_view_class->file_changed = nemo_empty_view_file_changed; nemo_view_class->get_selection = nemo_empty_view_get_selection; nemo_view_class->get_selection_for_file_transfer = nemo_empty_view_get_selection_for_file_transfer; nemo_view_class->get_item_count = nemo_empty_view_get_item_count; nemo_view_class->is_empty = nemo_empty_view_is_empty; nemo_view_class->remove_file = nemo_empty_view_remove_file; nemo_view_class->merge_menus = nemo_empty_view_merge_menus; nemo_view_class->update_menus = nemo_empty_view_update_menus; nemo_view_class->reset_to_defaults = nemo_empty_view_reset_to_defaults; nemo_view_class->restore_default_zoom_level = nemo_empty_view_restore_default_zoom_level; nemo_view_class->reveal_selection = nemo_empty_view_reveal_selection; nemo_view_class->select_all = nemo_empty_view_select_all; nemo_view_class->set_selection = nemo_empty_view_set_selection; nemo_view_class->compare_files = nemo_empty_view_compare_files; nemo_view_class->sort_directories_first_changed = nemo_empty_view_sort_directories_first_changed; nemo_view_class->start_renaming_file = nemo_empty_view_start_renaming_file; nemo_view_class->get_zoom_level = nemo_empty_view_get_zoom_level; nemo_view_class->zoom_to_level = nemo_empty_view_zoom_to_level; nemo_view_class->end_file_changes = nemo_empty_view_end_file_changes; nemo_view_class->using_manual_layout = nemo_empty_view_using_manual_layout; nemo_view_class->end_loading = nemo_empty_view_end_loading; nemo_view_class->get_view_id = nemo_empty_view_get_id; nemo_view_class->get_first_visible_file = nemo_empty_view_get_first_visible_file; nemo_view_class->scroll_to_file = nemo_empty_view_scroll_to_file; } static void nemo_empty_view_init (NemoEmptyView *empty_view) { empty_view->details = G_TYPE_INSTANCE_GET_PRIVATE (empty_view, NEMO_TYPE_EMPTY_VIEW, NemoEmptyViewDetails); } static NemoView * nemo_empty_view_create (NemoWindowSlot *slot) { NemoEmptyView *view; g_assert (NEMO_IS_WINDOW_SLOT (slot)); view = g_object_new (NEMO_TYPE_EMPTY_VIEW, "window-slot", slot, NULL); return NEMO_VIEW (view); } static gboolean nemo_empty_view_supports_uri (const char *uri, GFileType file_type, const char *mime_type) { if (file_type == G_FILE_TYPE_DIRECTORY) { return TRUE; } if (strcmp (mime_type, NEMO_SAVED_SEARCH_MIMETYPE) == 0){ return TRUE; } if (g_str_has_prefix (uri, "trash:")) { return TRUE; } if (g_str_has_prefix (uri, EEL_SEARCH_URI)) { return TRUE; } return FALSE; } static NemoViewInfo nemo_empty_view = { NEMO_EMPTY_VIEW_ID, "Empty", "Empty View", "_Empty View", "The empty view encountered an error.", "Display this location with the empty view.", nemo_empty_view_create, nemo_empty_view_supports_uri }; void nemo_empty_view_register (void) { nemo_empty_view.id = nemo_empty_view.id; nemo_empty_view.view_combo_label = nemo_empty_view.view_combo_label; nemo_empty_view.view_menu_label_with_mnemonic = nemo_empty_view.view_menu_label_with_mnemonic; nemo_empty_view.error_label = nemo_empty_view.error_label; nemo_empty_view.display_location_label = nemo_empty_view.display_location_label; nemo_view_factory_register (&nemo_empty_view); } nemo-4.4.2/src/nemo-empty-view.h000066400000000000000000000040771357442400300164730ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-empty-view.h - interface for empty view of directory. Copyright (C) 2006 Free Software Foundation, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Christian Neumair */ #ifndef NEMO_EMPTY_VIEW_H #define NEMO_EMPTY_VIEW_H #include "nemo-view.h" #define NEMO_TYPE_EMPTY_VIEW nemo_empty_view_get_type() #define NEMO_EMPTY_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_EMPTY_VIEW, NemoEmptyView)) #define NEMO_EMPTY_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_EMPTY_VIEW, NemoEmptyViewClass)) #define NEMO_IS_EMPTY_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_EMPTY_VIEW)) #define NEMO_IS_EMPTY_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_EMPTY_VIEW)) #define NEMO_EMPTY_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_EMPTY_VIEW, NemoEmptyViewClass)) #define NEMO_EMPTY_VIEW_ID "OAFIID:Nemo_File_Manager_Empty_View" typedef struct NemoEmptyViewDetails NemoEmptyViewDetails; typedef struct { NemoView parent_instance; NemoEmptyViewDetails *details; } NemoEmptyView; typedef struct { NemoViewClass parent_class; } NemoEmptyViewClass; GType nemo_empty_view_get_type (void); void nemo_empty_view_register (void); #endif /* NEMO_EMPTY_VIEW_H */ nemo-4.4.2/src/nemo-error-reporting.c000066400000000000000000000241051357442400300175120ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-error-reporting.h - implementation of file manager functions that report errors to the user. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #include #include "nemo-error-reporting.h" #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_DIRECTORY_VIEW #include #define NEW_NAME_TAG "Nemo: new name" #define MAXIMUM_DISPLAYED_FILE_NAME_LENGTH 50 static void finish_rename (NemoFile *file, gboolean stop_timer, GError *error); void nemo_report_error_loading_directory (NemoFile *file, GError *error, GtkWindow *parent_window) { char *file_name; char *message; if (error == NULL || error->message == NULL) { return; } if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED) { /* This case is retried automatically */ return; } file_name = nemo_file_get_display_name (file); if (error->domain == G_IO_ERROR) { switch (error->code) { case G_IO_ERROR_PERMISSION_DENIED: message = g_strdup_printf (_("You do not have the permissions necessary to view the contents of \"%s\"."), file_name); break; case G_IO_ERROR_NOT_FOUND: message = g_strdup_printf (_("\"%s\" could not be found. Perhaps it has recently been deleted."), file_name); break; default: message = g_strdup_printf (_("Sorry, could not display all the contents of \"%s\": %s"), file_name, error->message); } } else { message = g_strdup (error->message); } eel_show_error_dialog (_("The folder contents could not be displayed."), message, parent_window); g_free (file_name); g_free (message); } void nemo_report_error_setting_group (NemoFile *file, GError *error, GtkWindow *parent_window) { char *file_name; char *message; if (error == NULL) { return; } file_name = nemo_file_get_display_name (file); message = NULL; if (error->domain == G_IO_ERROR) { switch (error->code) { case G_IO_ERROR_PERMISSION_DENIED: message = g_strdup_printf (_("You do not have the permissions necessary to change the group of \"%s\"."), file_name); break; default: break; } } if (message == NULL) { /* We should invent decent error messages for every case we actually experience. */ g_warning ("Hit unhandled case %s:%d in nemo_report_error_setting_group", g_quark_to_string (error->domain), error->code); /* fall through */ message = g_strdup_printf (_("Sorry, could not change the group of \"%s\": %s"), file_name, error->message); } eel_show_error_dialog (_("The group could not be changed."), message, parent_window); g_free (file_name); g_free (message); } void nemo_report_error_setting_owner (NemoFile *file, GError *error, GtkWindow *parent_window) { char *file_name; char *message; if (error == NULL) { return; } file_name = nemo_file_get_display_name (file); message = g_strdup_printf (_("Sorry, could not change the owner of \"%s\": %s"), file_name, error->message); eel_show_error_dialog (_("The owner could not be changed."), message, parent_window); g_free (file_name); g_free (message); } void nemo_report_error_setting_permissions (NemoFile *file, GError *error, GtkWindow *parent_window) { char *file_name; char *message; if (error == NULL) { return; } file_name = nemo_file_get_display_name (file); message = g_strdup_printf (_("Sorry, could not change the permissions of \"%s\": %s"), file_name, error->message); eel_show_error_dialog (_("The permissions could not be changed."), message, parent_window); g_free (file_name); g_free (message); } typedef struct _NemoRenameData { char *name; NemoFileOperationCallback callback; gpointer callback_data; } NemoRenameData; void nemo_report_error_renaming_file (NemoFile *file, const char *new_name, GError *error, GtkWindow *parent_window) { char *original_name, *original_name_truncated; char *new_name_truncated; char *message; /* Truncate names for display since very long file names with no spaces * in them won't get wrapped, and can create insanely wide dialog boxes. */ original_name = nemo_file_get_display_name (file); original_name_truncated = eel_str_middle_truncate (original_name, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH); g_free (original_name); new_name_truncated = eel_str_middle_truncate (new_name, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH); message = NULL; if (error->domain == G_IO_ERROR) { switch (error->code) { case G_IO_ERROR_EXISTS: message = g_strdup_printf (_("The name \"%s\" is already used in this folder. " "Please use a different name."), new_name_truncated); break; case G_IO_ERROR_NOT_FOUND: message = g_strdup_printf (_("There is no \"%s\" in this folder. " "Perhaps it was just moved or deleted?"), original_name_truncated); break; case G_IO_ERROR_PERMISSION_DENIED: message = g_strdup_printf (_("You do not have the permissions necessary to rename \"%s\"."), original_name_truncated); break; case G_IO_ERROR_INVALID_FILENAME: if (strchr (new_name, '/') != NULL) { message = g_strdup_printf (_("The name \"%s\" is not valid because it contains the character \"/\". " "Please use a different name."), new_name_truncated); } else { message = g_strdup_printf (_("The name \"%s\" is not valid. " "Please use a different name."), new_name_truncated); } break; case G_IO_ERROR_FILENAME_TOO_LONG: message = g_strdup_printf (_("The name \"%s\" is too long. " "Please use a different name."), new_name_truncated); break; default: break; } } if (message == NULL) { /* We should invent decent error messages for every case we actually experience. */ g_warning ("Hit unhandled case %s:%d in nemo_report_error_renaming_file", g_quark_to_string (error->domain), error->code); /* fall through */ message = g_strdup_printf (_("Sorry, could not rename \"%s\" to \"%s\": %s"), original_name_truncated, new_name_truncated, error->message); } g_free (original_name_truncated); g_free (new_name_truncated); eel_show_error_dialog (_("The item could not be renamed."), message, parent_window); g_free (message); } static void nemo_rename_data_free (NemoRenameData *data) { g_free (data->name); g_free (data); } static void rename_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { NemoRenameData *data; g_assert (NEMO_IS_FILE (file)); g_assert (callback_data == NULL); data = g_object_get_data (G_OBJECT (file), NEW_NAME_TAG); g_assert (data != NULL); if (error && !(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)) { /* If rename failed, notify the user. */ nemo_report_error_renaming_file (file, data->name, error, NULL); } finish_rename (file, TRUE, error); } static void cancel_rename_callback (gpointer callback_data) { GError *error; error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"); finish_rename (NEMO_FILE (callback_data), FALSE, error); g_error_free (error); } static void finish_rename (NemoFile *file, gboolean stop_timer, GError *error) { NemoRenameData *data; data = g_object_get_data (G_OBJECT (file), NEW_NAME_TAG); if (data == NULL) { return; } /* Cancel both the rename and the timed wait. */ nemo_file_cancel (file, rename_callback, NULL); if (stop_timer) { eel_timed_wait_stop (cancel_rename_callback, file); } if (data->callback != NULL) { data->callback (file, NULL, error, data->callback_data); } /* Let go of file name. */ g_object_set_data (G_OBJECT (file), NEW_NAME_TAG, NULL); } void nemo_rename_file (NemoFile *file, const char *new_name, NemoFileOperationCallback callback, gpointer callback_data) { char *old_name, *wait_message; NemoRenameData *data; char *uri; GError *error; g_return_if_fail (NEMO_IS_FILE (file)); g_return_if_fail (new_name != NULL); /* Stop any earlier rename that's already in progress. */ error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"); finish_rename (file, TRUE, error); g_error_free (error); data = g_new0 (NemoRenameData, 1); data->name = g_strdup (new_name); data->callback = callback; data->callback_data = callback_data; /* Attach the new name to the file. */ g_object_set_data_full (G_OBJECT (file), NEW_NAME_TAG, data, (GDestroyNotify)nemo_rename_data_free); /* Start the timed wait to cancel the rename. */ old_name = nemo_file_get_display_name (file); wait_message = g_strdup_printf (_("Renaming \"%s\" to \"%s\"."), old_name, new_name); g_free (old_name); eel_timed_wait_start (cancel_rename_callback, file, wait_message, NULL); /* FIXME bugzilla.gnome.org 42395: Parent this? */ g_free (wait_message); uri = nemo_file_get_uri (file); DEBUG ("Renaming file %s to %s", uri, new_name); g_free (uri); /* Start the rename. */ nemo_file_rename (file, new_name, rename_callback, NULL); } nemo-4.4.2/src/nemo-error-reporting.h000066400000000000000000000041241357442400300175160ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-error-reporting.h - interface for file manager functions that report errors to the user. Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #ifndef NEMO_ERROR_REPORTING_H #define NEMO_ERROR_REPORTING_H #include #include void nemo_report_error_loading_directory (NemoFile *file, GError *error, GtkWindow *parent_window); void nemo_report_error_renaming_file (NemoFile *file, const char *new_name, GError *error, GtkWindow *parent_window); void nemo_report_error_setting_permissions (NemoFile *file, GError *error, GtkWindow *parent_window); void nemo_report_error_setting_owner (NemoFile *file, GError *error, GtkWindow *parent_window); void nemo_report_error_setting_group (NemoFile *file, GError *error, GtkWindow *parent_window); /* FIXME bugzilla.gnome.org 42394: Should this file be renamed or should this function be moved? */ void nemo_rename_file (NemoFile *file, const char *new_name, NemoFileOperationCallback callback, gpointer callback_data); #endif /* NEMO_ERROR_REPORTING_H */ nemo-4.4.2/src/nemo-extension-config-widget.c000066400000000000000000000343041357442400300211140ustar00rootroot00000000000000/* nemo-extension-config-widget.h */ /* A widget that displays a list of extensions to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #include #include "nemo-extension-config-widget.h" #include "nemo-application.h" #include "nemo-global-preferences.h" #include G_DEFINE_TYPE (NemoExtensionConfigWidget, nemo_extension_config_widget, NEMO_TYPE_CONFIG_BASE_WIDGET); typedef struct { NemoExtensionConfigWidget *widget; gchar *name; gchar *display_name; gchar *desc; gchar *config_exec; } ExtensionProxy; static void extension_proxy_free (ExtensionProxy *proxy) { g_clear_pointer (&proxy->name, g_free); g_clear_pointer (&proxy->display_name, g_free); g_clear_pointer (&proxy->desc, g_free); g_clear_pointer (&proxy->config_exec, g_free); } static void update_restart_visiblity (NemoExtensionConfigWidget *widget) { GList *tmp = g_list_copy (widget->initial_extension_ids); gchar **new_settings = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS); gboolean needs_restart = FALSE; if (g_list_length (tmp) != g_strv_length (new_settings)) { needs_restart = TRUE; goto out; } guint i; for (i = 0; i < g_strv_length (new_settings); i++) { GList *l = g_list_find_custom (tmp, new_settings[i], (GCompareFunc) g_strcmp0); if (!l) { needs_restart = TRUE; break; } } out: g_strfreev (new_settings); g_list_free (tmp); gtk_widget_set_visible (widget->restart_button, needs_restart); } static GtkWidget * get_button_for_row (GtkWidget *row) { GtkWidget *ret; GtkWidget *box = gtk_bin_get_child (GTK_BIN (row)); GList *clist = gtk_container_get_children (GTK_CONTAINER (box)); ret = clist->data; g_list_free (clist); return ret; } static void on_row_activated (GtkWidget *box, GtkWidget *row, GtkWidget *widget) { GtkWidget *button = get_button_for_row (row); gtk_button_clicked (GTK_BUTTON (button)); } static void on_check_toggled(GtkWidget *button, ExtensionProxy *proxy) { gboolean enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS); GPtrArray *new_list = g_ptr_array_new (); guint i; if (enabled) { for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->name) == 0) continue; g_ptr_array_add (new_list, g_strdup (blacklist[i])); } } else { for (i = 0; i < g_strv_length (blacklist); i++) { g_ptr_array_add (new_list, g_strdup (blacklist[i])); } g_ptr_array_add (new_list, g_strdup (proxy->name)); } g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_signal_handler_block (nemo_plugin_preferences, proxy->widget->bl_handler); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS, (const gchar * const *)new_list_ptr); g_signal_handler_unblock (nemo_plugin_preferences, proxy->widget->bl_handler); update_restart_visiblity (proxy->widget); g_strfreev (blacklist); g_strfreev (new_list_ptr); } static gboolean on_config_clicked (GtkLinkButton *button, gpointer user_data) { ExtensionProxy *proxy = (ExtensionProxy *) user_data; g_spawn_command_line_async (proxy->config_exec, NULL); return GDK_EVENT_STOP; } #define LINE_PREFIX "NEMO_EXTENSION:::" #define LINE_PREFIX_LEN 17 static void detect_extensions (NemoExtensionConfigWidget *widget) { gchar *out = NULL; if (g_spawn_command_line_sync (LIBEXECDIR "/nemo-extensions-list", &out, NULL, NULL, NULL)) { if (out) { gchar **lines = g_strsplit (out, "\n", -1); g_free (out); guint i; for (i = 0; i < g_strv_length (lines); i++) { if (g_str_has_prefix (lines[i], LINE_PREFIX)) { ExtensionProxy *p = g_slice_new0 (ExtensionProxy); gchar **split = g_strsplit (lines[i] + LINE_PREFIX_LEN, ":::", -1); gint len = g_strv_length (split); if (len > 0) { p->name = g_strdup (split[0]); } if (len == 3) { p->display_name = g_strdup (split[1]); p->desc = g_strdup (split[2]); } else if (len == 4) { p->display_name = g_strdup (split[1]); p->desc = g_strdup (split[2]); p->config_exec = g_strdup (split[3]); } else { p->display_name = NULL; p->desc = NULL; p->config_exec = NULL; } p->widget = widget; widget->current_extensions = g_list_append (widget->current_extensions, p); g_strfreev (split); } } g_strfreev (lines); } } else { g_printerr ("oops could not run nemo-extensions-list\n"); } } static void refresh_widget (NemoExtensionConfigWidget *widget) { if (widget->current_extensions != NULL) { g_list_free_full (widget->current_extensions, (GDestroyNotify) extension_proxy_free); widget->current_extensions = NULL; } nemo_config_base_widget_clear_list (NEMO_CONFIG_BASE_WIDGET (widget)); detect_extensions (widget); if (widget->current_extensions == NULL) { GtkWidget *empty_label = gtk_label_new (NULL); gchar *markup = NULL; markup = g_strdup_printf ("%s", _("No extensions found")); gtk_label_set_markup (GTK_LABEL (empty_label), markup); g_free (markup); GtkWidget *empty_row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (empty_row), empty_label); gtk_widget_show_all (empty_row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), empty_row); gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), FALSE); } else { GtkSizeGroup *row_group, *name_group; GList *l; gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS); row_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); name_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); for (l = widget->current_extensions; l != NULL; l=l->next) { gchar *markup; ExtensionProxy *proxy = l->data; gboolean active = TRUE; guint i = 0; for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->name) == 0) { active = FALSE; break; } } GtkWidget *w; GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); GtkWidget *button = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active); g_signal_connect (button, "toggled", G_CALLBACK (on_check_toggled), proxy); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2); w = gtk_label_new (NULL); markup = NULL; if (proxy->display_name == NULL) markup = g_strdup_printf ("%s", proxy->name); else markup = g_strdup_printf ("%s", proxy->display_name); gtk_label_set_markup (GTK_LABEL (w), markup); gtk_label_set_xalign (GTK_LABEL (w), 0.0); g_clear_pointer (&markup, g_free); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0); gtk_size_group_add_widget (name_group, w); w = gtk_label_new (NULL); gtk_label_set_lines (GTK_LABEL (w), 2); gtk_label_set_line_wrap (GTK_LABEL (w), TRUE); gtk_label_set_xalign (GTK_LABEL (w), 0.0); if (proxy->display_name == NULL) markup = g_strdup (_("no information available")); else markup = g_strdup_printf ("%s", proxy->desc); gtk_label_set_markup (GTK_LABEL (w), markup); g_clear_pointer (&markup, g_free); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 6); if (proxy->config_exec != NULL) { button = gtk_link_button_new_with_label ("", _("Configure")); g_signal_connect (button, "activate-link", G_CALLBACK (on_config_clicked), proxy); gtk_box_pack_end (GTK_BOX (box), button, FALSE, FALSE, 2); gtk_widget_set_tooltip_text (button, ""); } GtkWidget *row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (row), box); gtk_size_group_add_widget (row_group, row); gtk_widget_show_all (row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), row); } g_strfreev (blacklist); } update_restart_visiblity (widget); nemo_config_base_widget_set_default_buttons_sensitive (NEMO_CONFIG_BASE_WIDGET (widget), widget->current_extensions != NULL); } static void on_settings_changed (GSettings *settings, gchar *key, gpointer user_data) { NemoExtensionConfigWidget *w = NEMO_EXTENSION_CONFIG_WIDGET (user_data); update_restart_visiblity (w); refresh_widget (w); } static void on_enable_clicked (GtkWidget *button, NemoExtensionConfigWidget *widget) { g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS, NULL); } static void on_disable_clicked (GtkWidget *button, NemoExtensionConfigWidget *widget) { GPtrArray *new_list = g_ptr_array_new (); GList *l; for (l = widget->current_extensions; l != NULL; l = l->next) g_ptr_array_add (new_list, g_strdup (((ExtensionProxy *) l->data)->name)); g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS, (const gchar * const *) new_list_ptr); g_strfreev (new_list_ptr); } static void on_restart_clicked (GtkWidget *button, NemoExtensionConfigWidget *widget) { /* TODO: We should be able to get existing window locations and geometry out of * gtk_application_get_windows() and restore them with the proper window geometry * and locations opened when restarting... dual pane, multiple tabs will probably * not be possible or exceedingly tedious, but we can cover the default view in * each window. */ g_spawn_command_line_async ("sh -c \"nemo --quit && sleep 1 && nemo\"", NULL); } static void nemo_extension_config_widget_finalize (GObject *object) { NemoExtensionConfigWidget *widget = NEMO_EXTENSION_CONFIG_WIDGET (object); if (widget->current_extensions != NULL) { g_list_free_full (widget->current_extensions, (GDestroyNotify) extension_proxy_free); widget->current_extensions = NULL; } g_list_free_full (widget->initial_extension_ids, (GDestroyNotify) g_free); g_signal_handler_disconnect (nemo_plugin_preferences, widget->bl_handler); G_OBJECT_CLASS (nemo_extension_config_widget_parent_class)->finalize (object); } static void nemo_extension_config_widget_class_init (NemoExtensionConfigWidgetClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_extension_config_widget_finalize; } static void nemo_extension_config_widget_init (NemoExtensionConfigWidget *self) { self->current_extensions = NULL; self->initial_extension_ids = NULL; self->bl_handler = g_signal_connect (nemo_plugin_preferences, "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS, G_CALLBACK (on_settings_changed), self); GtkWidget *label = nemo_config_base_widget_get_label (NEMO_CONFIG_BASE_WIDGET (self)); gchar *title = g_strdup (_("Extensions")); gchar *markup = g_strdup_printf ("%s", title); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (title); g_free (markup); self->restart_button = gtk_button_new_with_label (_("Extensions changed. Restart required.")); GtkWidget *bb = nemo_config_base_widget_get_buttonbox (NEMO_CONFIG_BASE_WIDGET (self)); gtk_box_pack_end (GTK_BOX (bb), self->restart_button, FALSE, FALSE, 0); g_signal_connect (self->restart_button, "clicked", G_CALLBACK (on_restart_clicked), self); gtk_widget_set_no_show_all (self->restart_button, TRUE); g_signal_connect (nemo_config_base_widget_get_enable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_enable_clicked), self); g_signal_connect (nemo_config_base_widget_get_disable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_disable_clicked), self); g_signal_connect (NEMO_CONFIG_BASE_WIDGET (self)->listbox, "row-activated", G_CALLBACK (on_row_activated), self); gchar **init_settings = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS); guint i; for (i = 0; i < g_strv_length (init_settings); i++) { self->initial_extension_ids = g_list_append (self->initial_extension_ids, g_strdup (init_settings[i])); } g_strfreev (init_settings); refresh_widget (self); } GtkWidget * nemo_extension_config_widget_new (void) { return g_object_new (NEMO_TYPE_EXTENSION_CONFIG_WIDGET, NULL); } nemo-4.4.2/src/nemo-extension-config-widget.h000066400000000000000000000033401357442400300211150ustar00rootroot00000000000000/* nemo-extension-config-widget.h */ /* A widget that displays a list of extensions to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #ifndef __NEMO_EXTENSION_CONFIG_WIDGET_H__ #define __NEMO_EXTENSION_CONFIG_WIDGET_H__ #include #include #include #include "nemo-config-base-widget.h" G_BEGIN_DECLS #define NEMO_TYPE_EXTENSION_CONFIG_WIDGET (nemo_extension_config_widget_get_type()) #define NEMO_EXTENSION_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_EXTENSION_CONFIG_WIDGET, NemoExtensionConfigWidget)) #define NEMO_EXTENSION_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_EXTENSION_CONFIG_WIDGET, NemoExtensionConfigWidgetClass)) #define NEMO_IS_EXTENSION_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_EXTENSION_CONFIG_WIDGET)) #define NEMO_IS_EXTENSION_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_EXTENSION_CONFIG_WIDGET)) #define NEMO_EXTENSION_CONFIG_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_EXTENSION_CONFIG_WIDGET, NemoExtensionConfigWidgetClass)) typedef struct _NemoExtensionConfigWidget NemoExtensionConfigWidget; typedef struct _NemoExtensionConfigWidgetClass NemoExtensionConfigWidgetClass; struct _NemoExtensionConfigWidget { NemoConfigBaseWidget parent; GtkWidget *restart_button; GList *current_extensions; GList *initial_extension_ids; gulong bl_handler; }; struct _NemoExtensionConfigWidgetClass { NemoConfigBaseWidgetClass parent_class; }; GType nemo_extension_config_widget_get_type (void); GtkWidget *nemo_extension_config_widget_new (void); G_END_DECLS #endif /* __NEMO_EXTENSION_CONFIG_WIDGET_H__ */ nemo-4.4.2/src/nemo-extensions-list.c000066400000000000000000000076351357442400300175330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-open-with-main.c - Start the "Open with" dialog. * Nemo * * Copyright (C) 2005 Vincent Untz * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: * Vincent Untz * Cosimo Cecchi */ #include #include #include #include #include #include static GList *module_objects = NULL; static void module_object_weak_notify (gpointer user_data, GObject *object) { module_objects = g_list_remove (module_objects, object); } static void load_module_objects (NemoModule *module) { const GType *types; int num_types; int i; module->list_types (&types, &num_types); for (i = 0; i < num_types; i++) { if (types[i] == 0) { /* Work around broken extensions */ break; } GObject *object; object = g_object_new (types[i], NULL); g_object_weak_ref (object, (GWeakNotify)module_object_weak_notify, NULL); module_objects = g_list_prepend (module_objects, object); } } static void load_module_file (const char *filename) { NemoModule *module = NULL; module = g_object_new (NEMO_TYPE_MODULE, NULL); module->path = g_strdup (filename); if (g_type_module_use (G_TYPE_MODULE (module))) { load_module_objects (module); g_type_module_unuse (G_TYPE_MODULE (module)); } else { g_object_unref (module); } } static void populate_from_directory (const gchar *path) { GDir *dir; dir = g_dir_open (path, 0, NULL); if (dir) { const char *name; while ((name = g_dir_read_name (dir))) { if (g_str_has_suffix (name, "." G_MODULE_SUFFIX)) { char *filename; filename = g_build_filename (path, name, NULL); load_module_file (filename); g_free (filename); } } g_dir_close (dir); } } static GList * module_get_extensions_for_type (GType type) { GList *l; GList *ret = NULL; for (l = module_objects; l != NULL; l = l->next) { if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data), type)) { g_object_ref (l->data); ret = g_list_prepend (ret, l->data); } } return ret; } int main (int argc, char *argv[]) { populate_from_directory (NEMO_EXTENSIONDIR); GList *nd_providers; GList *l; nd_providers = module_get_extensions_for_type (NEMO_TYPE_NAME_AND_DESC_PROVIDER); for (l = module_objects; l != NULL; l = l->next) { GObject *obj = G_OBJECT (l->data); g_printf ("NEMO_EXTENSION:::%s", G_OBJECT_TYPE_NAME (obj)); if (g_list_index (nd_providers, obj) > -1) { GList *nd_list = nemo_name_and_desc_provider_get_name_and_desc (NEMO_NAME_AND_DESC_PROVIDER (obj)); g_printf (":::%s\n", (gchar *) nd_list->data); g_list_free (nd_list); } else { g_printf ("\n"); } } g_list_free_full (nd_providers, (GDestroyNotify) g_object_unref); return 0; } nemo-4.4.2/src/nemo-file-management-properties.c000066400000000000000000001134351357442400300216020ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-management-properties.c - Functions to create and show the nemo preference dialog. Copyright (C) 2002 Jan Arne Petersen The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Jan Arne Petersen */ #include #include "nemo-file-management-properties.h" #include #include #include #include #include #include #include #include #include #include #include "nemo-plugin-manager.h" #include "nemo-actions.h" /* string enum preferences */ #define NEMO_FILE_MANAGEMENT_PROPERTIES_DEFAULT_VIEW_WIDGET "default_view_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_ICON_VIEW_ZOOM_WIDGET "icon_view_zoom_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_COMPACT_VIEW_ZOOM_WIDGET "compact_view_zoom_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_LIST_VIEW_ZOOM_WIDGET "list_view_zoom_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SORT_ORDER_WIDGET "sort_order_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_DATE_FORMAT_WIDGET "date_format_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_PREVIEW_IMAGE_WIDGET "preview_image_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_PREVIEW_FOLDER_WIDGET "preview_folder_combobox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SIZE_PREFIXES_WIDGET "size_prefixes_combobox" /* bool preferences */ #define NEMO_FILE_MANAGEMENT_PROPERTIES_INHERIT_VIEW_WIDGET "inherit_view_checkbox" #define NEMO_FILE_MANAGEMENT_PROPERTIES_REVERSE_SORT_WIDGET "reverse_sort_checkbox" #define NEMO_FILE_MANAGEMENT_QUICK_RENAMES_WITH_PAUSE_IN_BETWEEN "quick_renames_with_pause_in_between" #define NEMO_FILE_MANAGEMENT_PROPERTIES_FOLDERS_FIRST_WIDGET "sort_folders_first_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_COMPACT_LAYOUT_WIDGET "compact_layout_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_LABELS_BESIDE_ICONS_WIDGET "labels_beside_icons_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_ALL_COLUMNS_SAME_WIDTH "all_columns_same_width_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_ALWAYS_USE_BROWSER_WIDGET "always_use_browser_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_CONFIRM_MOVE_WIDGET "trash_confirm_move_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_CONFIRM_WIDGET "trash_confirm_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_DELETE_WIDGET "trash_delete_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SWAP_TRASH_DELETE "swap_trash_binding_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_OPEN_NEW_WINDOW_WIDGET "new_window_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TREE_VIEW_FOLDERS_WIDGET "treeview_folders_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_PREVIOUS_ICON_TOOLBAR_WIDGET "show_previous_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_NEXT_ICON_TOOLBAR_WIDGET "show_next_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_UP_ICON_TOOLBAR_WIDGET "show_up_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_RELOAD_ICON_TOOLBAR_WIDGET "show_reload_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_EDIT_ICON_TOOLBAR_WIDGET "show_edit_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_HOME_ICON_TOOLBAR_WIDGET "show_home_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_COMPUTER_ICON_TOOLBAR_WIDGET "show_computer_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SEARCH_ICON_TOOLBAR_WIDGET "show_search_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_NEW_FOLDER_ICON_TOOLBAR_WIDGET "show_new_folder_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_OPEN_IN_TERMINAL_ICON_TOOLBAR_WIDGET "show_open_in_terminal_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_ICON_VIEW_ICON_TOOLBAR_WIDGET "show_icon_view_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_LIST_VIEW_ICON_TOOLBAR_WIDGET "show_list_view_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_COMPACT_VIEW_ICON_TOOLBAR_WIDGET "show_compact_view_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SHOW_THUMBNAILS_ICON_TOOLBAR_WIDGET "show_show_thumbnails_icon_toolbar_togglebutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_FULL_PATH_IN_TITLE_BARS_WIDGET "show_full_path_in_title_bars_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_CLOSE_DEVICE_VIEW_ON_EJECT_WIDGET "close_device_view_on_eject_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_AUTOMOUNT_MEDIA_WIDGET "media_automount_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_AUTOOPEN_MEDIA_WIDGET "media_autoopen_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_AUTORUN_MEDIA_WIDGET "media_autorun_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_ADVANCED_PERMISSIONS_WIDGET "show_advanced_permissions_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_START_WITH_DUAL_PANE_WIDGET "start_with_dual_pane_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET "ignore_view_metadata_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_BOOKMARKS_IN_TO_MENUS_WIDGET "bookmarks_in_to_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_PLACES_IN_TO_MENUS_WIDGET "places_in_to_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_INHERIT_SHOW_THUMBNAILS_WIDGET "inherit_show_thumbnails_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_BULK_RENAME_WIDGET "bulk_rename_entry" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_ICON_VIEW_WIDGET "tooltips_on_icon_view_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_LIST_VIEW_WIDGET "tooltips_on_list_view_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_DESKTOP_WIDGET "tooltips_on_desktop_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FILE_TYPE_WIDGET "tt_show_file_type_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_MOD_DATE_WIDGET "tt_show_modified_date_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_ACCESS_DATE_WIDGET "tt_show_accessed_date_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_CREATED_DATE_WIDGET "tt_show_created_date_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FULL_PATH_WIDGET "tt_show_full_path_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_NEMO_PREFERENCES_SKIP_FILE_OP_QUEUE_WIDGET "skip_file_op_queue_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_NEMO_PREFERENCES_CLICK_DBL_PARENT_FOLDER_WIDGET "click_double_parent_folder_checkbutton" /* int enums */ #define NEMO_FILE_MANAGEMENT_PROPERTIES_THUMBNAIL_LIMIT_WIDGET "preview_image_size_combobox" #define W(s) (gtk_builder_get_object (builder, s)) #define TOOLBAR_PADDING 20 static const char * const default_view_values[] = { "icon-view", "list-view", "compact-view", NULL }; static const char * const zoom_values[] = { "smallest", "smaller", "small", "standard", "large", "larger", "largest", NULL }; static const char * const sort_order_values[] = { "name", "size", "type", "detailed_type", "mtime", "atime", "trash-time", NULL }; static const char * const date_format_values[] = { "locale", "iso", "informal", NULL }; static const char * const preview_image_values[] = { "always", "local-only", "never", NULL }; static const char * const preview_folder_values[] = { "always", "local-only", "never", NULL }; static const char * const click_behavior_components[] = { "single_click_radiobutton", "double_click_radiobutton", NULL }; static const char * const click_behavior_values[] = { "single", "double", NULL }; static const char * const executable_text_components[] = { "scripts_execute_radiobutton", "scripts_view_radiobutton", "scripts_confirm_radiobutton", NULL }; static const char * const executable_text_values[] = { "launch", "display", "ask", NULL }; static const char * const size_prefixes_values[] = { "base-10", "base-10-full", "base-2", "base-2-full", NULL }; static const guint64 thumbnail_limit_values[] = { 102400, 512000, 1048576, 3145728, 5242880, 10485760, 104857600, 1073741824, 2147483648U, 4294967295U, 8589934592U, 17179869184U, 34359738368U }; static const char * const icon_captions_components[] = { "captions_0_combobox", "captions_1_combobox", "captions_2_combobox", NULL }; static GtkWidget *preferences_dialog = NULL; static void nemo_file_management_properties_size_group_create (GtkBuilder *builder, char *prefix, int items) { GtkSizeGroup *size_group; int i; char *item_name; GtkWidget *widget; size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); for (i = 0; i < items; i++) { item_name = g_strdup_printf ("%s_%d", prefix, i); widget = GTK_WIDGET (gtk_builder_get_object (builder, item_name)); gtk_size_group_add_widget (size_group, widget); g_free (item_name); } g_object_unref (G_OBJECT (size_group)); } static void columns_changed_callback (NemoColumnChooser *chooser, gpointer callback_data) { char **visible_columns; char **column_order; nemo_column_chooser_get_settings (NEMO_COLUMN_CHOOSER (chooser), &visible_columns, &column_order); g_settings_set_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, (const char * const *)visible_columns); g_settings_set_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER, (const char * const *)column_order); g_strfreev (visible_columns); g_strfreev (column_order); } static void free_column_names_array (GPtrArray *column_names) { g_ptr_array_foreach (column_names, (GFunc) g_free, NULL); g_ptr_array_free (column_names, TRUE); } static void create_icon_caption_combo_box_items (GtkComboBoxText *combo_box, GList *columns) { GList *l; GPtrArray *column_names; column_names = g_ptr_array_new (); /* Translators: this is referred to captions under icons. */ gtk_combo_box_text_append_text (combo_box, _("None")); g_ptr_array_add (column_names, g_strdup ("none")); for (l = columns; l != NULL; l = l->next) { NemoColumn *column; char *name; char *label; column = NEMO_COLUMN (l->data); g_object_get (G_OBJECT (column), "name", &name, "label", &label, NULL); /* Don't show name here, it doesn't make sense */ if (!strcmp (name, "name")) { g_free (name); g_free (label); continue; } gtk_combo_box_text_append_text (combo_box, label); g_ptr_array_add (column_names, name); g_free (label); } g_object_set_data_full (G_OBJECT (combo_box), "column_names", column_names, (GDestroyNotify) free_column_names_array); } static void icon_captions_changed_callback (GtkComboBox *combo_box, gpointer user_data) { GPtrArray *captions; GtkBuilder *builder; guint i; builder = GTK_BUILDER (user_data); captions = g_ptr_array_new (); for (i = 0; icon_captions_components[i] != NULL; i++) { int active; GPtrArray *column_names; char *name; GtkWidget *c_box; c_box = GTK_WIDGET (gtk_builder_get_object (builder, icon_captions_components[i])); active = gtk_combo_box_get_active (GTK_COMBO_BOX (c_box)); column_names = g_object_get_data (G_OBJECT (c_box), "column_names"); name = g_ptr_array_index (column_names, active); g_ptr_array_add (captions, name); } g_ptr_array_add (captions, NULL); g_settings_set_strv (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, (const char **)captions->pdata); g_ptr_array_free (captions, TRUE); } static void update_caption_combo_box (GtkBuilder *builder, const char *combo_box_name, const char *name) { GtkWidget *combo_box; guint i; GPtrArray *column_names; combo_box = GTK_WIDGET (gtk_builder_get_object (builder, combo_box_name)); g_signal_handlers_block_by_func (combo_box, G_CALLBACK (icon_captions_changed_callback), builder); column_names = g_object_get_data (G_OBJECT (combo_box), "column_names"); for (i = 0; i < column_names->len; ++i) { if (!strcmp (name, g_ptr_array_index (column_names, i))) { gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), i); break; } } g_signal_handlers_unblock_by_func (combo_box, G_CALLBACK (icon_captions_changed_callback), builder); } static void update_icon_captions_from_settings (GtkBuilder *builder) { char **captions; int i, j; captions = g_settings_get_strv (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS); if (captions == NULL) return; for (i = 0, j = 0; icon_captions_components[i] != NULL; i++) { char *data; if (captions[j]) { data = captions[j]; ++j; } else { data = (char *)"none"; } update_caption_combo_box (builder, icon_captions_components[i], data); } g_strfreev (captions); } static void nemo_file_management_properties_dialog_setup_icon_caption_page (GtkBuilder *builder) { GList *columns; int i; gboolean writable; writable = g_settings_is_writable (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS); columns = nemo_get_common_columns (); for (i = 0; icon_captions_components[i] != NULL; i++) { GtkWidget *combo_box; combo_box = GTK_WIDGET (gtk_builder_get_object (builder, icon_captions_components[i])); create_icon_caption_combo_box_items (GTK_COMBO_BOX_TEXT (combo_box), columns); gtk_widget_set_sensitive (combo_box, writable); g_signal_connect (combo_box, "changed", G_CALLBACK (icon_captions_changed_callback), builder); } nemo_column_list_free (columns); update_icon_captions_from_settings (builder); } static void nemo_file_management_properties_dialog_setup_plugin_page (GtkBuilder *builder) { GtkWidget *box; box = GTK_WIDGET (gtk_builder_get_object (builder, "plugin_box")); gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (nemo_plugin_manager_new ()), TRUE, TRUE, 0); } static void create_date_format_menu (GtkBuilder *builder) { GtkComboBoxText *combo_box; gchar *date_string; GDateTime *now; combo_box = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, NEMO_FILE_MANAGEMENT_PROPERTIES_DATE_FORMAT_WIDGET)); now = g_date_time_new_now_local (); date_string = g_date_time_format (now, "%c"); gtk_combo_box_text_append_text (combo_box, date_string); g_free (date_string); date_string = g_date_time_format (now, "%Y-%m-%d %H:%M:%S"); gtk_combo_box_text_append_text (combo_box, date_string); g_free (date_string); gtk_combo_box_text_append_text (combo_box, _("Yesterday")); g_date_time_unref (now); } static void set_columns_from_settings (NemoColumnChooser *chooser) { char **visible_columns; char **column_order; visible_columns = g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); column_order = g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); nemo_column_chooser_set_settings (NEMO_COLUMN_CHOOSER (chooser), visible_columns, column_order); g_strfreev (visible_columns); g_strfreev (column_order); } static void use_default_callback (NemoColumnChooser *chooser, gpointer user_data) { g_settings_reset (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); g_settings_reset (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); set_columns_from_settings (chooser); } static void nemo_file_management_properties_dialog_setup_list_column_page (GtkBuilder *builder) { GtkWidget *chooser; GtkWidget *box; chooser = nemo_column_chooser_new (NULL); set_columns_from_settings (NEMO_COLUMN_CHOOSER (chooser)); g_signal_connect (chooser, "changed", G_CALLBACK (columns_changed_callback), chooser); g_signal_connect (chooser, "use_default", G_CALLBACK (use_default_callback), chooser); gtk_widget_show (chooser); box = GTK_WIDGET (gtk_builder_get_object (builder, "list_columns_vbox")); gtk_box_pack_start (GTK_BOX (box), chooser, TRUE, TRUE, 0); } static void bind_builder_bool (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs) { g_settings_bind (settings, prefs, gtk_builder_get_object (builder, widget_name), "active", G_SETTINGS_BIND_DEFAULT); } static void bind_builder_bool_inverted (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs) { g_settings_bind (settings, prefs, gtk_builder_get_object (builder, widget_name), "active", G_SETTINGS_BIND_INVERT_BOOLEAN); } static void bind_builder_string_entry (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs) { g_settings_bind (settings, prefs, gtk_builder_get_object (builder, widget_name), "text", G_SETTINGS_BIND_DEFAULT); } static gboolean enum_get_mapping (GValue *value, GVariant *variant, gpointer user_data) { const char **enum_values = user_data; const char *str; int i; str = g_variant_get_string (variant, NULL); for (i = 0; enum_values[i] != NULL; i++) { if (strcmp (enum_values[i], str) == 0) { g_value_set_int (value, i); return TRUE; } } return FALSE; } static GVariant * enum_set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) { const char **enum_values = user_data; return g_variant_new_string (enum_values[g_value_get_int (value)]); } static void bind_builder_enum (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs, const char **enum_values) { g_settings_bind_with_mapping (settings, prefs, gtk_builder_get_object (builder, widget_name), "active", G_SETTINGS_BIND_DEFAULT, enum_get_mapping, enum_set_mapping, enum_values, NULL); } typedef struct { const guint64 *values; int n_values; } UIntEnumBinding; static gboolean uint_enum_get_mapping (GValue *value, GVariant *variant, gpointer user_data) { UIntEnumBinding *binding = user_data; guint64 v; int i; v = g_variant_get_uint64 (variant); for (i = 0; i < binding->n_values; i++) { if (binding->values[i] >= v) { g_value_set_int (value, i); return TRUE; } } return FALSE; } static GVariant * uint_enum_set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) { UIntEnumBinding *binding = user_data; return g_variant_new_uint64 (binding->values[g_value_get_int (value)]); } static void bind_builder_uint_enum (GtkBuilder *builder, GSettings *settings, const char *widget_name, const char *prefs, const guint64 *values, int n_values) { UIntEnumBinding *binding; binding = g_new (UIntEnumBinding, 1); binding->values = values; binding->n_values = n_values; g_settings_bind_with_mapping (settings, prefs, gtk_builder_get_object (builder, widget_name), "active", G_SETTINGS_BIND_DEFAULT, uint_enum_get_mapping, uint_enum_set_mapping, binding, g_free); } static GVariant * radio_mapping_set (const GValue *gvalue, const GVariantType *expected_type, gpointer user_data) { const gchar *widget_value = user_data; GVariant *retval = NULL; if (g_value_get_boolean (gvalue)) { retval = g_variant_new_string (widget_value); } return retval; } static gboolean radio_mapping_get (GValue *gvalue, GVariant *variant, gpointer user_data) { const gchar *widget_value = user_data; const gchar *value; value = g_variant_get_string (variant, NULL); if (g_strcmp0 (value, widget_value) == 0) { g_value_set_boolean (gvalue, TRUE); } else { g_value_set_boolean (gvalue, FALSE); } return TRUE; } static void bind_builder_radio (GtkBuilder *builder, GSettings *settings, const char **widget_names, const char *prefs, const char **values) { GtkWidget *button; int i; for (i = 0; widget_names[i] != NULL; i++) { button = GTK_WIDGET (gtk_builder_get_object (builder, widget_names[i])); g_settings_bind_with_mapping (settings, prefs, button, "active", G_SETTINGS_BIND_DEFAULT, radio_mapping_get, radio_mapping_set, (gpointer) values[i], NULL); } } static void setup_configurable_menu_items (GtkBuilder *builder) { gint i; for (i = 0; i < CONFIGURABLE_MENU_ITEM_COUNT; i++) { if (CONFIGURABLE_MENU_ITEM_INFO[i].config_widget_name == NULL) { continue; } bind_builder_bool (builder, nemo_menu_config_preferences, CONFIGURABLE_MENU_ITEM_INFO[i].config_widget_name, CONFIGURABLE_MENU_ITEM_INFO[i].settings_key); } } static void setup_tooltip_items (GtkBuilder *builder) { gboolean enabled = FALSE; enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_ICON_VIEW_WIDGET))) || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_DESKTOP_WIDGET))) || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_LIST_VIEW_WIDGET))); gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FILE_TYPE_WIDGET)), enabled); gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_MOD_DATE_WIDGET)), enabled); gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_CREATED_DATE_WIDGET)), enabled); gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_ACCESS_DATE_WIDGET)), enabled); gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FULL_PATH_WIDGET)), enabled); } static void connect_tooltip_items (GtkBuilder *builder) { GtkToggleButton *w; w = GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_ICON_VIEW_WIDGET)); g_signal_connect_swapped (w, "toggled", G_CALLBACK (setup_tooltip_items), builder); w = GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_LIST_VIEW_WIDGET)); g_signal_connect_swapped (w, "toggled", G_CALLBACK (setup_tooltip_items), builder); w = GTK_TOGGLE_BUTTON (W (NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_DESKTOP_WIDGET)); g_signal_connect_swapped (w, "toggled", G_CALLBACK (setup_tooltip_items), builder); } /* When single click radio button is selected, checkbox for quick renames should get unselected and disable to avoid annoying features */ static void setup_quick_renames (GtkBuilder *builder) { gboolean enabled = FALSE; enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W (click_behavior_components[1]))); if(enabled==FALSE){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(W (NEMO_FILE_MANAGEMENT_QUICK_RENAMES_WITH_PAUSE_IN_BETWEEN)), FALSE); } gtk_widget_set_sensitive (GTK_WIDGET (W (NEMO_FILE_MANAGEMENT_QUICK_RENAMES_WITH_PAUSE_IN_BETWEEN)), enabled); } static void connect_quick_renames (GtkBuilder *builder) { GtkRadioButton *w; w=GTK_RADIO_BUTTON(W(click_behavior_components[0])); g_signal_connect_swapped (w, "toggled", G_CALLBACK (setup_quick_renames), builder); w=GTK_RADIO_BUTTON(W(click_behavior_components[1])); g_signal_connect_swapped (w, "toggled", G_CALLBACK (setup_quick_renames), builder); } static void on_dialog_destroy (GtkWidget *widget, gpointer user_data) { GtkBuilder *builder = GTK_BUILDER (user_data); g_object_unref (builder); } static void nemo_file_management_properties_dialog_setup (GtkBuilder *builder, GtkWindow *window, const gchar *initial_page) { GtkWidget *dialog; /* setup UI */ nemo_file_management_properties_size_group_create (builder, (char *)"views_label", 5); nemo_file_management_properties_size_group_create (builder, (char *)"captions_label", 3); nemo_file_management_properties_size_group_create (builder, (char *)"preview_label", 3); create_date_format_menu (builder); /* nemo patch */ bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_PREVIOUS_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_PREVIOUS_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_NEXT_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_NEXT_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_UP_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_UP_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_RELOAD_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_RELOAD_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_EDIT_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_EDIT_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_HOME_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_HOME_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_COMPUTER_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_COMPUTER_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SEARCH_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_SEARCH_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_NEW_FOLDER_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_NEW_FOLDER_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_OPEN_IN_TERMINAL_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_OPEN_IN_TERMINAL_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_ICON_VIEW_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_ICON_VIEW_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_LIST_VIEW_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_LIST_VIEW_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_COMPACT_VIEW_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_COMPACT_VIEW_ICON_TOOLBAR); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SHOW_THUMBNAILS_ICON_TOOLBAR_WIDGET, NEMO_PREFERENCES_SHOW_SHOW_THUMBNAILS_TOOLBAR); /* setup preferences */ bind_builder_bool (builder, nemo_icon_view_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_LABELS_BESIDE_ICONS_WIDGET, NEMO_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS); bind_builder_bool (builder, nemo_compact_view_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_ALL_COLUMNS_SAME_WIDTH, NEMO_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_FOLDERS_FIRST_WIDGET, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST); bind_builder_bool(builder, nemo_preferences, NEMO_FILE_MANAGEMENT_QUICK_RENAMES_WITH_PAUSE_IN_BETWEEN, NEMO_PREFERENCES_CLICK_TO_RENAME); bind_builder_bool_inverted (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_ALWAYS_USE_BROWSER_WIDGET, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_CONFIRM_MOVE_WIDGET, NEMO_PREFERENCES_CONFIRM_MOVE_TO_TRASH); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_CONFIRM_WIDGET, NEMO_PREFERENCES_CONFIRM_TRASH); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TRASH_DELETE_WIDGET, NEMO_PREFERENCES_ENABLE_DELETE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SWAP_TRASH_DELETE, NEMO_PREFERENCES_SWAP_TRASH_DELETE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_FULL_PATH_IN_TITLE_BARS_WIDGET, NEMO_PREFERENCES_SHOW_FULL_PATH_TITLES); bind_builder_bool (builder, nemo_tree_sidebar_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TREE_VIEW_FOLDERS_WIDGET, NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_INHERIT_VIEW_WIDGET, NEMO_PREFERENCES_INHERIT_FOLDER_VIEWER); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_REVERSE_SORT_WIDGET, NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_DEFAULT_VIEW_WIDGET, NEMO_PREFERENCES_DEFAULT_FOLDER_VIEWER, (const char **) default_view_values); bind_builder_enum (builder, nemo_icon_view_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_ICON_VIEW_ZOOM_WIDGET, NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, (const char **) zoom_values); bind_builder_enum (builder, nemo_compact_view_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_COMPACT_VIEW_ZOOM_WIDGET, NEMO_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL, (const char **) zoom_values); bind_builder_enum (builder, nemo_list_view_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_LIST_VIEW_ZOOM_WIDGET, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL, (const char **) zoom_values); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SORT_ORDER_WIDGET, NEMO_PREFERENCES_DEFAULT_SORT_ORDER, (const char **) sort_order_values); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_PREVIEW_IMAGE_WIDGET, NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, (const char **) preview_image_values); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_INHERIT_SHOW_THUMBNAILS_WIDGET, NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_PREVIEW_FOLDER_WIDGET, NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS, (const char **) preview_folder_values); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SIZE_PREFIXES_WIDGET, NEMO_PREFERENCES_SIZE_PREFIXES, (const char **) size_prefixes_values); bind_builder_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_DATE_FORMAT_WIDGET, NEMO_PREFERENCES_DATE_FORMAT, (const char **) date_format_values); bind_builder_radio (builder, nemo_preferences, (const char **) click_behavior_components, NEMO_PREFERENCES_CLICK_POLICY, (const char **) click_behavior_values); bind_builder_radio (builder, nemo_preferences, (const char **) executable_text_components, NEMO_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION, (const char **) executable_text_values); bind_builder_uint_enum (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_THUMBNAIL_LIMIT_WIDGET, NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT, thumbnail_limit_values, G_N_ELEMENTS (thumbnail_limit_values)); bind_builder_bool (builder, gnome_media_handling_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_AUTOMOUNT_MEDIA_WIDGET, GNOME_DESKTOP_MEDIA_HANDLING_AUTOMOUNT); bind_builder_bool (builder, gnome_media_handling_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_AUTOOPEN_MEDIA_WIDGET, GNOME_DESKTOP_MEDIA_HANDLING_AUTOMOUNT_OPEN); bind_builder_bool_inverted (builder, gnome_media_handling_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_AUTORUN_MEDIA_WIDGET, GNOME_DESKTOP_MEDIA_HANDLING_AUTORUN); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_CLOSE_DEVICE_VIEW_ON_EJECT_WIDGET, NEMO_PREFERENCES_CLOSE_DEVICE_VIEW_ON_EJECT); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_ADVANCED_PERMISSIONS_WIDGET, NEMO_PREFERENCES_SHOW_ADVANCED_PERMISSIONS); bind_builder_string_entry (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_BULK_RENAME_WIDGET, NEMO_PREFERENCES_BULK_RENAME_TOOL); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_START_WITH_DUAL_PANE_WIDGET, NEMO_PREFERENCES_START_WITH_DUAL_PANE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET, NEMO_PREFERENCES_IGNORE_VIEW_METADATA); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_BOOKMARKS_IN_TO_MENUS_WIDGET, NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_PLACES_IN_TO_MENUS_WIDGET, NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_DESKTOP_WIDGET, NEMO_PREFERENCES_TOOLTIPS_DESKTOP); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_ICON_VIEW_WIDGET, NEMO_PREFERENCES_TOOLTIPS_ICON_VIEW); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIPS_ON_LIST_VIEW_WIDGET, NEMO_PREFERENCES_TOOLTIPS_LIST_VIEW); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FILE_TYPE_WIDGET, NEMO_PREFERENCES_TOOLTIP_FILE_TYPE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_MOD_DATE_WIDGET, NEMO_PREFERENCES_TOOLTIP_MOD_DATE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_ACCESS_DATE_WIDGET, NEMO_PREFERENCES_TOOLTIP_ACCESS_DATE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_CREATED_DATE_WIDGET, NEMO_PREFERENCES_TOOLTIP_CREATED_DATE); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_TOOLTIP_FULL_PATH_WIDGET, NEMO_PREFERENCES_TOOLTIP_FULL_PATH); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_NEMO_PREFERENCES_SKIP_FILE_OP_QUEUE_WIDGET, NEMO_PREFERENCES_NEVER_QUEUE_FILE_OPS); bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_NEMO_PREFERENCES_CLICK_DBL_PARENT_FOLDER_WIDGET, NEMO_PREFERENCES_CLICK_DOUBLE_PARENT_FOLDER); setup_tooltip_items (builder); connect_tooltip_items (builder); /* to make checkbox for quickrenames get disabled when single click is selected */ setup_quick_renames(builder); connect_quick_renames(builder); nemo_file_management_properties_dialog_setup_icon_caption_page (builder); nemo_file_management_properties_dialog_setup_list_column_page (builder); nemo_file_management_properties_dialog_setup_plugin_page (builder); setup_configurable_menu_items (builder); dialog = GTK_WIDGET (gtk_builder_get_object (builder, "file_management_dialog")); g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL); g_signal_connect (dialog, "destroy", G_CALLBACK (on_dialog_destroy), builder); gtk_window_set_icon_name (GTK_WINDOW (dialog), "folder"); if (window) { gtk_window_set_transient_for (GTK_WINDOW (dialog), window); } preferences_dialog = dialog; g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &preferences_dialog); if (initial_page != NULL) { GtkStack *stack; stack = GTK_STACK (gtk_builder_get_object (builder, "page_stack")); gtk_stack_set_visible_child_name (stack, initial_page); } gtk_widget_show (dialog); } void nemo_file_management_properties_dialog_show (GtkWindow *window, const gchar *initial_page) { GtkBuilder *builder; if (preferences_dialog != NULL) { gtk_window_present (GTK_WINDOW (preferences_dialog)); return; } builder = gtk_builder_new (); gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); gtk_builder_add_from_resource (builder, "/org/nemo/nemo-file-management-properties.glade", NULL); nemo_file_management_properties_dialog_setup (builder, window, initial_page); } nemo-4.4.2/src/nemo-file-management-properties.h000066400000000000000000000025051357442400300216020ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-file-management-properties.h - Function to show the nemo preference dialog. Copyright (C) 2002 Jan Arne Petersen The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Jan Arne Petersen */ #ifndef NEMO_FILE_MANAGEMENT_PROPERTIES_H #define NEMO_FILE_MANAGEMENT_PROPERTIES_H #include #include G_BEGIN_DECLS void nemo_file_management_properties_dialog_show (GtkWindow *window, const gchar *initial_page); G_END_DECLS #endif /* NEMO_FILE_MANAGEMENT_PROPERTIES_H */ nemo-4.4.2/src/nemo-floating-bar.c000066400000000000000000000226621357442400300167250ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Floating status bar. * * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi * */ #include #include "nemo-floating-bar.h" struct _NemoFloatingBarDetails { gchar *label; GtkWidget *label_widget; GtkWidget *spinner; gboolean show_spinner; gboolean is_interactive; }; enum { PROP_LABEL = 1, PROP_SHOW_SPINNER, NUM_PROPERTIES }; enum { ACTION, NUM_SIGNALS }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; static guint signals[NUM_SIGNALS] = { 0, }; G_DEFINE_TYPE (NemoFloatingBar, nemo_floating_bar, GTK_TYPE_BOX); static void action_button_clicked_cb (GtkButton *button, NemoFloatingBar *self) { gint action_id; action_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "action-id")); g_signal_emit (self, signals[ACTION], 0, action_id); } static void nemo_floating_bar_finalize (GObject *obj) { NemoFloatingBar *self = NEMO_FLOATING_BAR (obj); g_free (self->priv->label); G_OBJECT_CLASS (nemo_floating_bar_parent_class)->finalize (obj); } static void nemo_floating_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoFloatingBar *self = NEMO_FLOATING_BAR (object); switch (property_id) { case PROP_LABEL: g_value_set_string (value, self->priv->label); break; case PROP_SHOW_SPINNER: g_value_set_boolean (value, self->priv->show_spinner); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_floating_bar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoFloatingBar *self = NEMO_FLOATING_BAR (object); switch (property_id) { case PROP_LABEL: nemo_floating_bar_set_label (self, g_value_get_string (value)); break; case PROP_SHOW_SPINNER: nemo_floating_bar_set_show_spinner (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void update_label (NemoFloatingBar *self) { gtk_label_set_text (GTK_LABEL (self->priv->label_widget), self->priv->label); } static gboolean overlay_enter_notify_cb (GtkWidget *parent, GdkEventCrossing *event, gpointer user_data) { GtkWidget *widget = user_data; if (event->window != gtk_widget_get_window (widget)) { return FALSE; } if (NEMO_FLOATING_BAR (widget)->priv->is_interactive) { return FALSE; } if (gtk_widget_get_halign (widget) == GTK_ALIGN_START) { gtk_widget_set_halign (widget, GTK_ALIGN_END); } else { gtk_widget_set_halign (widget, GTK_ALIGN_START); } gtk_widget_queue_resize (widget); return FALSE; } static void nemo_floating_bar_parent_set (GtkWidget *widget, GtkWidget *old_parent) { GtkWidget *parent; parent = gtk_widget_get_parent (widget); if (old_parent != NULL) { g_signal_handlers_disconnect_by_func (old_parent, overlay_enter_notify_cb, widget); } if (parent != NULL) { g_signal_connect (parent, "enter-notify-event", G_CALLBACK (overlay_enter_notify_cb), widget); } } static void nemo_floating_bar_show (GtkWidget *widget) { NemoFloatingBar *self = NEMO_FLOATING_BAR (widget); GTK_WIDGET_CLASS (nemo_floating_bar_parent_class)->show (widget); if (self->priv->show_spinner) { gtk_spinner_start (GTK_SPINNER (self->priv->spinner)); } } static void nemo_floating_bar_hide (GtkWidget *widget) { NemoFloatingBar *self = NEMO_FLOATING_BAR (widget); GTK_WIDGET_CLASS (nemo_floating_bar_parent_class)->hide (widget); gtk_spinner_stop (GTK_SPINNER (self->priv->spinner)); } static gboolean nemo_floating_bar_draw (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); gtk_style_context_set_state (context, gtk_widget_get_state_flags (widget)); gtk_render_background (context, cr, 0, 0, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); gtk_render_frame (context, cr, 0, 0, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); gtk_style_context_restore (context); return GTK_WIDGET_CLASS (nemo_floating_bar_parent_class)->draw (widget, cr);; } static void nemo_floating_bar_constructed (GObject *obj) { NemoFloatingBar *self = NEMO_FLOATING_BAR (obj); GtkWidget *w, *box; G_OBJECT_CLASS (nemo_floating_bar_parent_class)->constructed (obj); box = GTK_WIDGET (obj); w = gtk_spinner_new (); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0); gtk_widget_set_visible (w, self->priv->show_spinner); self->priv->spinner = w; gtk_widget_set_size_request (w, 16, 16); gtk_widget_set_margin_left (w, 8); w = gtk_label_new (NULL); gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_END); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0); g_object_set (w, "margin-top", 2, "margin-bottom", 2, "margin-left", 12, "margin-right", 12, NULL); self->priv->label_widget = w; gtk_widget_show (w); } static void nemo_floating_bar_init (NemoFloatingBar *self) { GtkStyleContext *context; self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_FLOATING_BAR, NemoFloatingBarDetails); context = gtk_widget_get_style_context (GTK_WIDGET (self)); gtk_style_context_add_class (context, "floating-bar"); } static void nemo_floating_bar_class_init (NemoFloatingBarClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); oclass->constructed = nemo_floating_bar_constructed; oclass->set_property = nemo_floating_bar_set_property; oclass->get_property = nemo_floating_bar_get_property; oclass->finalize = nemo_floating_bar_finalize; wclass->draw = nemo_floating_bar_draw; wclass->show = nemo_floating_bar_show; wclass->hide = nemo_floating_bar_hide; wclass->parent_set = nemo_floating_bar_parent_set; properties[PROP_LABEL] = g_param_spec_string ("label", "Bar's label", "Label displayed by the bar", NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); properties[PROP_SHOW_SPINNER] = g_param_spec_boolean ("show-spinner", "Show spinner", "Whether a spinner should be shown in the floating bar", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); signals[ACTION] = g_signal_new ("action", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_type_class_add_private (klass, sizeof (NemoFloatingBarDetails)); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } void nemo_floating_bar_set_label (NemoFloatingBar *self, const gchar *label) { if (g_strcmp0 (self->priv->label, label) != 0) { g_free (self->priv->label); self->priv->label = g_strdup (label); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]); update_label (self); } } void nemo_floating_bar_set_show_spinner (NemoFloatingBar *self, gboolean show_spinner) { if (self->priv->show_spinner != show_spinner) { self->priv->show_spinner = show_spinner; gtk_widget_set_visible (self->priv->spinner, show_spinner); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_SPINNER]); } } GtkWidget * nemo_floating_bar_new (const gchar *label, gboolean show_spinner) { return g_object_new (NEMO_TYPE_FLOATING_BAR, "label", label, "show-spinner", show_spinner, "orientation", GTK_ORIENTATION_HORIZONTAL, "spacing", 8, NULL); } void nemo_floating_bar_add_action (NemoFloatingBar *self, const gchar *stock_id, gint action_id) { GtkWidget *w, *button; w = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU); gtk_widget_show (w); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), w); gtk_box_pack_end (GTK_BOX (self), button, FALSE, FALSE, 0); gtk_widget_show (button); g_object_set_data (G_OBJECT (button), "action-id", GINT_TO_POINTER (action_id)); g_signal_connect (button, "clicked", G_CALLBACK (action_button_clicked_cb), self); self->priv->is_interactive = TRUE; } void nemo_floating_bar_cleanup_actions (NemoFloatingBar *self) { GtkWidget *widget; GList *children, *l; gpointer data; children = gtk_container_get_children (GTK_CONTAINER (self)); l = children; while (l != NULL) { widget = l->data; data = g_object_get_data (G_OBJECT (widget), "action-id"); l = l->next; if (data != NULL) { /* destroy this */ gtk_widget_destroy (widget); } } g_list_free (children); self->priv->is_interactive = FALSE; } nemo-4.4.2/src/nemo-floating-bar.h000066400000000000000000000051201357442400300167200ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Floating status bar. * * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi * */ #ifndef __NEMO_FLOATING_BAR_H__ #define __NEMO_FLOATING_BAR_H__ #include #define NEMO_FLOATING_BAR_ACTION_ID_STOP 1 #define NEMO_TYPE_FLOATING_BAR nemo_floating_bar_get_type() #define NEMO_FLOATING_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_FLOATING_BAR, NemoFloatingBar)) #define NEMO_FLOATING_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_FLOATING_BAR, NemoFloatingBarClass)) #define NEMO_IS_FLOATING_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_FLOATING_BAR)) #define NEMO_IS_FLOATING_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_FLOATING_BAR)) #define NEMO_FLOATING_BAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_FLOATING_BAR, NemoFloatingBarClass)) typedef struct _NemoFloatingBar NemoFloatingBar; typedef struct _NemoFloatingBarClass NemoFloatingBarClass; typedef struct _NemoFloatingBarDetails NemoFloatingBarDetails; struct _NemoFloatingBar { GtkBox parent; NemoFloatingBarDetails *priv; }; struct _NemoFloatingBarClass { GtkBoxClass parent_class; }; /* GObject */ GType nemo_floating_bar_get_type (void); GtkWidget * nemo_floating_bar_new (const gchar *label, gboolean show_spinner); void nemo_floating_bar_set_label (NemoFloatingBar *self, const gchar *label); void nemo_floating_bar_set_show_spinner (NemoFloatingBar *self, gboolean show_spinner); void nemo_floating_bar_add_action (NemoFloatingBar *self, const gchar *stock_id, gint action_id); void nemo_floating_bar_cleanup_actions (NemoFloatingBar *self); #endif /* __NEMO_FLOATING_BAR_H__ */ nemo-4.4.2/src/nemo-freedesktop-dbus.c000066400000000000000000000144441357442400300176250ustar00rootroot00000000000000/* * nemo-freedesktop-dbus: Implementation for the org.freedesktop DBus file-management interfaces * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Akshay Gupta * Federico Mena Quintero */ #include #include "nemo-application.h" #include "nemo-freedesktop-dbus.h" #include "nemo-freedesktop-generated.h" /* We share the same debug domain as nemo-dbus-manager */ #define DEBUG_FLAG NEMO_DEBUG_DBUS #include #include "nemo-properties-window.h" #include struct _NemoFreedesktopDBus { GObject parent; /* Id from g_dbus_own_name() */ guint owner_id; /* DBus paraphernalia */ GDBusObjectManagerServer *object_manager; /* Our DBus implementation skeleton */ NemoFreedesktopFileManager1 *skeleton; }; struct _NemoFreedesktopDBusClass { GObjectClass parent_class; }; G_DEFINE_TYPE (NemoFreedesktopDBus, nemo_freedesktop_dbus, G_TYPE_OBJECT); static gboolean skeleton_handle_show_items_cb (NemoFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, const gchar *const *uris, const gchar *startup_id, gpointer data) { NemoApplication *application; int i; application = NEMO_APPLICATION (g_application_get_default ()); for (i = 0; uris[i] != NULL; i++) { GFile *file; GFile *parent; file = g_file_new_for_uri (uris[i]); parent = g_file_get_parent (file); if (parent != NULL) { nemo_application_open_location (application, parent, file, startup_id, FALSE); g_object_unref (parent); } else { nemo_application_open_location (application, file, NULL, startup_id, FALSE); } g_object_unref (file); } nemo_freedesktop_file_manager1_complete_show_items (object, invocation); return TRUE; } static gboolean skeleton_handle_show_folders_cb (NemoFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, const gchar *const *uris, const gchar *startup_id, gpointer data) { NemoApplication *application; int i; application = NEMO_APPLICATION (g_application_get_default ()); for (i = 0; uris[i] != NULL; i++) { GFile *file; file = g_file_new_for_uri (uris[i]); nemo_application_open_location (application, file, NULL, startup_id, FALSE); g_object_unref (file); } nemo_freedesktop_file_manager1_complete_show_folders (object, invocation); return TRUE; } static gboolean skeleton_handle_show_item_properties_cb (NemoFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, const gchar *const *uris, const gchar *startup_id, gpointer data) { GList *files; int i; files = NULL; for (i = 0; uris[i] != NULL; i++) { files = g_list_prepend (files, nemo_file_get_by_uri (uris[i])); } files = g_list_reverse (files); nemo_properties_window_present (files, NULL, startup_id); nemo_file_list_free (files); nemo_freedesktop_file_manager1_complete_show_item_properties (object, invocation); return TRUE; } static void bus_acquired_cb (GDBusConnection *conn, const gchar *name, gpointer user_data) { NemoFreedesktopDBus *fdb = user_data; DEBUG ("Bus acquired at %s", name); fdb->object_manager = g_dbus_object_manager_server_new ("/org/freedesktop/FileManager1"); fdb->skeleton = nemo_freedesktop_file_manager1_skeleton_new (); g_signal_connect (fdb->skeleton, "handle-show-items", G_CALLBACK (skeleton_handle_show_items_cb), fdb); g_signal_connect (fdb->skeleton, "handle-show-folders", G_CALLBACK (skeleton_handle_show_folders_cb), fdb); g_signal_connect (fdb->skeleton, "handle-show-item-properties", G_CALLBACK (skeleton_handle_show_item_properties_cb), fdb); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (fdb->skeleton), conn, "/org/freedesktop/FileManager1", NULL); g_dbus_object_manager_server_set_connection (fdb->object_manager, conn); } static void name_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { DEBUG ("Acquired the name %s on the session message bus\n", name); } static void name_lost_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { DEBUG ("Lost (or failed to acquire) the name %s on the session message bus\n", name); } static void nemo_freedesktop_dbus_dispose (GObject *object) { NemoFreedesktopDBus *fdb = (NemoFreedesktopDBus *) object; if (fdb->owner_id != 0) { g_bus_unown_name (fdb->owner_id); fdb->owner_id = 0; } if (fdb->skeleton != NULL) { g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (fdb->skeleton)); g_object_unref (fdb->skeleton); fdb->skeleton = NULL; } g_clear_object (&fdb->object_manager); G_OBJECT_CLASS (nemo_freedesktop_dbus_parent_class)->dispose (object); } static void nemo_freedesktop_dbus_class_init (NemoFreedesktopDBusClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = nemo_freedesktop_dbus_dispose; } static void nemo_freedesktop_dbus_init (NemoFreedesktopDBus *fdb) { fdb->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.freedesktop.FileManager1", G_BUS_NAME_OWNER_FLAGS_NONE, bus_acquired_cb, name_acquired_cb, name_lost_cb, fdb, NULL); } void nemo_freedesktop_dbus_set_open_locations (NemoFreedesktopDBus *fdb, const gchar **locations) { g_return_if_fail (NEMO_IS_FREEDESKTOP_DBUS (fdb)); nemo_freedesktop_file_manager1_set_open_locations (fdb->skeleton, locations); } /* Tries to own the org.freedesktop.FileManager1 service name */ NemoFreedesktopDBus * nemo_freedesktop_dbus_new (void) { return g_object_new (nemo_freedesktop_dbus_get_type (), NULL); } nemo-4.4.2/src/nemo-freedesktop-dbus.h000066400000000000000000000040201357442400300176170ustar00rootroot00000000000000/* * nemo-freedesktop-dbus: Implementation for the org.freedesktop DBus file-management interfaces * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Akshay Gupta * Federico Mena Quintero */ #ifndef __NEMO_FREEDESKTOP_DBUS_H__ #define __NEMO_FREEDESKTOP_DBUS_H__ #include #define NEMO_TYPE_FREEDESKTOP_DBUS nemo_freedesktop_dbus_get_type() #define NEMO_FREEDESKTOP_DBUS(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_FREEDESKTOP_DBUS, NemoFreedesktopDBus)) #define NEMO_FREEDESKTOP_DBUS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_FREEDESKTOP_DBUS, NemoFreedesktopDBusClass)) #define NEMO_IS_FREEDESKTOP_DBUS(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_FREEDESKTOP_DBUS)) #define NEMO_IS_FREEDESKTOP_DBUS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_FREEDESKTOP_DBUS)) #define NEMO_FREEDESKTOP_DBUS_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_FREEDESKTOP_DBUS, NemoFreedesktopDBusClass)) typedef struct _NemoFreedesktopDBus NemoFreedesktopDBus; typedef struct _NemoFreedesktopDBusClass NemoFreedesktopDBusClass; GType nemo_freedesktop_dbus_get_type (void); NemoFreedesktopDBus * nemo_freedesktop_dbus_new (void); void nemo_freedesktop_dbus_set_open_locations (NemoFreedesktopDBus *fdb, const gchar **locations); #endif /* __NEMO_FREEDESKTOP_DBUS_H__ */ nemo-4.4.2/src/nemo-icon-view-container.c000066400000000000000000002140301357442400300202300ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* fm-icon-container.h - the container widget for file manager icons Copyright (C) 2002 Sun Microsystems, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Michael Meeks */ #include #include "nemo-icon-view-container.h" #include #include #include #include #include #include #include "nemo-icon-private.h" #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_ICON_CONTAINER #include "nemo-debug.h" /* Maximum size (pixels) allowed for icons at the standard zoom level. */ #define MINIMUM_IMAGE_SIZE 24 #define MAXIMUM_IMAGE_SIZE 96 /* If icon size is bigger than this, request large embedded text. * Its selected so that the non-large text should fit in "normal" icon sizes */ #define ICON_SIZE_FOR_LARGE_EMBEDDED_TEXT 55 static void get_max_icon_dimensions (GList *icon_start, GList *icon_end, double *max_icon_width, double *max_icon_height, double *max_text_width, double *max_text_height, double *max_bounds_height); static void find_empty_location (NemoIconContainer *container, NemoPlacementGrid *grid, NemoIcon *icon, int start_x, int start_y, int *x, int *y); G_DEFINE_TYPE (NemoIconViewContainer, nemo_icon_view_container, NEMO_TYPE_ICON_CONTAINER); static GQuark attribute_none_q; static GQuark *caption_attributes = NULL; static NemoIconView * get_icon_view (NemoIconContainer *container) { /* Type unsafe comparison for performance */ return ((NemoIconViewContainer *)container)->view; } static NemoIconInfo * nemo_icon_view_container_get_icon_images (NemoIconContainer *container, NemoIconData *data, int size, gboolean for_drag_accept, gboolean *has_window_open) { NemoIconView *icon_view; NemoFile *file; NemoFileIconFlags flags; NemoIconInfo *icon_info; GdkPixbuf *pixbuf; GIcon *emblemed_icon; GEmblem *emblem; GList *emblem_icons, *l; gint scale; file = (NemoFile *) data; g_assert (NEMO_IS_FILE (file)); icon_view = get_icon_view (container); g_return_val_if_fail (icon_view != NULL, NULL); *has_window_open = nemo_file_has_open_window (file); flags = NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM | NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS | NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE; if (for_drag_accept) { flags |= NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT; } emblem_icons = nemo_file_get_emblem_icons (file, nemo_view_get_directory_as_file (NEMO_VIEW (icon_view))); scale = gtk_widget_get_scale_factor (GTK_WIDGET (icon_view)); icon_info = nemo_file_get_icon (file, size, 0, scale, flags); /* apply emblems */ if (emblem_icons != NULL) { gint w, h, s; gboolean bad_ratio; l = emblem_icons; pixbuf = nemo_icon_info_get_pixbuf (icon_info); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); s = MAX (w, h); if (s < size) size = s; bad_ratio = (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > w || (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > h; if (bad_ratio) goto skip_emblem; /* Would prefer to not use goto, but * I don't want to do these checks on * non-emblemed icons (the majority) * as it would be too costly */ emblem = g_emblem_new (l->data); emblemed_icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem); g_object_unref (emblem); for (l = l->next; l != NULL; l = l->next) { emblem = g_emblem_new (l->data); g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (emblemed_icon), emblem); g_object_unref (emblem); } nemo_icon_info_clear (&icon_info); icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); g_object_unref (emblemed_icon); skip_emblem: g_object_unref (pixbuf); } if (emblem_icons != NULL) { g_list_free_full (emblem_icons, g_object_unref); } return icon_info; } static char * nemo_icon_view_container_get_icon_description (NemoIconContainer *container, NemoIconData *data) { NemoFile *file; char *mime_type; const char *description; file = NEMO_FILE (data); g_assert (NEMO_IS_FILE (file)); if (NEMO_IS_DESKTOP_ICON_FILE (file)) { return NULL; } mime_type = nemo_file_get_mime_type (file); description = g_content_type_get_description (mime_type); g_free (mime_type); return g_strdup (description); } static void nemo_icon_view_container_prioritize_thumbnailing (NemoIconContainer *container, NemoIconData *data) { NemoFile *file; char *uri; file = (NemoFile *) data; g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_thumbnailing (file)) { uri = nemo_file_get_uri (file); nemo_thumbnail_prioritize (uri); g_free (uri); } } static void update_auto_strv_as_quarks (GSettings *settings, const gchar *key, gpointer user_data) { GQuark **storage = user_data; int i = 0; char **value; value = g_settings_get_strv (settings, key); g_free (*storage); *storage = g_new (GQuark, g_strv_length (value) + 1); for (i = 0; value[i] != NULL; ++i) { (*storage)[i] = g_quark_from_string (value[i]); } (*storage)[i] = 0; g_strfreev (value); } /* * Get the preference for which caption text should appear * beneath icons. */ static GQuark * nemo_icon_view_container_get_icon_text_attributes_from_preferences (void) { if (caption_attributes == NULL) { update_auto_strv_as_quarks (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, &caption_attributes); } /* We don't need to sanity check the attributes list even though it came * from preferences. * * There are 2 ways that the values in the list could be bad. * * 1) The user picks "bad" values. "bad" values are those that result in * there being duplicate attributes in the list. * * 2) Value stored in GConf are tampered with. Its possible physically do * this by pulling the rug underneath GConf and manually editing its * config files. Its also possible to use a third party GConf key * editor and store garbage for the keys in question. * * Thankfully, the Nemo preferences machinery deals with both of * these cases. * * In the first case, the preferences dialog widgetry prevents * duplicate attributes by making "bad" choices insensitive. * * In the second case, the preferences getter (and also the auto storage) for * string_array values are always valid members of the enumeration associated * with the preference. * * So, no more error checking on attributes is needed here and we can return * a the auto stored value. */ return caption_attributes; } static int quarkv_length (GQuark *attributes) { int i; i = 0; while (attributes[i] != 0) { i++; } return i; } /** * nemo_icon_view_get_icon_text_attribute_names: * * Get a list representing which text attributes should be displayed * beneath an icon. The result is dependent on zoom level and possibly * user configuration. Don't free the result. * @view: NemoIconView to query. * **/ static GQuark * nemo_icon_view_container_get_icon_text_attribute_names (NemoIconContainer *container, int *len) { GQuark *attributes; int piece_count; const int pieces_by_level[] = { 0, /* NEMO_ZOOM_LEVEL_SMALLEST */ 0, /* NEMO_ZOOM_LEVEL_SMALLER */ 0, /* NEMO_ZOOM_LEVEL_SMALL */ 1, /* NEMO_ZOOM_LEVEL_STANDARD */ 2, /* NEMO_ZOOM_LEVEL_LARGE */ 2, /* NEMO_ZOOM_LEVEL_LARGER */ 3 /* NEMO_ZOOM_LEVEL_LARGEST */ }; piece_count = pieces_by_level[nemo_icon_container_get_zoom_level (container)]; attributes = nemo_icon_view_container_get_icon_text_attributes_from_preferences (); *len = MIN (piece_count, quarkv_length (attributes)); return attributes; } /* This callback returns the text, both the editable part, and the * part below that is not editable. */ static void nemo_icon_view_container_get_icon_text (NemoIconContainer *container, NemoIconData *data, char **editable_text, char **additional_text, gboolean *pinned, gboolean include_invisible) { GQuark *attributes; char *text_array[4]; int i, j, num_attributes; NemoIconView *icon_view; NemoFile *file; gboolean use_additional; file = NEMO_FILE (data); g_assert (NEMO_IS_FILE (file)); g_assert (editable_text != NULL); icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); use_additional = (additional_text != NULL); /* In the smallest zoom mode, no text is drawn. */ if (nemo_icon_container_get_zoom_level (container) == NEMO_ZOOM_LEVEL_SMALLEST && !include_invisible) { *editable_text = NULL; if (pinned) { *pinned = FALSE; } } else { /* Strip the suffix for nemo object xml files. */ *editable_text = nemo_file_get_display_name (file); if (pinned) { *pinned = nemo_file_get_pinning (file); } } if (!use_additional) { return; } if (nemo_icon_view_is_compact (icon_view)) { *additional_text = NULL; return; } if (NEMO_IS_DESKTOP_ICON_FILE (file) || nemo_file_is_nemo_link (file)) { /* Don't show the normal extra information for desktop icons, * or desktop files, it doesn't make sense. */ *additional_text = NULL; return; } /* Find out what attributes go below each icon. */ attributes = nemo_icon_view_container_get_icon_text_attribute_names (container, &num_attributes); /* Get the attributes. */ j = 0; for (i = 0; i < num_attributes; ++i) { if (attributes[i] == attribute_none_q) { continue; } text_array[j++] = nemo_file_get_string_attribute_with_default_q (file, attributes[i]); } text_array[j] = NULL; /* Return them. */ if (j == 0) { *additional_text = NULL; } else if (j == 1) { /* Only one item, avoid the strdup + free */ *additional_text = text_array[0]; } else { *additional_text = g_strjoinv ("\n", text_array); for (i = 0; i < j; i++) { g_free (text_array[i]); } } } /* Sort as follows: * 0) computer link * 1) home link * 2) network link * 3) mount links * 4) trash link * 5) other */ typedef enum { SORT_COMPUTER_LINK, SORT_HOME_LINK, SORT_NETWORK_LINK, SORT_MOUNT_LINK, SORT_TRASH_LINK, SORT_OTHER } SortCategory; static SortCategory get_sort_category (NemoFile *file) { NemoDesktopLink *link; SortCategory category; category = SORT_OTHER; if (NEMO_IS_DESKTOP_ICON_FILE (file)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); if (link != NULL) { switch (nemo_desktop_link_get_link_type (link)) { case NEMO_DESKTOP_LINK_COMPUTER: category = SORT_COMPUTER_LINK; break; case NEMO_DESKTOP_LINK_HOME: category = SORT_HOME_LINK; break; case NEMO_DESKTOP_LINK_MOUNT: category = SORT_MOUNT_LINK; break; case NEMO_DESKTOP_LINK_TRASH: category = SORT_TRASH_LINK; break; case NEMO_DESKTOP_LINK_NETWORK: category = SORT_NETWORK_LINK; break; default: category = SORT_OTHER; break; } g_object_unref (link); } } return category; } static int fm_desktop_icon_container_icons_compare (NemoIconContainer *container, NemoIconData *data_a, NemoIconData *data_b) { NemoFile *file_a; NemoFile *file_b; NemoView *directory_view; SortCategory category_a, category_b; file_a = (NemoFile *) data_a; file_b = (NemoFile *) data_b; directory_view = NEMO_VIEW (NEMO_ICON_VIEW_CONTAINER (container)->view); g_return_val_if_fail (directory_view != NULL, 0); category_a = get_sort_category (file_a); category_b = get_sort_category (file_b); if (category_a == category_b) { return nemo_file_compare_for_sort (file_a, file_b, NEMO_FILE_SORT_BY_DISPLAY_NAME, nemo_view_should_sort_directories_first (directory_view), FALSE); } if (category_a < category_b) { return -1; } else { return +1; } } static int nemo_icon_view_container_compare_icons (NemoIconContainer *container, NemoIconData *icon_a, NemoIconData *icon_b) { NemoIconView *icon_view; icon_view = get_icon_view (container); g_return_val_if_fail (icon_view != NULL, 0); if (NEMO_ICON_VIEW_CONTAINER (container)->sort_for_desktop) { return fm_desktop_icon_container_icons_compare (container, icon_a, icon_b); } /* Type unsafe comparisons for performance */ return nemo_icon_view_compare_files (icon_view, (NemoFile *)icon_a, (NemoFile *)icon_b); } static void nemo_icon_view_container_freeze_updates (NemoIconContainer *container) { NemoIconView *icon_view; icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); nemo_view_freeze_updates (NEMO_VIEW (icon_view)); } static void nemo_icon_view_container_unfreeze_updates (NemoIconContainer *container) { NemoIconView *icon_view; icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); nemo_view_unfreeze_updates (NEMO_VIEW (icon_view)); } inline static void nemo_icon_view_container_icon_get_bounding_box (NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage) { double x1, y1, x2, y2; if (usage == BOUNDS_USAGE_FOR_DISPLAY) { eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item), &x1, &y1, &x2, &y2); } else if (usage == BOUNDS_USAGE_FOR_LAYOUT) { nemo_icon_canvas_item_get_bounds_for_layout (icon->item, &x1, &y1, &x2, &y2); } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { nemo_icon_canvas_item_get_bounds_for_entire_item (icon->item, &x1, &y1, &x2, &y2); } else { g_assert_not_reached (); } if (x1_return != NULL) { *x1_return = x1; } if (y1_return != NULL) { *y1_return = y1; } if (x2_return != NULL) { *x2_return = x2; } if (y2_return != NULL) { *y2_return = y2; } } static gboolean get_stored_icon_position (NemoIconContainer *container, NemoIconData *data, NemoIconPosition *position) { GdkPoint point; char *scale_string; NemoIconView *icon_view; NemoFile *file; g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (NEMO_IS_FILE (data)); g_assert (position != NULL); file = NEMO_FILE (data); icon_view = get_icon_view (container); g_assert (NEMO_IS_ICON_VIEW (icon_view)); if (nemo_icon_view_is_compact (icon_view) || nemo_file_get_is_desktop_orphan (file)) { return FALSE; } nemo_file_get_position (file, &point); position->x = point.x; position->y = point.y; /* If it is the desktop directory, maybe the gnome-libs metadata has information about it */ /* Disable scaling if not on the desktop */ if (nemo_icon_container_get_is_desktop (container)) { /* Get the scale of the icon from the metadata. */ scale_string = nemo_file_get_metadata (file, NEMO_METADATA_KEY_ICON_SCALE, "1"); position->scale = g_ascii_strtod (scale_string, NULL); if (errno != 0) { position->scale = 1.0; } g_free (scale_string); } else { position->scale = 1.0; } return position->x > ICON_UNPOSITIONED_VALUE; } static void lay_down_one_line (NemoIconContainer *container, GList *line_start, GList *line_end, double y, double max_height, GArray *positions, gboolean whole_text, gint gap) { GList *p; NemoIcon *icon; double x, y_offset; NemoCanvasRects *position; int i; gboolean is_rtl; is_rtl = nemo_icon_container_is_layout_rtl (container); /* Lay out the icons along the baseline. */ x = gap; i = 0; for (p = line_start; p != line_end; p = p->next) { icon = p->data; position = &g_array_index (positions, NemoCanvasRects, i++); if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { y_offset = (max_height - position->height) / 2; } else { y_offset = position->y_offset; } nemo_icon_container_icon_set_position (container, icon, is_rtl ? nemo_icon_container_get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset, y + y_offset); nemo_icon_canvas_item_set_entire_text (icon->item, whole_text); icon->saved_ltr_x = is_rtl ? nemo_icon_container_get_mirror_x_position (container, icon, icon->x) : icon->x; x += position->width; } } static void lay_down_one_column (NemoIconContainer *container, GList *line_start, GList *line_end, double x, double y_start, double y_iter, GArray *positions) { GList *p; NemoIcon *icon; double y; NemoCanvasRects *position; int i; gboolean is_rtl; is_rtl = nemo_icon_container_is_layout_rtl (container); /* Lay out the icons along the baseline. */ y = y_start; i = 0; for (p = line_start; p != line_end; p = p->next) { icon = p->data; position = &g_array_index (positions, NemoCanvasRects, i++); nemo_icon_container_icon_set_position (container, icon, is_rtl ? nemo_icon_container_get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset, y + position->y_offset); icon->saved_ltr_x = is_rtl ? nemo_icon_container_get_mirror_x_position (container, icon, icon->x) : icon->x; y += y_iter; } } #define LAYOUT_GAP 4 static void lay_down_icons_horizontal (NemoIconContainer *container, GList *icons, double start_y) { GList *p, *line_start; NemoIcon *icon; double canvas_width, y; GArray *positions; NemoCanvasRects *position; EelDRect bounds; EelDRect icon_bounds; EelDRect text_bounds; double max_height_above, max_height_below; double height_above, height_below; double line_width; double grid_width; double max_text_width, max_icon_width; int icon_width; int i; int num_columns; double ppu; int gap; int device_canvas_width; GtkAllocation allocation; gint icon_size, text_size, use_size; g_assert (NEMO_IS_ICON_CONTAINER (container)); if (icons == NULL) { return; } positions = g_array_new (FALSE, FALSE, sizeof (NemoCanvasRects)); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); /* Lay out icons a line at a time. */ canvas_width = nemo_icon_container_get_canvas_width (container, allocation); max_icon_width = max_text_width = 0.0; ppu = EEL_CANVAS (container)->pixels_per_unit; gap = floor (LAYOUT_GAP / ppu); device_canvas_width = floor (canvas_width * ppu); icon_size = nemo_get_icon_size_for_zoom_level (container->details->zoom_level); text_size = nemo_get_icon_text_width_for_zoom_level (container->details->zoom_level); use_size = MAX (icon_size, text_size) + 15; if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { /* Would it be worth caching these bounds for the next loop? */ for (p = icons; p != NULL; p = p->next) { icon = p->data; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); max_icon_width = MAX (max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0)); text_bounds = nemo_icon_canvas_item_get_text_rectangle (icon->item, TRUE); max_text_width = MAX (max_text_width, ceil (text_bounds.x1 - text_bounds.x0)); } grid_width = max_icon_width + max_text_width + gap; } else { num_columns = device_canvas_width / use_size; /* Minimum of one column */ num_columns = MAX (num_columns, 1); /* -1 prevents jitter */ grid_width = (((device_canvas_width / num_columns) / ppu) - 1.0); } line_width = container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE ? gap : 0; line_start = icons; y = start_y + gap; i = 0; max_height_above = 0; max_height_below = 0; for (p = icons; p != NULL; p = p->next) { icon = p->data; /* Assume it's only one level hierarchy to avoid costly affine calculations */ nemo_icon_canvas_item_get_bounds_for_layout (icon->item, &bounds.x0, &bounds.y0, &bounds.x1, &bounds.y1); icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); icon_width = grid_width; /* Calculate size above/below baseline */ height_above = icon_bounds.y1 - bounds.y0; height_below = bounds.y1 - icon_bounds.y1; /* If this icon doesn't fit, it's time to lay out the line that's queued up. */ if (line_start != p && line_width + icon_width >= canvas_width ) { if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { y += gap; } else { /* Advance to the baseline. */ y += gap + max_height_above; } lay_down_one_line (container, line_start, p, y, max_height_above, positions, FALSE, gap); if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { y += max_height_above + max_height_below + gap; } else { /* Advance to next line. */ y += max_height_below + gap; } line_width = container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE ? gap : 0; line_start = p; i = 0; max_height_above = height_above; max_height_below = height_below; } else { if (height_above > max_height_above) { max_height_above = height_above; } if (height_below > max_height_below) { max_height_below = height_below; } } g_array_set_size (positions, i + 1); position = &g_array_index (positions, NemoCanvasRects, i++); position->width = icon_width; position->height = icon_bounds.y1 - icon_bounds.y0; if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { position->x_offset = max_icon_width + (2 * gap) - (icon_bounds.x1 - icon_bounds.x0); position->y_offset = 0; } else { position->x_offset = (icon_width - (icon_bounds.x1 - icon_bounds.x0)) / 2; position->y_offset = icon_bounds.y0 - icon_bounds.y1; } /* Add this icon. */ line_width += icon_width; } /* Lay down that last line of icons. */ if (line_start != NULL) { if (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE) { y += gap; } else { /* Advance to the baseline. */ y += gap + max_height_above; } lay_down_one_line (container, line_start, NULL, y, max_height_above, positions, TRUE, gap); } g_array_free (positions, TRUE); } /* column-wise layout. At the moment, this only works with label-beside-icon (used by "Compact View"). */ static void lay_down_icons_vertical (NemoIconContainer *container, GList *icons, double start_y) { GList *p, *line_start; NemoIcon *icon; double x, canvas_height; GArray *positions; NemoCanvasRects *position; EelDRect icon_bounds; EelDRect text_bounds; GtkAllocation allocation; double ppu; int gap; double line_height; double max_height; double max_height_with_borders; double max_width; double max_width_in_column; double max_bounds_height; double max_bounds_height_with_borders; double max_text_width, max_icon_width; double max_text_height, max_icon_height; int height; int i; g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (container->details->label_position == NEMO_ICON_LABEL_POSITION_BESIDE); if (icons == NULL) { return; } ppu = EEL_CANVAS (container)->pixels_per_unit; gap = floor (LAYOUT_GAP / ppu); positions = g_array_new (FALSE, FALSE, sizeof (NemoCanvasRects)); gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); /* Lay out icons a column at a time. */ canvas_height = nemo_icon_container_get_canvas_height (container, allocation); max_icon_width = max_text_width = 0.0; max_icon_height = max_text_height = 0.0; max_bounds_height = 0.0; get_max_icon_dimensions (icons, NULL, &max_icon_width, &max_icon_height, &max_text_width, &max_text_height, &max_bounds_height); max_width = max_icon_width + max_text_width; max_height = MAX (max_icon_height, max_text_height); max_height_with_borders = gap + max_height; max_bounds_height_with_borders = gap + max_bounds_height; line_height = gap; line_start = icons; x = 0; i = 0; max_width_in_column = 0.0; for (p = icons; p != NULL; p = p->next) { icon = p->data; /* If this icon doesn't fit, it's time to lay out the column that's queued up. */ /* We use the bounds height here, since for wrapping we also want to consider * overlapping emblems at the bottom. We may wrap a little bit too early since * the icon with the max. bounds height may actually not be in the last row, but * it is better than visual glitches */ if (line_start != p && line_height + (max_bounds_height_with_borders-1) >= canvas_height ) { x += gap; /* correctly set (per-column) width */ if (!container->details->all_columns_same_width) { for (i = 0; i < (int) positions->len; i++) { position = &g_array_index (positions, NemoCanvasRects, i); position->width = max_width_in_column; } } lay_down_one_column (container, line_start, p, x, gap, max_height_with_borders, positions); /* Advance to next column. */ if (container->details->all_columns_same_width) { x += max_width + gap; } else { x += max_width_in_column + gap; } line_height = gap; line_start = p; i = 0; max_width_in_column = 0; } icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); text_bounds = nemo_icon_canvas_item_get_text_rectangle (icon->item, TRUE); max_width_in_column = MAX (max_width_in_column, ceil (icon_bounds.x1 - icon_bounds.x0) + ceil (text_bounds.x1 - text_bounds.x0)); g_array_set_size (positions, i + 1); position = &g_array_index (positions, NemoCanvasRects, i++); if (container->details->all_columns_same_width) { position->width = max_width; } position->height = max_height; position->y_offset = gap; position->x_offset = gap; position->x_offset += max_icon_width - ceil (icon_bounds.x1 - icon_bounds.x0); height = MAX (ceil (icon_bounds.y1 - icon_bounds.y0), ceil(text_bounds.y1 - text_bounds.y0)); position->y_offset += (max_height - height) / 2; /* Add this icon. */ line_height += max_height_with_borders; } /* Lay down that last column of icons. */ if (line_start != NULL) { x += gap; lay_down_one_column (container, line_start, NULL, x, gap, max_height_with_borders, positions); } g_array_free (positions, TRUE); } static void lay_down_icons_vertical_desktop (NemoIconContainer *container, GList *icons) { GList *p, *placed_icons, *unplaced_icons; int total, new_length, placed; NemoIcon *icon; int height, max_width, column_width, icon_width, icon_height; int x, y, x1, x2, y1, y2; EelDRect icon_rect; GtkAllocation allocation; /* Get container dimensions */ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); height = nemo_icon_container_get_canvas_height (container, allocation); /* Determine which icons have and have not been placed */ placed_icons = NULL; unplaced_icons = NULL; total = g_list_length (container->details->icons); new_length = g_list_length (icons); placed = total - new_length; if (placed > 0) { NemoPlacementGrid *grid; /* Add only placed icons in list */ for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (nemo_icon_container_icon_is_positioned (icon)) { nemo_icon_container_icon_set_position(container, icon, icon->saved_ltr_x, icon->y); placed_icons = g_list_prepend (placed_icons, icon); } else { icon->x = 0; icon->y = 0; unplaced_icons = g_list_prepend (unplaced_icons, icon); } } placed_icons = g_list_reverse (placed_icons); unplaced_icons = g_list_reverse (unplaced_icons); grid = nemo_placement_grid_new (container, FALSE); if (grid) { for (p = placed_icons; p != NULL; p = p->next) { nemo_placement_grid_mark_icon (grid, (NemoIcon*)p->data); } /* Place unplaced icons in the best locations */ for (p = unplaced_icons; p != NULL; p = p->next) { icon = p->data; icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); /* Start the icon in the first column */ x = GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + (GET_VIEW_CONSTANT (container, snap_size_x) / 2) - ((icon_rect.x1 - icon_rect.x0) / 2); y = GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y) - (icon_rect.y1 - icon_rect.y0); find_empty_location (container, grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); icon->saved_ltr_x = x; nemo_placement_grid_mark_icon (grid, icon); } nemo_placement_grid_free (grid); } g_list_free (placed_icons); g_list_free (unplaced_icons); } else { /* There are no placed icons. Just lay them down using our rules */ x = GET_VIEW_CONSTANT (container, desktop_pad_horizontal); while (icons != NULL) { int center_x; int baseline; int icon_height_for_bound_check; gboolean should_snap; should_snap = container->details->keep_aligned; y = GET_VIEW_CONSTANT (container, desktop_pad_vertical); max_width = 0; /* Calculate max width for column */ for (p = icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_container_icon_get_bounding_box (container, icon, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_LAYOUT); icon_width = x2 - x1; icon_height = y2 - y1; nemo_icon_container_icon_get_bounding_box (container, icon, NULL, &y1, NULL, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM); icon_height_for_bound_check = y2 - y1; if (should_snap) { /* Snap the baseline to a grid position */ icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); baseline = y + (icon_rect.y1 - icon_rect.y0); baseline = SNAP_CEIL_VERTICAL (baseline); y = baseline - (icon_rect.y1 - icon_rect.y0); } /* Check and see if we need to move to a new column */ if (y != GET_VIEW_CONSTANT (container, desktop_pad_vertical) && y + icon_height_for_bound_check > height) { break; } if (max_width < icon_width) { max_width = icon_width; } y += icon_height + GET_VIEW_CONSTANT (container, desktop_pad_vertical); } y = GET_VIEW_CONSTANT (container, desktop_pad_vertical); center_x = x + max_width / 2; column_width = max_width; if (should_snap) { /* Find the grid column to center on */ center_x = SNAP_CEIL_HORIZONTAL (center_x); column_width = (center_x - x) + (max_width / 2); } /* Lay out column */ for (p = icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_container_icon_get_bounding_box (container, icon, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_LAYOUT); icon_height = y2 - y1; nemo_icon_container_icon_get_bounding_box (container, icon, NULL, &y1, NULL, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM); icon_height_for_bound_check = y2 - y1; icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); if (should_snap) { baseline = y + (icon_rect.y1 - icon_rect.y0); baseline = SNAP_CEIL_VERTICAL (baseline); y = baseline - (icon_rect.y1 - icon_rect.y0); } /* Check and see if we need to move to a new column */ if (y != GET_VIEW_CONSTANT (container, desktop_pad_vertical) && y > height - icon_height_for_bound_check && /* Make sure we lay out at least one icon per column, to make progress */ p != icons) { x += column_width + GET_VIEW_CONSTANT (container, desktop_pad_horizontal); break; } nemo_icon_container_icon_set_position (container, icon, center_x - (icon_rect.x1 - icon_rect.x0) / 2, y); icon->saved_ltr_x = icon->x; y += icon_height + GET_VIEW_CONSTANT (container, desktop_pad_vertical); } icons = p; } } /* These modes are special. We freeze all of our positions * after we do the layout. */ /* FIXME bugzilla.gnome.org 42478: * This should not be tied to the direction of layout. * It should be a separate switch. */ nemo_icon_container_freeze_icon_positions (container); } static void nemo_icon_view_container_lay_down_icons (NemoIconContainer *container, GList *icons, double start_y) { switch (container->details->layout_mode) { case NEMO_ICON_LAYOUT_L_R_T_B: case NEMO_ICON_LAYOUT_R_L_T_B: lay_down_icons_horizontal (container, icons, start_y); break; case NEMO_ICON_LAYOUT_T_B_L_R: case NEMO_ICON_LAYOUT_T_B_R_L: if (nemo_icon_container_get_is_desktop (container)) { lay_down_icons_vertical_desktop (container, icons); } else { lay_down_icons_vertical (container, icons, start_y); } break; default: g_assert_not_reached (); } } static void get_max_icon_dimensions (GList *icon_start, GList *icon_end, double *max_icon_width, double *max_icon_height, double *max_text_width, double *max_text_height, double *max_bounds_height) { NemoIcon *icon; EelDRect icon_bounds; EelDRect text_bounds; GList *p; double y1, y2; *max_icon_width = *max_text_width = 0.0; *max_icon_height = *max_text_height = 0.0; *max_bounds_height = 0.0; /* Would it be worth caching these bounds for the next loop? */ for (p = icon_start; p != icon_end; p = p->next) { icon = p->data; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); *max_icon_width = MAX (*max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0)); *max_icon_height = MAX (*max_icon_height, ceil (icon_bounds.y1 - icon_bounds.y0)); text_bounds = nemo_icon_canvas_item_get_text_rectangle (icon->item, TRUE); *max_text_width = MAX (*max_text_width, ceil (text_bounds.x1 - text_bounds.x0)); *max_text_height = MAX (*max_text_height, ceil (text_bounds.y1 - text_bounds.y0)); nemo_icon_canvas_item_get_bounds_for_layout (icon->item, NULL, &y1, NULL, &y2); *max_bounds_height = MAX (*max_bounds_height, y2 - y1); } } static void snap_position (NemoIconContainer *container, NemoIcon *icon, int *x, int *y) { int center_x; int baseline_y; int icon_width; int icon_height; int total_width; int total_height; EelDRect icon_position; GtkAllocation allocation; icon_position = nemo_icon_canvas_item_get_icon_rectangle (icon->item); icon_width = icon_position.x1 - icon_position.x0; icon_height = icon_position.y1 - icon_position.y0; gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); total_width = nemo_icon_container_get_canvas_width (container, allocation); total_height = nemo_icon_container_get_canvas_height (container, allocation); if (nemo_icon_container_is_layout_rtl (container)) *x = nemo_icon_container_get_mirror_x_position (container, icon, *x); if (*x + icon_width / 2 < GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + GET_VIEW_CONSTANT (container, snap_size_x)) { *x = GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + GET_VIEW_CONSTANT (container, snap_size_x) - icon_width / 2; } if (*x + icon_width / 2 > total_width - (GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + GET_VIEW_CONSTANT (container, snap_size_x))) { *x = total_width - (GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + GET_VIEW_CONSTANT (container, snap_size_x) + (icon_width / 2)); } if (*y + icon_height < GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y)) { *y = GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y) - icon_height; } if (*y + icon_height > total_height - (GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y))) { *y = total_height - (GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y) + (icon_height / 2)); } center_x = *x + icon_width / 2; *x = SNAP_NEAREST_HORIZONTAL (center_x) - (icon_width / 2); if (nemo_icon_container_is_layout_rtl (container)) { *x = nemo_icon_container_get_mirror_x_position (container, icon, *x); } /* Find the grid position vertically and place on the proper baseline */ baseline_y = *y + icon_height; baseline_y = SNAP_NEAREST_VERTICAL (baseline_y); *y = baseline_y - icon_height; } static int compare_icons_by_position (gconstpointer a, gconstpointer b) { NemoIcon *icon_a, *icon_b; int x1, y1, x2, y2; int center_a; int center_b; icon_a = (NemoIcon*)a; icon_b = (NemoIcon*)b; nemo_icon_view_container_icon_get_bounding_box (icon_a, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_DISPLAY); center_a = x1 + (x2 - x1) / 2; nemo_icon_view_container_icon_get_bounding_box (icon_b, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_DISPLAY); center_b = x1 + (x2 - x1) / 2; return center_a == center_b ? icon_a->y - icon_b->y : center_a - center_b; } /* x, y are the top-left coordinates of the icon. */ static void nemo_icon_view_container_icon_set_position (NemoIconContainer *container, NemoIcon *icon, double x, double y) { double pixels_per_unit; int container_left, container_top, container_right, container_bottom; int x1, x2, y1, y2; int container_x, container_y, container_width, container_height; EelDRect icon_bounds; int item_width, item_height; int height_above, width_left; int min_x, max_x, min_y, max_y; if (icon->x == x && icon->y == y) { return; } if (icon == nemo_icon_container_get_icon_being_renamed (container)) { nemo_icon_container_end_renaming_mode (container, TRUE); } if (nemo_icon_container_get_is_fixed_size (container)) { GtkAllocation alloc; gtk_widget_get_allocation (GTK_WIDGET (container), &alloc); container_x = alloc.x; container_y = alloc.y; container_width = alloc.width - container->details->left_margin - container->details->right_margin; container_height = alloc.height - container->details->top_margin - container->details->bottom_margin; pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit; /* Clip the position of the icon within our desktop bounds */ container_left = container_x / pixels_per_unit; container_top = container_y / pixels_per_unit; container_right = container_left + container_width / pixels_per_unit; container_bottom = container_top + container_height / pixels_per_unit; nemo_icon_container_icon_get_bounding_box (container, icon, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM); item_width = x2 - x1; item_height = y2 - y1; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); /* determine icon rectangle relative to item rectangle */ height_above = icon_bounds.y0 - y1; width_left = icon_bounds.x0 - x1; min_x = container_left + GET_VIEW_CONSTANT (container, desktop_pad_horizontal) + width_left; max_x = container_right - GET_VIEW_CONSTANT (container, desktop_pad_horizontal) - item_width + width_left; x = CLAMP (x, min_x, max_x); min_y = container_top + height_above + GET_VIEW_CONSTANT (container, desktop_pad_vertical); max_y = container_bottom - GET_VIEW_CONSTANT (container, desktop_pad_vertical) - item_height + height_above; y = CLAMP (y, min_y, max_y); } if (icon->x == ICON_UNPOSITIONED_VALUE) { icon->x = 0; } if (icon->y == ICON_UNPOSITIONED_VALUE) { icon->y = 0; } eel_canvas_item_move (EEL_CANVAS_ITEM (icon->item), x - icon->x, y - icon->y); icon->x = x; icon->y = y; } static void nemo_icon_view_container_move_icon (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position) { NemoIconContainerDetails *details; gboolean emit_signal; NemoIconPosition position; details = container->details; emit_signal = FALSE; if (icon == nemo_icon_container_get_icon_being_renamed (container)) { nemo_icon_container_end_renaming_mode (container, TRUE); } if (scale != icon->scale) { icon->scale = scale; nemo_icon_container_update_icon (container, icon); if (update_position) { nemo_icon_container_redo_layout (container); emit_signal = TRUE; } } if (!details->auto_layout) { if (details->keep_aligned && snap) { snap_position (container, icon, &x, &y); } if (x != icon->x || y != icon->y) { nemo_icon_container_icon_set_position (container, icon, x, y); emit_signal = update_position; } icon->saved_ltr_x = nemo_icon_container_is_layout_rtl (container) ? nemo_icon_container_get_mirror_x_position (container, icon, icon->x) : icon->x; } if (emit_signal) { position.x = icon->saved_ltr_x; position.y = icon->y; position.scale = scale; position.monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); g_signal_emit_by_name (container, "icon_position_changed", icon->data, &position); } if (raise) { nemo_icon_container_icon_raise (container, icon); } /* FIXME bugzilla.gnome.org 42474: * Handling of the scroll region is inconsistent here. In * the scale-changing case, redo_layout is called, which updates the * scroll region appropriately. In other cases, it's up to the * caller to make sure the scroll region is updated. This could * lead to hard-to-track-down bugs. */ } static void icon_get_size (NemoIconContainer *container, NemoIcon *icon, guint *size) { if (size != NULL) { *size = MAX (nemo_get_icon_size_for_zoom_level (container->details->zoom_level) * icon->scale, NEMO_ICON_SIZE_SMALLEST); } } static void nemo_icon_view_container_update_icon (NemoIconContainer *container, NemoIcon *icon) { NemoIconContainerDetails *details; guint icon_size; guint min_image_size, max_image_size; NemoIconInfo *icon_info; GdkPixbuf *pixbuf; char *editable_text, *additional_text; gboolean has_open_window; gboolean pinned; if (icon == NULL) { return; } details = container->details; /* compute the maximum size based on the scale factor */ min_image_size = MINIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit; max_image_size = MAX (MAXIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit, NEMO_ICON_MAXIMUM_SIZE); /* Get the appropriate images for the file. */ if (container->details->forced_icon_size > 0) { icon_size = container->details->forced_icon_size; } else { icon_get_size (container, icon, &icon_size); } icon_size = MAX (icon_size, min_image_size); icon_size = MIN (icon_size, max_image_size); DEBUG ("Icon size, getting for size %d", icon_size); /* Get the icons. */ icon_info = nemo_icon_container_get_icon_images (container, icon->data, icon_size, icon == details->drop_target, &has_open_window); if (container->details->forced_icon_size > 0) { gint scale_factor; scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (container)); pixbuf = nemo_icon_info_get_pixbuf_at_size (icon_info, icon_size * scale_factor); } else { pixbuf = nemo_icon_info_get_pixbuf (icon_info); } nemo_icon_info_unref (icon_info); nemo_icon_container_get_icon_text (container, icon->data, &editable_text, &additional_text, &pinned, FALSE); /* If name of icon being renamed was changed from elsewhere, end renaming mode. * Alternatively, we could replace the characters in the editable text widget * with the new name, but that could cause timing problems if the user just * happened to be typing at that moment. */ if (icon == nemo_icon_container_get_icon_being_renamed (container) && g_strcmp0 (editable_text, nemo_icon_canvas_item_get_editable_text (icon->item)) != 0) { nemo_icon_container_end_renaming_mode (container, FALSE); } eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item), "editable_text", editable_text, "additional_text", additional_text, "highlighted_for_drop", icon == details->drop_target, "pinned", pinned, NULL); nemo_icon_canvas_item_set_image (icon->item, pixbuf); /* Let the pixbufs go. */ g_object_unref (pixbuf); g_free (editable_text); g_free (additional_text); } static void find_empty_location (NemoIconContainer *container, NemoPlacementGrid *grid, NemoIcon *icon, int start_x, int start_y, int *x, int *y) { double icon_width, icon_height; int canvas_width; int canvas_height; int height_for_bound_check; EelIRect icon_position; EelDRect pixbuf_rect; gboolean collision; GtkAllocation allocation; /* Get container dimensions */ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation); canvas_width = nemo_icon_container_get_canvas_width (container, allocation); canvas_height = nemo_icon_container_get_canvas_height (container, allocation); nemo_icon_container_icon_get_bounding_box (container, icon, &icon_position.x0, &icon_position.y0, &icon_position.x1, &icon_position.y1, BOUNDS_USAGE_FOR_LAYOUT); icon_width = icon_position.x1 - icon_position.x0; icon_height = icon_position.y1 - icon_position.y0; nemo_icon_container_icon_get_bounding_box (container, icon, NULL, &icon_position.y0, NULL, &icon_position.y1, BOUNDS_USAGE_FOR_ENTIRE_ITEM); height_for_bound_check = icon_position.y1 - icon_position.y0; pixbuf_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); /* Start the icon on a grid location */ snap_position (container, icon, &start_x, &start_y); icon_position.x0 = start_x; icon_position.y0 = start_y; icon_position.x1 = icon_position.x0 + icon_width; icon_position.y1 = icon_position.y0 + icon_height; do { EelIRect grid_position; gboolean need_new_column; collision = FALSE; nemo_placement_grid_canvas_position_to_grid_position (grid, icon_position, &grid_position); need_new_column = icon_position.y0 + height_for_bound_check + GET_VIEW_CONSTANT (container, desktop_pad_vertical) > canvas_height; if (need_new_column || !nemo_placement_grid_position_is_free (grid, grid_position)) { icon_position.y0 += GET_VIEW_CONSTANT (container, snap_size_y); icon_position.y1 = icon_position.y0 + icon_height; if (need_new_column) { /* Move to the next column */ icon_position.y0 = GET_VIEW_CONSTANT (container, desktop_pad_vertical) + GET_VIEW_CONSTANT (container, snap_size_y) - (pixbuf_rect.y1 - pixbuf_rect.y0); while (icon_position.y0 < GET_VIEW_CONSTANT (container, desktop_pad_vertical)) { icon_position.y0 += GET_VIEW_CONSTANT (container, snap_size_y); } icon_position.y1 = icon_position.y0 + icon_height; icon_position.x0 += GET_VIEW_CONSTANT (container, snap_size_x); icon_position.x1 = icon_position.x0 + icon_width; } collision = TRUE; } } while (collision && (icon_position.x1 < canvas_width)); *x = icon_position.x0; *y = icon_position.y0; } static void nemo_icon_view_container_align_icons (NemoIconContainer *container) { GList *unplaced_icons; GList *l; NemoPlacementGrid *grid; unplaced_icons = g_list_copy (container->details->icons); unplaced_icons = g_list_sort (unplaced_icons, compare_icons_by_position); if (nemo_icon_container_is_layout_rtl (container)) { unplaced_icons = g_list_reverse (unplaced_icons); } grid = nemo_placement_grid_new (container, TRUE); if (!grid) { g_list_free (unplaced_icons); return; } for (l = unplaced_icons; l != NULL; l = l->next) { NemoIcon *icon; int x, y; icon = l->data; x = icon->saved_ltr_x; y = icon->y; find_empty_location (container, grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); icon->saved_ltr_x = icon->x; nemo_placement_grid_mark_icon (grid, icon); } g_list_free (unplaced_icons); nemo_placement_grid_free (grid); if (nemo_icon_container_is_layout_rtl (container)) { nemo_icon_container_set_rtl_positions (container); } } static void nemo_icon_view_container_reload_icon_positions (NemoIconContainer *container) { GList *p, *no_position_icons; NemoIcon *icon; gboolean have_stored_position; NemoIconPosition position; EelDRect bounds; double bottom; EelCanvasItem *item; g_assert (!container->details->auto_layout); nemo_icon_container_resort (container); no_position_icons = NULL; /* Place all the icons with positions. */ bottom = 0; for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; have_stored_position = get_stored_icon_position (container, icon->data, &position); if (have_stored_position) { nemo_icon_container_icon_set_position (container, icon, position.x, position.y); item = EEL_CANVAS_ITEM (icon->item); nemo_icon_canvas_item_get_bounds_for_layout (icon->item, &bounds.x0, &bounds.y0, &bounds.x1, &bounds.y1); eel_canvas_item_i2w (item->parent, &bounds.x0, &bounds.y0); eel_canvas_item_i2w (item->parent, &bounds.x1, &bounds.y1); if (bounds.y1 > bottom) { bottom = bounds.y1; } } else { no_position_icons = g_list_prepend (no_position_icons, icon); } } no_position_icons = g_list_reverse (no_position_icons); /* Place all the other icons. */ NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, no_position_icons, bottom + GET_VIEW_CONSTANT (container, icon_pad_bottom)); g_list_free (no_position_icons); } static gboolean assign_icon_position (NemoIconContainer *container, NemoIcon *icon) { gboolean have_stored_position; NemoIconPosition position; /* Get the stored position. */ have_stored_position = FALSE; position.scale = 1.0; have_stored_position = get_stored_icon_position (container, icon->data, &position); icon->scale = position.scale; if (!container->details->auto_layout) { if (have_stored_position) { nemo_icon_container_icon_set_position (container, icon, position.x, position.y); icon->saved_ltr_x = icon->x; } else { return FALSE; } } return TRUE; } static void nemo_icon_view_container_finish_adding_new_icons (NemoIconContainer *container) { GList *p, *new_icons, *no_position_icons, *semi_position_icons; NemoIcon *icon; double bottom; gint current_monitor; new_icons = container->details->new_icons; container->details->new_icons = NULL; current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET(container)); /* Position most icons (not unpositioned manual-layout icons). */ new_icons = g_list_reverse (new_icons); no_position_icons = semi_position_icons = NULL; for (p = new_icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_container_update_icon (container, icon); if (icon->has_lazy_position || nemo_icon_container_icon_is_new_for_monitor (container, icon, current_monitor)) { assign_icon_position (container, icon); semi_position_icons = g_list_prepend (semi_position_icons, icon); } else if (!assign_icon_position (container, icon)) { no_position_icons = g_list_prepend (no_position_icons, icon); } nemo_icon_container_finish_adding_icon (container, icon); } g_list_free (new_icons); if (semi_position_icons != NULL) { NemoPlacementGrid *grid; time_t now; gboolean dummy; g_assert (!container->details->auto_layout); semi_position_icons = g_list_reverse (semi_position_icons); /* This is currently only used on the desktop. * Thus, we pass FALSE for tight, like lay_down_icons_tblr */ grid = nemo_placement_grid_new (container, FALSE); for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (nemo_icon_container_icon_is_positioned (icon) && !icon->has_lazy_position) { nemo_placement_grid_mark_icon (grid, icon); } } now = time (NULL); for (p = semi_position_icons; p != NULL; p = p->next) { NemoIconPosition position; int x, y; icon = p->data; x = icon->x; y = icon->y; find_empty_location (container, grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); position.x = icon->x; position.y = icon->y; position.scale = icon->scale; position.monitor = current_monitor; nemo_placement_grid_mark_icon (grid, icon); g_signal_emit_by_name (container, "icon_position_changed", icon->data, &position); g_signal_emit_by_name (container, "store_layout_timestamp", icon->data, &now, &dummy); /* ensure that next time we run this code, the formerly semi-positioned * icons are treated as being positioned. */ icon->has_lazy_position = FALSE; } nemo_placement_grid_free (grid); g_list_free (semi_position_icons); } /* Position the unpositioned manual layout icons. */ if (no_position_icons != NULL) { g_assert (!container->details->auto_layout); nemo_icon_container_sort_icons (container, &no_position_icons); if (nemo_icon_container_get_is_desktop (container)) { NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, no_position_icons, GET_VIEW_CONSTANT (container, container_pad_top)); } else { nemo_icon_container_get_all_icon_bounds (container, NULL, NULL, NULL, &bottom, BOUNDS_USAGE_FOR_LAYOUT); NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, no_position_icons, bottom + GET_VIEW_CONSTANT (container, icon_pad_bottom)); } g_list_free (no_position_icons); } if (container->details->store_layout_timestamps_when_finishing_new_icons) { nemo_icon_container_store_layout_timestamps_now (container); container->details->store_layout_timestamps_when_finishing_new_icons = FALSE; } } static void nemo_icon_view_container_set_zoom_level (NemoIconContainer *container, gint new_level) { NemoIconContainerDetails *details; int pinned_level; double pixels_per_unit; details = container->details; nemo_icon_container_end_renaming_mode (container, TRUE); pinned_level = new_level; if (pinned_level < NEMO_ZOOM_LEVEL_SMALLEST) { pinned_level = NEMO_ZOOM_LEVEL_SMALLEST; } else if (pinned_level > NEMO_ZOOM_LEVEL_LARGEST) { pinned_level = NEMO_ZOOM_LEVEL_LARGEST; } if (pinned_level == details->zoom_level) { return; } details->zoom_level = pinned_level; pixels_per_unit = (double) nemo_get_icon_size_for_zoom_level (pinned_level) / NEMO_ICON_SIZE_STANDARD; eel_canvas_set_pixels_per_unit (EEL_CANVAS (container), pixels_per_unit); } static int text_ellipsis_limits[NEMO_ZOOM_LEVEL_N_ENTRIES]; static int desktop_text_ellipsis_limit; static gboolean get_text_ellipsis_limit_for_zoom (char **strs, const char *zoom_level, int *limit) { char **p; char *str; gboolean success; success = FALSE; /* default */ *limit = 3; if (zoom_level != NULL) { str = g_strdup_printf ("%s:%%d", zoom_level); } else { str = g_strdup ("%d"); } if (strs != NULL) { for (p = strs; *p != NULL; p++) { if (sscanf (*p, str, limit)) { success = TRUE; } } } g_free (str); return success; } static const char * zoom_level_names[] = { "smallest", "smaller", "small", "standard", "large", "larger", "largest" }; static void text_ellipsis_limit_changed_callback (gpointer callback_data) { char **pref; unsigned int i; int one_limit; pref = g_settings_get_strv (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT); /* set default */ get_text_ellipsis_limit_for_zoom (pref, NULL, &one_limit); for (i = 0; i < NEMO_ZOOM_LEVEL_N_ENTRIES; i++) { text_ellipsis_limits[i] = one_limit; } /* override for each zoom level */ for (i = 0; i < G_N_ELEMENTS(zoom_level_names); i++) { if (get_text_ellipsis_limit_for_zoom (pref, zoom_level_names[i], &one_limit)) { text_ellipsis_limits[i] = one_limit; } } g_strfreev (pref); } static void desktop_text_ellipsis_limit_changed_callback (gpointer callback_data) { int pref; pref = g_settings_get_int (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT); desktop_text_ellipsis_limit = pref; } static gchar * on_get_tooltip_text (NemoIconContainer *container, NemoFile *file, gpointer user_data) { gboolean is_desktop, show_tooltip; gchar *tooltip_text = NULL; is_desktop = container->details->is_desktop; show_tooltip = (container->details->show_desktop_tooltips && is_desktop) || (container->details->show_icon_view_tooltips && !is_desktop); if (show_tooltip) { tooltip_text = nemo_file_construct_tooltip (file, container->details->tooltip_flags); } return tooltip_text; } static gint nemo_icon_view_container_get_max_layout_lines_for_pango (NemoIconContainer *container) { int limit; if (nemo_icon_container_get_is_desktop (container)) { limit = desktop_text_ellipsis_limit; } else { limit = text_ellipsis_limits[container->details->zoom_level]; } if (limit <= 0) { return G_MININT; } return -limit; } static gint nemo_icon_view_container_get_max_layout_lines (NemoIconContainer *container) { int limit; if (nemo_icon_container_get_is_desktop (container)) { limit = desktop_text_ellipsis_limit; } else { limit = text_ellipsis_limits[container->details->zoom_level]; } if (limit <= 0) { return G_MAXINT; } return limit; } static void finalize (GObject *object) { g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, text_ellipsis_limit_changed_callback, NULL); g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, desktop_text_ellipsis_limit_changed_callback, NULL); g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, update_auto_strv_as_quarks, &caption_attributes); G_OBJECT_CLASS (nemo_icon_view_container_parent_class)->finalize (object); } static void nemo_icon_view_container_class_init (NemoIconViewContainerClass *klass) { NemoIconContainerClass *ic_class; G_OBJECT_CLASS (klass)->finalize = finalize; ic_class = &klass->parent_class; attribute_none_q = g_quark_from_static_string ("none"); ic_class->is_grid_container = FALSE; ic_class->get_icon_text = nemo_icon_view_container_get_icon_text; ic_class->get_icon_images = nemo_icon_view_container_get_icon_images; ic_class->get_icon_description = nemo_icon_view_container_get_icon_description; ic_class->prioritize_thumbnailing = nemo_icon_view_container_prioritize_thumbnailing; ic_class->get_max_layout_lines_for_pango = nemo_icon_view_container_get_max_layout_lines_for_pango; ic_class->get_max_layout_lines = nemo_icon_view_container_get_max_layout_lines; ic_class->compare_icons = nemo_icon_view_container_compare_icons; ic_class->freeze_updates = nemo_icon_view_container_freeze_updates; ic_class->unfreeze_updates = nemo_icon_view_container_unfreeze_updates; ic_class->lay_down_icons = nemo_icon_view_container_lay_down_icons; ic_class->icon_set_position = nemo_icon_view_container_icon_set_position; ic_class->move_icon = nemo_icon_view_container_move_icon; ic_class->update_icon = nemo_icon_view_container_update_icon; ic_class->align_icons = nemo_icon_view_container_align_icons; ic_class->reload_icon_positions = nemo_icon_view_container_reload_icon_positions; ic_class->finish_adding_new_icons = nemo_icon_view_container_finish_adding_new_icons; ic_class->icon_get_bounding_box = nemo_icon_view_container_icon_get_bounding_box; ic_class->set_zoom_level = nemo_icon_view_container_set_zoom_level; } static void nemo_icon_view_container_init (NemoIconViewContainer *icon_container) { gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (icon_container)), GTK_STYLE_CLASS_VIEW); static gboolean setup_prefs = FALSE; g_signal_connect (icon_container, "get-tooltip-text", G_CALLBACK (on_get_tooltip_text), NULL); if (!setup_prefs) { g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (text_ellipsis_limit_changed_callback), NULL); text_ellipsis_limit_changed_callback (NULL); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (desktop_text_ellipsis_limit_changed_callback), NULL); desktop_text_ellipsis_limit_changed_callback (NULL); g_signal_connect (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, G_CALLBACK (update_auto_strv_as_quarks), &caption_attributes); setup_prefs = TRUE; } } NemoIconContainer * nemo_icon_view_container_construct (NemoIconViewContainer *icon_container, NemoIconView *view, gboolean is_desktop) { AtkObject *atk_obj; NemoViewLayoutConstants *constants = NEMO_ICON_CONTAINER (icon_container)->details->view_constants; g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NULL); icon_container->view = view; nemo_icon_container_set_is_desktop (NEMO_ICON_CONTAINER (icon_container), is_desktop); atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_container)); atk_object_set_name (atk_obj, _("Icon View")); constants = NEMO_ICON_CONTAINER (icon_container)->details->view_constants; constants->icon_pad_left = 4; constants->icon_pad_right = 4; constants->icon_pad_top = 4; constants->icon_pad_bottom = 4; constants->container_pad_left = 4; constants->container_pad_right = 4; constants->container_pad_top = 4; constants->container_pad_bottom = 4; constants->standard_icon_grid_width = 155; constants->text_beside_icon_grid_width = 205; constants->desktop_pad_horizontal = 10; constants->desktop_pad_vertical = 10; constants->snap_size_x = 78; constants->snap_size_y = 20; constants->max_text_width_standard = 135; constants->max_text_width_beside = 90; constants->max_text_width_beside_top_to_bottom = 150; return NEMO_ICON_CONTAINER (icon_container); } NemoIconContainer * nemo_icon_view_container_new (NemoIconView *view, gboolean is_desktop) { return nemo_icon_view_container_construct (g_object_new (NEMO_TYPE_ICON_VIEW_CONTAINER, NULL), view, is_desktop); } void nemo_icon_view_container_set_sort_desktop (NemoIconViewContainer *container, gboolean desktop) { container->sort_for_desktop = desktop; } nemo-4.4.2/src/nemo-icon-view-container.h000066400000000000000000000057401357442400300202430ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-icon-container.h - the container widget for file manager icons Copyright (C) 2002 Sun Microsystems, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Michael Meeks */ #ifndef NEMO_ICON_VIEW_CONTAINER_H #define NEMO_ICON_VIEW_CONTAINER_H #include "nemo-icon-view.h" #include typedef struct NemoIconViewContainer NemoIconViewContainer; typedef struct NemoIconViewContainerClass NemoIconViewContainerClass; #define NEMO_TYPE_ICON_VIEW_CONTAINER nemo_icon_view_container_get_type() #define NEMO_ICON_VIEW_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ICON_VIEW_CONTAINER, NemoIconViewContainer)) #define NEMO_ICON_VIEW_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ICON_VIEW_CONTAINER, NemoIconViewContainerClass)) #define NEMO_IS_ICON_VIEW_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ICON_VIEW_CONTAINER)) #define NEMO_IS_ICON_VIEW_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ICON_VIEW_CONTAINER)) #define NEMO_ICON_VIEW_CONTAINER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ICON_VIEW_CONTAINER, NemoIconViewContainerClass)) typedef struct NemoIconViewContainerDetails NemoIconViewContainerDetails; struct NemoIconViewContainer { NemoIconContainer parent; NemoIconView *view; gboolean sort_for_desktop; }; struct NemoIconViewContainerClass { NemoIconContainerClass parent_class; }; GType nemo_icon_view_container_get_type (void); NemoIconContainer *nemo_icon_view_container_construct (NemoIconViewContainer *icon_container, NemoIconView *view, gboolean is_desktop); NemoIconContainer *nemo_icon_view_container_new (NemoIconView *view, gboolean is_desktop); void nemo_icon_view_container_set_sort_desktop (NemoIconViewContainer *container, gboolean desktop); #endif /* NEMO_ICON_VIEW_CONTAINER_H */ nemo-4.4.2/src/nemo-icon-view-grid-container.c000066400000000000000000001565601357442400300211700ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* fm-icon-container.h - the container widget for file manager icons Copyright (C) 2002 Sun Microsystems, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Michael Meeks */ #include #include "nemo-icon-view-grid-container.h" #include #include #include #include #include #include #include "nemo-icon-private.h" #define DEBUG_FLAG NEMO_DEBUG_DESKTOP #include #include #include #include #include #include #include static void update_layout_constants (NemoIconContainer *container); G_DEFINE_TYPE (NemoIconViewGridContainer, nemo_icon_view_grid_container, NEMO_TYPE_ICON_CONTAINER); #define GRID_VIEW_MAX_ADDITIONAL_ATTRIBUTES 1 static GQuark attribute_none_q; static NemoIconView * get_icon_view (NemoIconContainer *container) { /* Type unsafe comparison for performance */ return ((NemoIconViewGridContainer *)container)->view; } static NemoIconInfo * nemo_icon_view_grid_container_get_icon_images (NemoIconContainer *container, NemoIconData *data, int size, gboolean for_drag_accept, gboolean *has_window_open) { NemoIconView *icon_view; NemoFile *file; NemoFileIconFlags flags; NemoIconInfo *icon_info; GdkPixbuf *pixbuf; GIcon *emblemed_icon; GEmblem *emblem; GList *emblem_icons, *l; gint scale; file = (NemoFile *) data; g_assert (NEMO_IS_FILE (file)); icon_view = get_icon_view (container); g_return_val_if_fail (icon_view != NULL, NULL); *has_window_open = nemo_file_has_open_window (file); flags = NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM | NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS | NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE | NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP; if (for_drag_accept) { flags |= NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT; } emblem_icons = nemo_file_get_emblem_icons (file, nemo_view_get_directory_as_file (NEMO_VIEW (icon_view))); scale = gtk_widget_get_scale_factor (GTK_WIDGET (icon_view)); icon_info = nemo_file_get_icon (file, size, GET_VIEW_CONSTANT (container, max_text_width_standard), scale, flags); /* apply emblems */ if (emblem_icons != NULL) { gint w, h, s; gboolean bad_ratio; l = emblem_icons; pixbuf = nemo_icon_info_get_pixbuf (icon_info); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); s = MAX (w, h); if (s < size) size = s; bad_ratio = (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > w || (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > h; if (bad_ratio) goto skip_emblem; /* Would prefer to not use goto, but * I don't want to do these checks on * non-emblemed icons (the majority) * as it would be too costly */ emblem = g_emblem_new (l->data); emblemed_icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem); g_object_unref (emblem); for (l = l->next; l != NULL; l = l->next) { emblem = g_emblem_new (l->data); g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (emblemed_icon), emblem); g_object_unref (emblem); } nemo_icon_info_clear (&icon_info); icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); g_object_unref (emblemed_icon); skip_emblem: g_object_unref (pixbuf); } if (emblem_icons != NULL) { g_list_free_full (emblem_icons, g_object_unref); } return icon_info; } static char * nemo_icon_view_grid_container_get_icon_description (NemoIconContainer *container, NemoIconData *data) { NemoFile *file; char *mime_type; const char *description; file = NEMO_FILE (data); g_assert (NEMO_IS_FILE (file)); if (NEMO_IS_DESKTOP_ICON_FILE (file)) { return NULL; } mime_type = nemo_file_get_mime_type (file); description = g_content_type_get_description (mime_type); g_free (mime_type); return g_strdup (description); } static void nemo_icon_view_grid_container_prioritize_thumbnailing (NemoIconContainer *container, NemoIconData *data) { NemoFile *file; char *uri; file = (NemoFile *) data; g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_thumbnailing (file)) { uri = nemo_file_get_uri (file); nemo_thumbnail_prioritize (uri); g_free (uri); } } static void update_auto_strv_as_quarks (GSettings *settings, const gchar *key, gpointer user_data) { GQuark **storage = user_data; int i = 0; char **value; value = g_settings_get_strv (settings, key); g_free (*storage); *storage = g_new (GQuark, g_strv_length (value) + 1); for (i = 0; value[i] != NULL; ++i) { (*storage)[i] = g_quark_from_string (value[i]); } (*storage)[i] = 0; g_strfreev (value); } static int quarkv_length (GQuark *attributes) { int i; i = 0; while (attributes[i] != 0) { i++; } return i; } /** * nemo_icon_view_get_icon_text_attribute_names: * * Get a list representing which text attributes should be displayed * beneath an icon. The result is dependent on zoom level and possibly * user configuration. Don't free the result. * @view: NemoIconView to query. * **/ static GQuark * nemo_icon_view_grid_container_get_icon_text_attribute_names (NemoIconContainer *container, int *len) { int piece_count; /* For now, limit extra attributes to one line - TODO: make this desktop * more flexible at displaying various file info without disturbing grid layout */ piece_count = GRID_VIEW_MAX_ADDITIONAL_ATTRIBUTES; *len = MIN (piece_count, quarkv_length (NEMO_ICON_VIEW_GRID_CONTAINER (container)->attributes)); return NEMO_ICON_VIEW_GRID_CONTAINER (container)->attributes; } /* This callback returns the text, both the editable part, and the * part below that is not editable. */ static void nemo_icon_view_grid_container_get_icon_text (NemoIconContainer *container, NemoIconData *data, char **editable_text, char **additional_text, gboolean *pinned, gboolean include_invisible) { GQuark *attributes; char *text_array[4]; int i, j, num_attributes; NemoIconView *icon_view; NemoFile *file; gboolean use_additional; file = NEMO_FILE (data); g_assert (NEMO_IS_FILE (file)); g_assert (editable_text != NULL); icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); use_additional = (additional_text != NULL); /* Strip the suffix for nemo object xml files. */ *editable_text = nemo_file_get_display_name (file); if (!use_additional) { return; } if (NEMO_IS_DESKTOP_ICON_FILE (file) || nemo_file_is_nemo_link (file)) { /* Don't show the normal extra information for desktop icons, * or desktop files, it doesn't make sense. */ *additional_text = NULL; return; } /* Find out what attributes go below each icon. */ attributes = nemo_icon_view_grid_container_get_icon_text_attribute_names (container, &num_attributes); /* Get the attributes. */ j = 0; for (i = 0; i < num_attributes; ++i) { if (attributes[i] == attribute_none_q) { continue; } text_array[j++] = nemo_file_get_string_attribute_with_default_q (file, attributes[i]); } text_array[j] = NULL; /* Return them. */ if (j == 0) { *additional_text = NULL; } else if (j == 1) { /* Only one item, avoid the strdup + free */ *additional_text = text_array[0]; } else { *additional_text = g_strjoinv ("\n", text_array); for (i = 0; i < j; i++) { g_free (text_array[i]); } } } /* Sort as follows: * 0) computer link * 1) home link * 2) network link * 3) mount links * 4) trash link * 5) other */ typedef enum { SORT_COMPUTER_LINK, SORT_HOME_LINK, SORT_NETWORK_LINK, SORT_MOUNT_LINK, SORT_TRASH_LINK, SORT_OTHER } SortCategory; static SortCategory get_sort_category (NemoFile *file) { NemoDesktopLink *link; SortCategory category; category = SORT_OTHER; if (NEMO_IS_DESKTOP_ICON_FILE (file)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); if (link != NULL) { switch (nemo_desktop_link_get_link_type (link)) { case NEMO_DESKTOP_LINK_COMPUTER: category = SORT_COMPUTER_LINK; break; case NEMO_DESKTOP_LINK_HOME: category = SORT_HOME_LINK; break; case NEMO_DESKTOP_LINK_MOUNT: category = SORT_MOUNT_LINK; break; case NEMO_DESKTOP_LINK_TRASH: category = SORT_TRASH_LINK; break; case NEMO_DESKTOP_LINK_NETWORK: category = SORT_NETWORK_LINK; break; default: category = SORT_OTHER; break; } g_object_unref (link); } } return category; } static int nemo_icon_view_grid_container_compare_icons (NemoIconContainer *container, NemoIconData *data_a, NemoIconData *data_b) { NemoFile *file_a; NemoFile *file_b; NemoIconView *icon_view; SortCategory category_a, category_b; file_a = (NemoFile *) data_a; file_b = (NemoFile *) data_b; icon_view = NEMO_ICON_VIEW (NEMO_ICON_VIEW_GRID_CONTAINER (container)->view); g_return_val_if_fail (icon_view != NULL, 0); category_a = get_sort_category (file_a); category_b = get_sort_category (file_b); if (category_a == category_b) { return nemo_icon_view_compare_files (icon_view, file_a, file_b); } if (category_a < category_b) { return -1; } else { return +1; } } static void nemo_icon_view_grid_container_freeze_updates (NemoIconContainer *container) { NemoIconView *icon_view; icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); nemo_view_freeze_updates (NEMO_VIEW (icon_view)); } static void nemo_icon_view_grid_container_unfreeze_updates (NemoIconContainer *container) { NemoIconView *icon_view; icon_view = get_icon_view (container); g_return_if_fail (icon_view != NULL); nemo_view_unfreeze_updates (NEMO_VIEW (icon_view)); } inline static void nemo_icon_view_grid_container_icon_get_bounding_box (NemoIcon *icon, int *x1_return, int *y1_return, int *x2_return, int *y2_return, NemoIconCanvasItemBoundsUsage usage) { double x1, y1, x2, y2; if (usage == BOUNDS_USAGE_FOR_DISPLAY) { eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item), &x1, &y1, &x2, &y2); } else if (usage == BOUNDS_USAGE_FOR_LAYOUT) { nemo_icon_canvas_item_get_bounds_for_layout (icon->item, &x1, &y1, &x2, &y2); } else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) { nemo_icon_canvas_item_get_bounds_for_entire_item (icon->item, &x1, &y1, &x2, &y2); } else { g_assert_not_reached (); } if (x1_return != NULL) { *x1_return = x1; } if (y1_return != NULL) { *y1_return = y1; } if (x2_return != NULL) { *x2_return = x2; } if (y2_return != NULL) { *y2_return = y2; } } static gboolean get_stored_icon_position (NemoIconContainer *container, NemoIconData *data, NemoIconPosition *position) { NemoFile *file; GdkPoint point; g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (NEMO_IS_FILE (data)); g_assert (position != NULL); file = NEMO_FILE (data); if (nemo_file_get_is_desktop_orphan (file)) { return FALSE; } nemo_file_get_position (file, &point); position->x = point.x; position->y = point.y; position->scale = 1.0; return position->x > ICON_UNPOSITIONED_VALUE; } static void store_new_icon_position (NemoIconContainer *container, NemoIcon *icon, NemoIconPosition position) { gboolean dummy; time_t now; now = time (NULL); g_signal_emit_by_name (container, "icon_position_changed", icon->data, &position); g_signal_emit_by_name (container, "store_layout_timestamp", icon->data, &now, &dummy); } static void snap_position (NemoIconContainer *container, NemoCenteredPlacementGrid *grid, NemoIcon *icon, gint x_in, gint y_in, gint *x_out, gint *y_out) { gint x_new, y_new; gboolean found_empty; GdkRectangle grid_rect; if (nemo_icon_container_is_layout_rtl (container)) { x_in = nemo_icon_container_get_mirror_x_position (container, icon, x_in); } nemo_centered_placement_grid_get_current_position_rect (grid, x_in, y_in, &grid_rect, &found_empty); if (found_empty) { x_new = grid_rect.x; y_new = grid_rect.y; } else { while (!found_empty) { nemo_centered_placement_grid_get_next_position_rect (grid, &grid_rect, &grid_rect, &found_empty); } x_new = grid_rect.x; y_new = grid_rect.y; } *x_out = x_new; *y_out = y_new; if (nemo_icon_container_is_layout_rtl (container)) { *x_out = nemo_icon_container_get_mirror_x_position (container, icon, *x_out); } } static void lay_down_icons_desktop (NemoIconContainer *container, GList *icons) { GList *p, *placed_icons, *unplaced_icons; int total, new_length, placed; NemoIcon *icon; int x, y; gint current_monitor; current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); /* Determine which icons have and have not been placed */ placed_icons = NULL; unplaced_icons = NULL; total = g_list_length (container->details->icons); new_length = g_list_length (icons); placed = total - new_length; if (placed > 0) { NemoCenteredPlacementGrid *grid; /* Add only placed icons in list */ for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; if (nemo_icon_container_icon_is_positioned (icon) && !icon->has_lazy_position) { nemo_icon_container_icon_set_position (container, icon, icon->saved_ltr_x, icon->y); placed_icons = g_list_prepend (placed_icons, icon); } else { icon->x = 0; icon->y = 0; unplaced_icons = g_list_prepend (unplaced_icons, icon); } } placed_icons = g_list_reverse (placed_icons); unplaced_icons = g_list_reverse (unplaced_icons); grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid) { nemo_centered_placement_grid_pre_populate (grid, placed_icons, FALSE); /* Place unplaced icons in the best locations */ for (p = unplaced_icons; p != NULL; p = p->next) { icon = p->data; nemo_centered_placement_grid_icon_position_to_nominal (grid, icon, icon->x, icon->y, &x, &y); snap_position (container, grid, icon, x, y, &x, &y); nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); icon->has_lazy_position = FALSE; icon->saved_ltr_x = x; nemo_centered_placement_grid_mark_icon (grid, icon); } nemo_centered_placement_grid_free (grid); } g_list_free (placed_icons); g_list_free (unplaced_icons); } else { NemoCenteredPlacementGrid *grid; GdkRectangle rect; /* There are no placed icons, or we have auto layout enabled */ grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid != NULL) { nemo_centered_placement_grid_get_current_position_rect (grid, 0, 0, &rect, NULL); while (icons != NULL) { NemoIconPosition position; icon = icons->data; nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, rect.x, rect.y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); icon->saved_ltr_x = icon->x; icon->has_lazy_position = FALSE; icons = icons->next; nemo_centered_placement_grid_mark_icon (grid, icon); nemo_centered_placement_grid_get_next_position_rect (grid, &rect, &rect, NULL); position.x = icon->x; position.y = icon->y; position.scale = 1.0; position.monitor = current_monitor; store_new_icon_position (container, icon, position); } nemo_centered_placement_grid_free (grid); } } if (!container->details->stored_auto_layout) { nemo_icon_container_freeze_icon_positions (container); } } static void nemo_icon_view_grid_container_lay_down_icons (NemoIconContainer *container, GList *icons, double start_y) { lay_down_icons_desktop (container, icons); } static gint order_icons_by_visual_position (gconstpointer a, gconstpointer b, gpointer user_data) { NemoCenteredPlacementGrid *grid; NemoIcon *icon_a, *icon_b; GdkRectangle rect_a, rect_b; grid = (NemoCenteredPlacementGrid *) user_data; icon_a = (NemoIcon*)a; icon_b = (NemoIcon*)b; nemo_centered_placement_grid_get_current_position_rect (grid, (gint) icon_a->x, (gint) icon_a->y, &rect_a, NULL); nemo_centered_placement_grid_get_current_position_rect (grid, (gint) icon_b->x, (gint) icon_b->y, &rect_b, NULL); if (grid->horizontal) { return (rect_a.y == rect_b.y) ? rect_a.x - rect_b.x : rect_a.y - rect_b.y; } else { return (rect_a.x == rect_b.x) ? rect_a.y - rect_b.y : rect_a.x - rect_b.x; } } static void update_visual_selection_state (NemoIconContainer *container) { NemoCenteredPlacementGrid *grid; grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid) { container->details->icons = g_list_sort_with_data (container->details->icons, order_icons_by_visual_position, grid); nemo_centered_placement_grid_free (grid); } } /* x, y are the top-left coordinates of the icon. */ static void nemo_icon_view_grid_container_icon_set_position (NemoIconContainer *container, NemoIcon *icon, double x, double y) { double pixels_per_unit; int container_left, container_top, container_right, container_bottom; int x1, x2, y1, y2; int container_x, container_y, container_width, container_height; EelDRect icon_bounds; GtkAllocation alloc; int item_width, item_height; int height_above, width_left; int min_x, max_x, min_y, max_y; if (icon->x == x && icon->y == y) { return; } if (icon == nemo_icon_container_get_icon_being_renamed (container)) { nemo_icon_container_end_renaming_mode (container, TRUE); } gtk_widget_get_allocation (GTK_WIDGET (container), &alloc); container_x = alloc.x; container_y = alloc.y; container_width = alloc.width - container->details->left_margin - container->details->right_margin; container_height = alloc.height - container->details->top_margin - container->details->bottom_margin; pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit; /* Clip the position of the icon within our desktop bounds */ container_left = container_x / pixels_per_unit; container_top = container_y / pixels_per_unit; container_right = container_left + container_width / pixels_per_unit; container_bottom = container_top + container_height / pixels_per_unit; nemo_icon_container_icon_get_bounding_box (container, icon, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_LAYOUT); item_width = x2 - x1; item_height = y2 - y1; icon_bounds = nemo_icon_canvas_item_get_icon_rectangle (icon->item); /* determine icon rectangle relative to item rectangle */ height_above = icon_bounds.y0 - y1; width_left = icon_bounds.x0 - x1; min_x = container_left + width_left; max_x = container_right - item_width + width_left; x = CLAMP (x, min_x, max_x); min_y = container_top + height_above; max_y = container_bottom - item_height + height_above; y = CLAMP (y, min_y, max_y); if (icon->x == ICON_UNPOSITIONED_VALUE) { icon->x = 0; } if (icon->y == ICON_UNPOSITIONED_VALUE) { icon->y = 0; } eel_canvas_item_move (EEL_CANVAS_ITEM (icon->item), x - icon->x, y - icon->y); icon->x = x; icon->y = y; } static void nemo_icon_view_grid_container_move_icon (NemoIconContainer *container, NemoIcon *icon, int x, int y, double scale, gboolean raise, gboolean snap, gboolean update_position) { NemoIconContainerDetails *details; gboolean emit_signal; NemoIconPosition position; gint current_monitor; current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); details = container->details; emit_signal = FALSE; if (icon == nemo_icon_container_get_icon_being_renamed (container)) { nemo_icon_container_end_renaming_mode (container, TRUE); } if (!details->auto_layout) { if (x != icon->x || y != icon->y) { nemo_icon_container_icon_set_position (container, icon, x, y); emit_signal = update_position; } nemo_icon_view_set_sort_reversed (get_icon_view (container), FALSE, TRUE); icon->saved_ltr_x = nemo_icon_container_is_layout_rtl (container) ? nemo_icon_container_get_mirror_x_position (container, icon, icon->x) : icon->x; } if (emit_signal) { position.x = icon->saved_ltr_x; position.y = icon->y; position.scale = scale; position.monitor = current_monitor; g_signal_emit_by_name (container, "icon_position_changed", icon->data, &position); } if (raise) { nemo_icon_container_icon_raise (container, icon); } if (!container->details->auto_layout) { update_visual_selection_state (container); } } static void nemo_icon_view_grid_container_update_icon (NemoIconContainer *container, NemoIcon *icon) { NemoIconContainerDetails *details; guint icon_size; NemoIconInfo *icon_info; GdkPixbuf *pixbuf; char *editable_text, *additional_text; gboolean has_open_window; gint scale_factor; EelIRect old_size, new_size; gint old_width, new_width; if (icon == NULL) { return; } details = container->details; nemo_icon_canvas_item_get_icon_canvas_rectangle (icon->item, &old_size); /* Get the appropriate images for the file. */ icon_size = container->details->forced_icon_size; DEBUG ("Icon size for desktop grid, getting for size %d", icon_size); /* Get the icons. */ icon_info = nemo_icon_container_get_icon_images (container, icon->data, icon_size, icon == details->drop_target, &has_open_window); scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (container)); pixbuf = nemo_icon_info_get_desktop_pixbuf_at_size (icon_info, icon_size * scale_factor, GET_VIEW_CONSTANT (container, max_text_width_standard)); nemo_icon_info_unref (icon_info); nemo_icon_container_get_icon_text (container, icon->data, &editable_text, &additional_text, NULL, FALSE); /* If name of icon being renamed was changed from elsewhere, end renaming mode. * Alternatively, we could replace the characters in the editable text widget * with the new name, but that could cause timing problems if the user just * happened to be typing at that moment. */ if (icon == nemo_icon_container_get_icon_being_renamed (container) && g_strcmp0 (editable_text, nemo_icon_canvas_item_get_editable_text (icon->item)) != 0) { nemo_icon_container_end_renaming_mode (container, FALSE); } eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item), "editable_text", editable_text, "additional_text", additional_text, "highlighted_for_drop", icon == details->drop_target, NULL); nemo_icon_canvas_item_set_image (icon->item, pixbuf); nemo_icon_canvas_item_get_icon_canvas_rectangle (icon->item, &new_size); old_width = old_size.x1 - old_size.x0; new_width = new_size.x1 - new_size.x0; if (old_width != 0 && old_width != new_width) { gint diff; diff = (new_width - old_width) / 2; nemo_icon_container_move_icon (container, icon, (int)icon->x - diff, (int)icon->y, 1.0, FALSE, TRUE, TRUE); nemo_icon_canvas_item_invalidate_label_size (icon->item); gtk_widget_queue_draw (GTK_WIDGET(container)); } /* Let the pixbufs go. */ g_object_unref (pixbuf); g_free (editable_text); g_free (additional_text); } static void nemo_icon_view_grid_container_align_icons (NemoIconContainer *container) { NemoCenteredPlacementGrid *grid; GList *unplaced_icons, *old_list; GList *l; gint current_monitor; grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid == NULL) { return; } current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); unplaced_icons = g_list_copy (container->details->icons); unplaced_icons = g_list_sort_with_data (unplaced_icons, order_icons_by_visual_position, grid); if (nemo_icon_container_is_layout_rtl (container)) { unplaced_icons = g_list_reverse (unplaced_icons); } for (l = unplaced_icons; l != NULL; l = l->next) { NemoIcon *icon; NemoIconPosition position; int x, y; icon = l->data; nemo_centered_placement_grid_icon_position_to_nominal (grid, icon, icon->saved_ltr_x, icon->y, &x, &y); snap_position (container, grid, icon, x, y, &x, &y); nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); icon->saved_ltr_x = icon->x; nemo_centered_placement_grid_mark_icon (grid, icon); position.x = icon->x; position.y = icon->y; position.scale = 1.0; position.monitor = current_monitor; store_new_icon_position (container, icon, position); } nemo_centered_placement_grid_free (grid); old_list = container->details->icons; container->details->icons = unplaced_icons; g_list_free (old_list); if (nemo_icon_container_is_layout_rtl (container)) { nemo_icon_container_set_rtl_positions (container); } update_visual_selection_state (container); } static void nemo_icon_view_grid_container_reload_icon_positions (NemoIconContainer *container) { GList *p, *no_position_icons; NemoIcon *icon; gboolean have_stored_position; NemoIconPosition position; g_assert (!container->details->auto_layout); nemo_icon_container_resort (container); no_position_icons = NULL; /* Place all the icons with positions. */ for (p = container->details->icons; p != NULL; p = p->next) { icon = p->data; have_stored_position = get_stored_icon_position (container, icon->data, &position); if (have_stored_position) { nemo_icon_container_icon_set_position (container, icon, position.x, position.y); } else { no_position_icons = g_list_prepend (no_position_icons, icon); } } no_position_icons = g_list_reverse (no_position_icons); /* Place all the other icons. */ NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, no_position_icons, 0); g_list_free (no_position_icons); } static gboolean assign_icon_position (NemoIconContainer *container, NemoIcon *icon) { gboolean have_stored_position; NemoIconPosition position; /* Get the stored position. */ have_stored_position = FALSE; position.scale = 1.0; have_stored_position = get_stored_icon_position (container, icon->data, &position); icon->scale = position.scale; if (!container->details->auto_layout) { if (have_stored_position) { nemo_icon_container_icon_set_position (container, icon, position.x, position.y); icon->saved_ltr_x = icon->x; } else { return FALSE; } } return TRUE; } static void nemo_icon_view_grid_container_finish_adding_new_icons (NemoIconContainer *container) { GList *p, *new_icons, *no_position_icons, *semi_position_icons; NemoIcon *icon; gint current_monitor; current_monitor = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (container)); update_layout_constants (container); update_visual_selection_state (container); new_icons = container->details->new_icons; container->details->new_icons = NULL; /* Position most icons (not unpositioned manual-layout icons). */ new_icons = g_list_reverse (new_icons); no_position_icons = semi_position_icons = NULL; for (p = new_icons; p != NULL; p = p->next) { icon = p->data; nemo_icon_container_update_icon (container, icon); if (!container->details->auto_layout && (icon->has_lazy_position || nemo_icon_container_icon_is_new_for_monitor (container, icon, current_monitor))) { assign_icon_position (container, icon); semi_position_icons = g_list_prepend (semi_position_icons, icon); } else if (!assign_icon_position (container, icon)) { no_position_icons = g_list_prepend (no_position_icons, icon); } nemo_icon_container_finish_adding_icon (container, icon); } g_list_free (new_icons); if (semi_position_icons != NULL) { NemoCenteredPlacementGrid *grid; g_assert (!container->details->auto_layout); semi_position_icons = g_list_reverse (semi_position_icons); /* This is currently only used on the desktop. * Thus, we pass FALSE for tight, like lay_down_icons_tblr */ grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid == NULL) { return; } nemo_centered_placement_grid_pre_populate (grid, container->details->icons, TRUE); for (p = semi_position_icons; p != NULL; p = p->next) { NemoIconPosition position; int x, y; icon = p->data; nemo_centered_placement_grid_icon_position_to_nominal (grid, icon, icon->x, icon->y, &x, &y); snap_position (container, grid, icon, x, y, &x, &y); nemo_centered_placement_grid_nominal_to_icon_position (grid, icon, x, y, &x, &y); nemo_icon_container_icon_set_position (container, icon, x, y); position.x = icon->x; position.y = icon->y; position.scale = icon->scale; position.monitor = current_monitor; nemo_centered_placement_grid_mark_icon (grid, icon); store_new_icon_position (container, icon, position); /* ensure that next time we run this code, the formerly semi-positioned * icons are treated as being positioned. */ icon->has_lazy_position = FALSE; } nemo_centered_placement_grid_free (grid); g_list_free (semi_position_icons); } /* Position the unpositioned manual layout icons. */ if (no_position_icons != NULL) { g_assert (!container->details->auto_layout); nemo_icon_container_sort_icons (container, &no_position_icons); NEMO_ICON_CONTAINER_GET_CLASS (container)->lay_down_icons (container, no_position_icons, 0); g_list_free (no_position_icons); } if (container->details->store_layout_timestamps_when_finishing_new_icons) { nemo_icon_container_store_layout_timestamps_now (container); container->details->store_layout_timestamps_when_finishing_new_icons = FALSE; } } static gboolean should_place_before (gint x, gint y, GdkRectangle *rect, gboolean horizontal) { gint half_x, half_y; half_x = rect->x + (rect->width / 2); half_y = rect->y + (rect->height / 2); if (horizontal) { return x < half_x; } else { return y < half_y; } return FALSE; } static void draw_insert_stroke (cairo_t *cr, gint draw_x, gint draw_y, gint draw_distance_x, gint draw_distance_y) { GdkRGBA shadow_rgba = { 0, 0, 0, 1.0 }; GdkRGBA fore_rgba = { 1.0, 1.0, 1.0, 1.0}; cairo_set_antialias (cr, CAIRO_ANTIALIAS_BEST); cairo_save (cr); cairo_set_line_width (cr, 1.0); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); gdk_cairo_set_source_rgba (cr, &shadow_rgba); cairo_move_to (cr, draw_x, draw_y); cairo_line_to (cr, draw_x + draw_distance_x, draw_y + draw_distance_y); cairo_stroke (cr); cairo_restore (cr); draw_x--; draw_y--; cairo_save (cr); cairo_set_line_width (cr, 1.0); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); gdk_cairo_set_source_rgba (cr, &fore_rgba); cairo_move_to (cr, draw_x, draw_y); cairo_line_to (cr, draw_x + draw_distance_x, draw_y + draw_distance_y); cairo_stroke (cr); cairo_restore (cr); } static void nemo_icon_view_grid_container_draw_background (EelCanvas *canvas, cairo_t *cr) { NemoIconContainer *container; NemoIcon *target_icon; // GtkAllocation allocation; gboolean before; container = NEMO_ICON_CONTAINER (canvas); if (DEBUGGING) { NemoCenteredPlacementGrid *grid; grid = nemo_centered_placement_grid_new (container, container->details->horizontal); if (grid != NULL) { GdkRectangle grid_rect; gint count; GdkRGBA grid_color = { 1.0, 1.0, 1.0, 0.4}; count = 0; cairo_save (cr); gdk_cairo_set_source_rgba (cr, &grid_color); cairo_set_line_width (cr, 1.0); nemo_centered_placement_grid_get_current_position_rect (grid, 0, 0, &grid_rect, NULL); while (count < grid->num_rows * grid->num_columns) { GdkRectangle draw_rect; draw_rect.x = grid_rect.x + container->details->left_margin; draw_rect.y = grid_rect.y + container->details->top_margin; draw_rect.width = grid_rect.width; draw_rect.height = grid_rect.height; gdk_cairo_rectangle (cr, &draw_rect); nemo_centered_placement_grid_get_next_position_rect (grid, &grid_rect, &grid_rect, NULL); count++; } } nemo_centered_placement_grid_free (grid); cairo_stroke (cr); cairo_restore (cr); } if (!container->details->insert_dnd_mode || container->details->dnd_info->drag_info.data_type != NEMO_ICON_DND_GNOME_ICON_LIST) { return; } target_icon = container->details->drop_target; if (target_icon == NULL) { NemoCenteredPlacementGrid *grid; GdkRectangle grid_rect; gint grid_cs_x, grid_cs_y; gint draw_x, draw_y, draw_distance_x, draw_distance_y; gboolean is_free; grid = container->details->dnd_grid; /* Canvas draw vfunc encompasses the margins. The placement grid coord system * does not - grid x and y are relative to the inside corner of the top and left canvas * margins. So we have to shift and then unshift by the margins here. The grid functions * will handle any grid padding calculations (grid->borders). */ grid_cs_x = container->details->current_dnd_x - container->details->left_margin; grid_cs_y = container->details->current_dnd_y - container->details->top_margin; nemo_centered_placement_grid_get_current_position_rect (grid, grid_cs_x, grid_cs_y, &grid_rect, &is_free); grid_rect.x += container->details->left_margin; grid_rect.y += container->details->top_margin; if (DEBUGGING) { GdkRGBA active_rect_color = { 0.5, 0.5, 0.5, 0.4}; cairo_save (cr); gdk_cairo_set_source_rgba (cr, &active_rect_color); gdk_cairo_rectangle (cr, &grid_rect); cairo_fill (cr); cairo_restore (cr); } before = should_place_before (container->details->current_dnd_x, container->details->current_dnd_y, &grid_rect, container->details->horizontal); if (container->details->horizontal) { if (!is_free && before) { draw_x = grid_rect.x; draw_y = grid_rect.y + (grid_rect.height * .2); draw_distance_x = 0; draw_distance_y = grid_rect.height * .6; draw_insert_stroke (cr, draw_x, draw_y, draw_distance_x, draw_distance_y); } if (!is_free && !before) { draw_x = grid_rect.x + grid_rect.width; draw_y = grid_rect.y + (grid_rect.height * .2); draw_distance_x = 0; draw_distance_y = grid_rect.height * .6; draw_insert_stroke (cr, draw_x, draw_y, draw_distance_x, draw_distance_y); } } else { if (!is_free && before) { draw_x = grid_rect.x + (grid_rect.width * .2); draw_y = grid_rect.y; draw_distance_x = grid_rect.width * .6; draw_distance_y = 0; draw_insert_stroke (cr, draw_x, draw_y, draw_distance_x, draw_distance_y); } if (!is_free && !before) { draw_x = grid_rect.x + (grid_rect.width * .2); draw_y = grid_rect.y + grid_rect.height; draw_distance_x = grid_rect.width * .6; draw_distance_y = 0; draw_insert_stroke (cr, draw_x, draw_y, draw_distance_x, draw_distance_y); } } } } #define BASE_SNAP_SIZE_X 130.0 #define BASE_SNAP_SIZE_Y 100.0 #define BASE_MAX_TEXT_WIDTH 120.0 /* from nemo-icon-canvas-item.c */ #define LABEL_OFFSET 1 static gint get_vertical_adjustment (NemoIconContainer *container, gint icon_size) { PangoLayout *layout; PangoContext *context; PangoFontDescription *desc; gint ellipsis_limit; gint height; ellipsis_limit = g_settings_get_int (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT); layout = gtk_widget_create_pango_layout (GTK_WIDGET (container), "Test"); if (container->details->font && g_strcmp0 (container->details->font, "") != 0) { desc = pango_font_description_from_string (container->details->font); } else { context = gtk_widget_get_pango_context (GTK_WIDGET (container)); desc = pango_font_description_copy (pango_context_get_font_description (context)); } if (pango_font_description_get_size (desc) > 0) { pango_font_description_set_size (desc, pango_font_description_get_size (desc) + container->details->font_size_table [container->details->zoom_level]); } pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); pango_layout_get_pixel_size (layout, NULL, &height); g_object_unref (layout); height *= ellipsis_limit; height += icon_size + GET_VIEW_CONSTANT (container, icon_pad_bottom) + LABEL_OFFSET; return height / 2; } static void update_layout_constants (NemoIconContainer *container) { gint icon_size, ellipsis_pref; NemoViewLayoutConstants *constants; gdouble scale, h_adjust, v_adjust; update_auto_strv_as_quarks (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, &(NEMO_ICON_VIEW_GRID_CONTAINER (container)->attributes)); ellipsis_pref = g_settings_get_int (nemo_desktop_preferences, NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT); NEMO_ICON_VIEW_GRID_CONTAINER (container)->text_ellipsis_limit = ellipsis_pref; icon_size = nemo_get_desktop_icon_size_for_zoom_level (container->details->zoom_level); scale = (double) icon_size / NEMO_DESKTOP_ICON_SIZE_STANDARD; h_adjust = container->details->h_adjust / 100.0; v_adjust = container->details->v_adjust / 100.0; constants = container->details->view_constants; constants->snap_size_x = BASE_SNAP_SIZE_X * scale * h_adjust; constants->snap_size_y = BASE_SNAP_SIZE_Y * scale * v_adjust; constants->max_text_width_standard = BASE_MAX_TEXT_WIDTH * scale * h_adjust; constants->icon_vertical_adjust = MIN (get_vertical_adjustment (container, icon_size), constants->snap_size_y / 2); /* This isn't what this is intended for, but it's a simple way vs. overriding what * icon_get_size() uses to get the icon size in nemo-icon-container.c (it should use * nemo_get_desktop_icon_size_for_zoom_level) */ nemo_icon_container_set_forced_icon_size (container, icon_size); gtk_widget_queue_draw (GTK_WIDGET (container)); } static void nemo_icon_view_grid_container_set_zoom_level (NemoIconContainer *container, gint new_level) { NemoIconContainerDetails *details; int pinned_level; details = container->details; nemo_icon_container_end_renaming_mode (container, TRUE); pinned_level = new_level; if (pinned_level < NEMO_ZOOM_LEVEL_SMALLEST) { pinned_level = NEMO_ZOOM_LEVEL_SMALLEST; } else if (pinned_level > NEMO_ZOOM_LEVEL_LARGEST) { pinned_level = NEMO_ZOOM_LEVEL_LARGEST; } if (pinned_level == details->zoom_level) { return; } details->zoom_level = pinned_level; eel_canvas_set_pixels_per_unit (EEL_CANVAS (container), 1.0); } static void desktop_text_ellipsis_limit_changed_callback (NemoIconContainer *container) { nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } static gint get_layout_adjust_for_additional_attributes (NemoIconContainer *container) { GQuark *attrs; gint length; attrs = nemo_icon_view_grid_container_get_icon_text_attribute_names (container, &length); if (length == 0) { return 0; } if (attrs[0] == attribute_none_q) { return 0; } return GRID_VIEW_MAX_ADDITIONAL_ATTRIBUTES; } static gint nemo_icon_view_grid_container_get_max_layout_lines_for_pango (NemoIconContainer *container) { int limit; limit = MAX (1, NEMO_ICON_VIEW_GRID_CONTAINER (container)->text_ellipsis_limit - get_layout_adjust_for_additional_attributes (container)); if (limit <= 0) { return G_MININT; } return -limit; } static gint nemo_icon_view_grid_container_get_max_layout_lines (NemoIconContainer *container) { int limit; limit = MAX (1, NEMO_ICON_VIEW_GRID_CONTAINER (container)->text_ellipsis_limit - get_layout_adjust_for_additional_attributes (container)); if (limit <= 0) { return G_MAXINT; } return limit; } static void captions_changed_callback (NemoIconContainer *container) { update_auto_strv_as_quarks (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, &(NEMO_ICON_VIEW_GRID_CONTAINER (container)->attributes)); nemo_icon_container_invalidate_labels (container); nemo_icon_container_request_update_all (container); } static gchar * on_get_tooltip_text (NemoIconContainer *container, NemoFile *file, gpointer user_data) { gchar *tooltip_text = NULL; if (container->details->show_desktop_tooltips) { tooltip_text = nemo_file_construct_tooltip (file, container->details->tooltip_flags); } return tooltip_text; } static void nemo_icon_view_grid_container_icon_added (NemoIconViewGridContainer *container, NemoIconData *icon_data, gpointer data) { } static void nemo_icon_view_grid_container_icon_removed (NemoIconViewGridContainer *container, NemoIconData *icon_data, gpointer data) { } NemoIconContainer * nemo_icon_view_grid_container_construct (NemoIconViewGridContainer *icon_container, NemoIconView *view, gboolean is_desktop) { AtkObject *atk_obj; NemoViewLayoutConstants *constants = NEMO_ICON_CONTAINER (icon_container)->details->view_constants; g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NULL); icon_container->view = view; nemo_icon_container_set_is_desktop (NEMO_ICON_CONTAINER (icon_container), is_desktop); atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_container)); atk_object_set_name (atk_obj, _("Icon View")); constants = NEMO_ICON_CONTAINER (icon_container)->details->view_constants; constants->icon_pad_left = 4; constants->icon_pad_right = 4; constants->icon_pad_top = 4; constants->icon_pad_bottom = 4; constants->container_pad_left = 4; constants->container_pad_right = 4; constants->container_pad_top = 4; constants->container_pad_bottom = 4; constants->standard_icon_grid_width = 155; // Not used constants->text_beside_icon_grid_width = 205; // Not used constants->desktop_pad_horizontal = 10; // Not used constants->desktop_pad_vertical = 10; // Not used constants->snap_size_x = BASE_SNAP_SIZE_X; constants->snap_size_y = BASE_SNAP_SIZE_Y; constants->max_text_width_standard = BASE_MAX_TEXT_WIDTH; constants->max_text_width_beside = 90; // Not used constants->max_text_width_beside_top_to_bottom = 150; // Not used constants->icon_vertical_adjust = 20; g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (desktop_text_ellipsis_limit_changed_callback), NEMO_ICON_CONTAINER (icon_container)); g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, G_CALLBACK (captions_changed_callback), NEMO_ICON_CONTAINER (icon_container)); g_signal_connect (icon_container, "get-tooltip-text", G_CALLBACK (on_get_tooltip_text), NULL); return NEMO_ICON_CONTAINER (icon_container); } static void finalize (GObject *object) { g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, desktop_text_ellipsis_limit_changed_callback, object); g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, captions_changed_callback, object); G_OBJECT_CLASS (nemo_icon_view_grid_container_parent_class)->finalize (object); } static void nemo_icon_view_grid_container_class_init (NemoIconViewGridContainerClass *klass) { NemoIconContainerClass *ic_class; ic_class = &klass->parent_class; attribute_none_q = g_quark_from_static_string ("none"); G_OBJECT_CLASS (klass)->finalize = finalize; ic_class->is_grid_container = TRUE; ic_class->get_icon_text = nemo_icon_view_grid_container_get_icon_text; ic_class->get_icon_images = nemo_icon_view_grid_container_get_icon_images; ic_class->get_icon_description = nemo_icon_view_grid_container_get_icon_description; ic_class->prioritize_thumbnailing = nemo_icon_view_grid_container_prioritize_thumbnailing; ic_class->get_max_layout_lines_for_pango = nemo_icon_view_grid_container_get_max_layout_lines_for_pango; ic_class->get_max_layout_lines = nemo_icon_view_grid_container_get_max_layout_lines; ic_class->compare_icons = nemo_icon_view_grid_container_compare_icons; ic_class->freeze_updates = nemo_icon_view_grid_container_freeze_updates; ic_class->unfreeze_updates = nemo_icon_view_grid_container_unfreeze_updates; ic_class->lay_down_icons = nemo_icon_view_grid_container_lay_down_icons; ic_class->icon_set_position = nemo_icon_view_grid_container_icon_set_position; ic_class->move_icon = nemo_icon_view_grid_container_move_icon; ic_class->update_icon = nemo_icon_view_grid_container_update_icon; ic_class->align_icons = nemo_icon_view_grid_container_align_icons; ic_class->reload_icon_positions = nemo_icon_view_grid_container_reload_icon_positions; ic_class->finish_adding_new_icons = nemo_icon_view_grid_container_finish_adding_new_icons; ic_class->icon_get_bounding_box = nemo_icon_view_grid_container_icon_get_bounding_box; ic_class->set_zoom_level = nemo_icon_view_grid_container_set_zoom_level; g_signal_override_class_handler ("icon_added", NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, G_CALLBACK (nemo_icon_view_grid_container_icon_added)); g_signal_override_class_handler ("icon_removed", NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, G_CALLBACK (nemo_icon_view_grid_container_icon_removed)); EEL_CANVAS_CLASS (klass)->draw_background = nemo_icon_view_grid_container_draw_background; } static void nemo_icon_view_grid_container_init (NemoIconViewGridContainer *icon_container) { gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (icon_container)), GTK_STYLE_CLASS_VIEW); NEMO_ICON_CONTAINER (icon_container)->details->font_size_table[NEMO_ZOOM_LEVEL_SMALL] = -1 * PANGO_SCALE; NEMO_ICON_CONTAINER (icon_container)->details->font_size_table[NEMO_ZOOM_LEVEL_LARGE] = 1 * PANGO_SCALE; icon_container->text_ellipsis_limit = 2; } NemoIconContainer * nemo_icon_view_grid_container_new (NemoIconView *view, gboolean is_desktop) { return nemo_icon_view_grid_container_construct (g_object_new (NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, NULL), view, is_desktop); } void nemo_icon_view_grid_container_set_sort_desktop (NemoIconViewGridContainer *container, gboolean desktop) { container->sort_for_desktop = desktop; } nemo-4.4.2/src/nemo-icon-view-grid-container.h000066400000000000000000000065401357442400300211650ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* fm-icon-container.h - the container widget for file manager icons Copyright (C) 2002 Sun Microsystems, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Author: Michael Meeks */ #ifndef NEMO_ICON_VIEW_GRID_CONTAINER_H #define NEMO_ICON_VIEW_GRID_CONTAINER_H #include "nemo-icon-view.h" #include typedef struct NemoIconViewGridContainer NemoIconViewGridContainer; typedef struct NemoIconViewGridContainerClass NemoIconViewGridContainerClass; #define NEMO_TYPE_ICON_VIEW_GRID_CONTAINER nemo_icon_view_grid_container_get_type() #define NEMO_ICON_VIEW_GRID_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, NemoIconViewGridContainer)) #define NEMO_ICON_VIEW_GRID_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, NemoIconViewGridContainerClass)) #define NEMO_IS_ICON_VIEW_GRID_CONTAINER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ICON_VIEW_GRID_CONTAINER)) #define NEMO_IS_ICON_VIEW_GRID_CONTAINER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ICON_VIEW_GRID_CONTAINER)) #define NEMO_ICON_VIEW_GRID_CONTAINER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ICON_VIEW_GRID_CONTAINER, NemoIconViewGridContainerClass)) typedef struct NemoIconViewGridContainerDetails NemoIconViewGridContainerDetails; struct NemoIconViewGridContainer { NemoIconContainer parent; NemoIconView *view; gboolean sort_for_desktop; gboolean horizontal; gboolean manual_sort_dirty; gint text_ellipsis_limit; GQuark *attributes; }; struct NemoIconViewGridContainerClass { NemoIconContainerClass parent_class; }; GType nemo_icon_view_grid_container_get_type (void); NemoIconContainer *nemo_icon_view_grid_container_construct (NemoIconViewGridContainer *icon_container, NemoIconView *view, gboolean is_desktop); NemoIconContainer *nemo_icon_view_grid_container_new (NemoIconView *view, gboolean is_desktop); void nemo_icon_view_grid_container_set_sort_desktop (NemoIconViewGridContainer *container, gboolean desktop); #endif /* NEMO_ICON_VIEW_GRID_CONTAINER_H */ nemo-4.4.2/src/nemo-icon-view.c000066400000000000000000002575431357442400300162700ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-icon-view.c - implementation of icon view of directory. Copyright (C) 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan */ #include #include "nemo-icon-view.h" #include "nemo-actions.h" #include "nemo-icon-view-container.h" #include "nemo-icon-view-grid-container.h" #include "nemo-error-reporting.h" #include "nemo-view-dnd.h" #include "nemo-view-factory.h" #include "nemo-window.h" #include "nemo-desktop-window.h" #include "nemo-desktop-manager.h" #include "nemo-application.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_ICON_VIEW #include #include #include #include #include #include #include #define POPUP_PATH_ICON_APPEARANCE "/selection/Icon Appearance Items" enum { PROP_COMPACT = 1, PROP_SUPPORTS_AUTO_LAYOUT, PROP_IS_DESKTOP, PROP_SUPPORTS_KEEP_ALIGNED, PROP_SUPPORTS_LABELS_BESIDE_ICONS, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; typedef struct { const NemoFileSortType sort_type; const char *metadata_text; const char *action; const char *menu_label; const char *menu_hint; } SortCriterion; typedef enum { MENU_ITEM_TYPE_STANDARD, MENU_ITEM_TYPE_CHECK, MENU_ITEM_TYPE_RADIO, MENU_ITEM_TYPE_TREE } MenuItemType; struct NemoIconViewDetails { GList *icons_not_positioned; guint react_to_icon_change_idle_id; const SortCriterion *sort; gboolean sort_reversed; GtkActionGroup *icon_action_group; guint icon_merge_id; gboolean compact; gulong clipboard_handler_id; GtkWidget *icon_container; gboolean supports_auto_layout; gboolean is_desktop; gboolean supports_keep_aligned; gboolean supports_labels_beside_icons; }; /* Note that the first item in this list is the default sort, * and that the items show up in the menu in the order they * appear in this list. */ static const SortCriterion sort_criteria[] = { { NEMO_FILE_SORT_BY_DISPLAY_NAME, "name", "Sort by Name", N_("by _Name"), N_("Keep icons sorted by name in rows") }, { NEMO_FILE_SORT_BY_SIZE, "size", "Sort by Size", N_("by _Size"), N_("Keep icons sorted by size in rows") }, { NEMO_FILE_SORT_BY_TYPE, "type", "Sort by Type", N_("by _Type"), N_("Keep icons sorted by type in rows") }, { NEMO_FILE_SORT_BY_DETAILED_TYPE, "detailed_type", "Sort by Detailed Type", N_("by _Detailed Type"), N_("Keep icons sorted by detailed type in rows") }, { NEMO_FILE_SORT_BY_MTIME, "modification date", "Sort by Modification Date", N_("by Modification _Date"), N_("Keep icons sorted by modification date in rows") }, { NEMO_FILE_SORT_BY_TRASHED_TIME, "trashed", "Sort by Trash Time", N_("by T_rash Time"), N_("Keep icons sorted by trash time in rows") } }; static void nemo_icon_view_set_directory_sort_by (NemoIconView *icon_view, NemoFile *file, const char *sort_by); static void nemo_icon_view_set_zoom_level (NemoIconView *view, NemoZoomLevel new_level, gboolean always_emit); static void nemo_icon_view_update_click_mode (NemoIconView *icon_view); static void nemo_icon_view_update_click_to_rename_mode (NemoIconView *icon_view); static gboolean nemo_icon_view_is_desktop (NemoIconView *icon_view); static void nemo_icon_view_reveal_selection (NemoView *view); static const SortCriterion *get_sort_criterion_by_sort_type (NemoFileSortType sort_type); static void switch_to_manual_layout (NemoIconView *view); static void update_layout_menus (NemoIconView *view); static NemoFileSortType get_default_sort_order (NemoFile *file, gboolean *reversed); static void nemo_icon_view_clear_full (NemoView *view, gboolean destroying); static const SortCriterion *get_sort_criterion_by_metadata_text (const char *metadata_text); static void nemo_icon_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory); G_DEFINE_TYPE (NemoIconView, nemo_icon_view, NEMO_TYPE_VIEW); static void nemo_icon_view_destroy (GtkWidget *object) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (object); nemo_icon_view_clear_full (NEMO_VIEW (object), TRUE); if (icon_view->details->react_to_icon_change_idle_id != 0) { g_source_remove (icon_view->details->react_to_icon_change_idle_id); icon_view->details->react_to_icon_change_idle_id = 0; } if (icon_view->details->clipboard_handler_id != 0) { g_signal_handler_disconnect (nemo_clipboard_monitor_get (), icon_view->details->clipboard_handler_id); icon_view->details->clipboard_handler_id = 0; } if (icon_view->details->icons_not_positioned) { nemo_file_list_free (icon_view->details->icons_not_positioned); icon_view->details->icons_not_positioned = NULL; } GTK_WIDGET_CLASS (nemo_icon_view_parent_class)->destroy (object); } static void sync_directory_monitor_number (NemoIconView *view, NemoFile *file) { NemoDirectory *directory; NemoDesktopWindow *desktop_window; gint monitor; if (!view->details->is_desktop) { return; } desktop_window = NEMO_DESKTOP_WINDOW (nemo_view_get_nemo_window (NEMO_VIEW (view))); monitor = nemo_desktop_window_get_monitor (desktop_window); directory = nemo_view_get_model (NEMO_VIEW (view)); NEMO_DESKTOP_DIRECTORY (directory)->display_number = monitor; } static NemoIconContainer * get_icon_container (NemoIconView *icon_view) { return NEMO_ICON_CONTAINER (icon_view->details->icon_container); } NemoIconContainer * nemo_icon_view_get_icon_container (NemoIconView *icon_view) { return get_icon_container (icon_view); } static gboolean nemo_icon_view_supports_manual_layout (NemoIconView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return !nemo_icon_view_is_compact (view); } static void real_set_sort_criterion (NemoIconView *icon_view, const SortCriterion *sort, gboolean clear, gboolean set_metadata) { NemoFile *file; file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); sync_directory_monitor_number (icon_view, file); if (clear) { nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_BY, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED, NULL, NULL); icon_view->details->sort = get_sort_criterion_by_sort_type (get_default_sort_order (file, &icon_view->details->sort_reversed)); } else if (set_metadata) { /* Store the new sort setting. */ nemo_icon_view_set_directory_sort_by (icon_view, file, sort->metadata_text); } /* Update the layout menus to match the new sort setting. */ update_layout_menus (icon_view); } static void set_sort_criterion (NemoIconView *icon_view, const SortCriterion *sort, gboolean set_metadata) { if (sort == NULL || icon_view->details->sort == sort) { return; } icon_view->details->sort = sort; real_set_sort_criterion (icon_view, sort, FALSE, set_metadata); } static void clear_sort_criterion (NemoIconView *icon_view) { real_set_sort_criterion (icon_view, NULL, TRUE, TRUE); } static void nemo_icon_view_clean_up (NemoIconView *icon_view) { NemoIconContainer *icon_container; gboolean saved_sort_reversed; icon_container = get_icon_container (icon_view); /* Hardwire Clean Up to always be by name, in forward order */ saved_sort_reversed = icon_view->details->sort_reversed; nemo_icon_view_set_sort_reversed (icon_view, FALSE, FALSE); set_sort_criterion (icon_view, &sort_criteria[0], FALSE); nemo_icon_container_sort (icon_container); nemo_icon_container_freeze_icon_positions (icon_container); nemo_icon_view_set_sort_reversed (icon_view, saved_sort_reversed, FALSE); } static void action_clean_up_callback (GtkAction *action, gpointer callback_data) { nemo_icon_view_clean_up (NEMO_ICON_VIEW (callback_data)); } static gboolean nemo_icon_view_using_auto_layout (NemoIconView *icon_view) { return nemo_icon_container_is_auto_layout (get_icon_container (icon_view)); } static void action_sort_radio_callback (GtkAction *action, GtkRadioAction *current, NemoIconView *view) { NemoFileSortType sort_type; sort_type = gtk_radio_action_get_current_value (current); /* Note that id might be a toggle item. * Ignore non-sort ids so that they don't cause sorting. */ if (sort_type == NEMO_FILE_SORT_NONE) { switch_to_manual_layout (view); } else { nemo_icon_view_set_sort_criterion_by_sort_type (view, sort_type); } } static void list_covers (NemoIconData *data, gpointer callback_data) { GSList **file_list; file_list = callback_data; *file_list = g_slist_prepend (*file_list, data); } static void unref_cover (NemoIconData *data, gpointer callback_data) { nemo_file_unref (NEMO_FILE (data)); } static void nemo_icon_view_clear_full (NemoView *view, gboolean destroying) { NemoIconContainer *icon_container; GSList *file_list; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); icon_container = get_icon_container (NEMO_ICON_VIEW (view)); if (!icon_container) return; /* Clear away the existing icons. */ file_list = NULL; nemo_icon_container_for_each (icon_container, list_covers, &file_list); nemo_icon_container_clear (icon_container); if (!destroying) { nemo_icon_container_update_scroll_region (icon_container); } g_slist_foreach (file_list, (GFunc)unref_cover, NULL); g_slist_free (file_list); } static void nemo_icon_view_clear (NemoView *view) { nemo_icon_view_clear_full (view, FALSE); } static gboolean should_show_file_on_screen (NemoView *view, NemoFile *file) { if (!nemo_view_should_show_file (view, file)) { return FALSE; } return TRUE; } static void nemo_icon_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; /* This used to assert that 'directory == nemo_view_get_model (view)', but that * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens. * It seems that somehow we get a files_changed event sent to the view from a directory * that isn't the model, but the code disables the monitor and signal callback handlers when * changing directories. Maybe we can get some more information when this happens. * Further discussion in bug #368178. */ if (directory != nemo_view_get_model (view)) { char *file_uri, *dir_uri, *model_uri; file_uri = nemo_file_get_uri (file); dir_uri = nemo_directory_get_uri (directory); model_uri = nemo_directory_get_uri (nemo_view_get_model (view)); g_warning ("nemo_icon_view_remove_file() - directory not icon view model, shouldn't happen.\n" "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n" "If you see this, please add this info to http://bugzilla.gnome.org/show_bug.cgi?id=368178", file, file_uri, directory, dir_uri, nemo_view_get_model (view), model_uri, nemo_view_get_loading (view)); g_free (file_uri); g_free (dir_uri); g_free (model_uri); } icon_view = NEMO_ICON_VIEW (view); if (nemo_icon_container_remove (get_icon_container (icon_view), NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_unref (file); } } static void nemo_icon_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; NemoIconContainer *icon_container; g_assert (directory == nemo_view_get_model (view)); icon_view = NEMO_ICON_VIEW (view); if (icon_view->details->is_desktop && !should_show_file_on_screen (view, file)) { return; } icon_container = get_icon_container (icon_view); if (nemo_file_has_thumbnail_access_problem (file)) { nemo_application_set_cache_flag (nemo_application_get_singleton ()); nemo_window_slot_check_bad_cache_bar (nemo_view_get_nemo_window_slot (view)); } /* Reset scroll region for the first icon added when loading a directory. */ if (nemo_view_get_loading (view) && nemo_icon_container_is_empty (icon_container)) { nemo_icon_container_reset_scroll_region (icon_container); } if (nemo_icon_container_add (icon_container, NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_ref (file); } } static void nemo_icon_view_file_changed (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoIconView *icon_view; g_assert (directory == nemo_view_get_model (view)); g_return_if_fail (view != NULL); icon_view = NEMO_ICON_VIEW (view); if (!icon_view->details->is_desktop) { nemo_icon_container_request_update (get_icon_container (icon_view), NEMO_ICON_CONTAINER_ICON_DATA (file)); return; } if (!should_show_file_on_screen (view, file)) { nemo_icon_view_remove_file (view, file, directory); } else { nemo_icon_container_request_update (get_icon_container (icon_view), NEMO_ICON_CONTAINER_ICON_DATA (file)); } } static gboolean nemo_icon_view_supports_auto_layout (NemoIconView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return view->details->supports_auto_layout; } static gboolean nemo_icon_view_is_desktop (NemoIconView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return view->details->is_desktop; } static gboolean nemo_icon_view_supports_keep_aligned (NemoIconView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return view->details->supports_keep_aligned; } static gboolean nemo_icon_view_supports_labels_beside_icons (NemoIconView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return view->details->supports_labels_beside_icons; } static void update_layout_menus (NemoIconView *view) { gboolean is_auto_layout; GtkAction *action; const char *action_name; NemoFile *file; if (view->details->icon_action_group == NULL) { return; } is_auto_layout = nemo_icon_view_using_auto_layout (view); file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); if (nemo_icon_view_supports_auto_layout (view)) { /* Mark sort criterion. */ action_name = is_auto_layout ? view->details->sort->action : NEMO_ACTION_MANUAL_LAYOUT; action = gtk_action_group_get_action (view->details->icon_action_group, action_name); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); action = gtk_action_group_get_action (view->details->icon_action_group, NEMO_ACTION_REVERSED_ORDER); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), view->details->sort_reversed); gtk_action_set_sensitive (action, is_auto_layout); action = gtk_action_group_get_action (view->details->icon_action_group, NEMO_ACTION_SORT_TRASH_TIME); if (file != NULL && nemo_file_is_in_trash (file)) { gtk_action_set_visible (action, TRUE); } else { gtk_action_set_visible (action, FALSE); } } action = gtk_action_group_get_action (view->details->icon_action_group, NEMO_ACTION_MANUAL_LAYOUT); gtk_action_set_visible (action, nemo_icon_view_supports_manual_layout (view)); /* Clean Up is only relevant for manual layout */ action = gtk_action_group_get_action (view->details->icon_action_group, NEMO_ACTION_CLEAN_UP); gtk_action_set_sensitive (action, !is_auto_layout); if (nemo_icon_view_is_desktop (view)) { gtk_action_set_label (action, _("_Organize Desktop by Name")); } action = gtk_action_group_get_action (view->details->icon_action_group, NEMO_ACTION_KEEP_ALIGNED); gtk_action_set_visible (action, nemo_icon_view_supports_keep_aligned (view)); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), nemo_icon_container_is_keep_aligned (get_icon_container (view))); gtk_action_set_sensitive (action, !is_auto_layout); } gchar * nemo_icon_view_get_directory_sort_by (NemoIconView *icon_view, NemoFile *file) { const SortCriterion *default_sort_criterion; if (!nemo_icon_view_supports_auto_layout (icon_view)) { return g_strdup ("name"); } default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL)); g_return_val_if_fail (default_sort_criterion != NULL, NULL); sync_directory_monitor_number (icon_view, file); return nemo_file_get_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_BY, default_sort_criterion->metadata_text); } static NemoFileSortType get_default_sort_order (NemoFile *file, gboolean *reversed) { NemoFileSortType retval, default_sort_order; gboolean default_sort_in_reverse_order; default_sort_order = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_DEFAULT_SORT_ORDER); default_sort_in_reverse_order = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER); retval = nemo_file_get_default_sort_type (file, reversed); if (retval == NEMO_FILE_SORT_NONE) { if (reversed != NULL) { *reversed = default_sort_in_reverse_order; } retval = CLAMP (default_sort_order, NEMO_FILE_SORT_BY_DISPLAY_NAME, NEMO_FILE_SORT_BY_MTIME); } return retval; } static void nemo_icon_view_set_directory_sort_by (NemoIconView *icon_view, NemoFile *file, const char *sort_by) { const SortCriterion *default_sort_criterion; if (!nemo_icon_view_supports_auto_layout (icon_view)) { return; } default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL)); g_return_if_fail (default_sort_criterion != NULL); sync_directory_monitor_number (icon_view, file); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_BY, default_sort_criterion->metadata_text, sort_by); } gboolean nemo_icon_view_get_directory_sort_reversed (NemoIconView *icon_view, NemoFile *file) { gboolean reversed; if (!nemo_icon_view_supports_auto_layout (icon_view)) { return FALSE; } get_default_sort_order (file, &reversed); sync_directory_monitor_number (icon_view, file); return nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED, reversed); } static void nemo_icon_view_set_directory_sort_reversed (NemoIconView *icon_view, NemoFile *file, gboolean sort_reversed) { gboolean reversed; if (!nemo_icon_view_supports_auto_layout (icon_view)) { return; } get_default_sort_order (file, &reversed); sync_directory_monitor_number (icon_view, file); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_SORT_REVERSED, reversed, sort_reversed); } static gboolean get_default_directory_keep_aligned (void) { return TRUE; } static gboolean nemo_icon_view_get_directory_keep_aligned (NemoIconView *icon_view, NemoFile *file) { if (!nemo_icon_view_supports_keep_aligned (icon_view)) { return FALSE; } sync_directory_monitor_number (icon_view, file); return nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED, get_default_directory_keep_aligned ()); } void nemo_icon_view_set_directory_keep_aligned (NemoIconView *icon_view, NemoFile *file, gboolean keep_aligned) { if (!nemo_icon_view_supports_keep_aligned (icon_view)) { return; } sync_directory_monitor_number (icon_view, file); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED, get_default_directory_keep_aligned (), keep_aligned); } static gboolean nemo_icon_view_get_directory_auto_layout (NemoIconView *icon_view, NemoFile *file) { if (!nemo_icon_view_supports_auto_layout (icon_view)) { return FALSE; } if (!nemo_icon_view_supports_manual_layout (icon_view)) { return TRUE; } sync_directory_monitor_number (icon_view, file); return nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, TRUE); } static void nemo_icon_view_set_directory_auto_layout (NemoIconView *icon_view, NemoFile *file, gboolean auto_layout) { if (!nemo_icon_view_supports_auto_layout (icon_view) || !nemo_icon_view_supports_manual_layout (icon_view)) { return; } sync_directory_monitor_number (icon_view, file); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, TRUE, auto_layout); } void nemo_icon_view_set_directory_horizontal_layout (NemoIconView *icon_view, NemoFile *file, gboolean horizontal) { sync_directory_monitor_number (icon_view, file); nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_DESKTOP_GRID_HORIZONTAL, FALSE, horizontal); } gboolean nemo_icon_view_get_directory_horizontal_layout (NemoIconView *icon_view, NemoFile *file) { sync_directory_monitor_number (icon_view, file); return nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_DESKTOP_GRID_HORIZONTAL, FALSE); } void nemo_icon_view_set_directory_grid_adjusts (NemoIconView *icon_view, NemoFile *file, gint horizontal, gint vertical) { sync_directory_monitor_number (icon_view, file); nemo_file_set_desktop_grid_adjusts (file, NEMO_METADATA_KEY_DESKTOP_GRID_ADJUST, horizontal, vertical); } void nemo_icon_view_get_directory_grid_adjusts (NemoIconView *icon_view, NemoFile *file, gint *horizontal, gint *vertical) { gint h, v; sync_directory_monitor_number (icon_view, file); nemo_file_get_desktop_grid_adjusts (file, NEMO_METADATA_KEY_DESKTOP_GRID_ADJUST, &h, &v); if (horizontal) *horizontal = h; if (vertical) *vertical = v; } gboolean nemo_icon_view_set_sort_reversed (NemoIconView *icon_view, gboolean new_value, gboolean set_metadata) { if (icon_view->details->sort_reversed == new_value) { return FALSE; } icon_view->details->sort_reversed = new_value; if (set_metadata) { /* Store the new sort setting. */ nemo_icon_view_set_directory_sort_reversed (icon_view, nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)), new_value); } /* Update the layout menus to match the new sort-order setting. */ update_layout_menus (icon_view); return TRUE; } void nemo_icon_view_flip_sort_reversed (NemoIconView *icon_view) { nemo_icon_view_set_sort_reversed (icon_view, !icon_view->details->sort_reversed, TRUE); } static const SortCriterion * get_sort_criterion_by_metadata_text (const char *metadata_text) { guint i; /* Figure out what the new sort setting should be. */ for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) { if (g_strcmp0 (sort_criteria[i].metadata_text, metadata_text) == 0) { return &sort_criteria[i]; } } return NULL; } static const SortCriterion * get_sort_criterion_by_sort_type (NemoFileSortType sort_type) { guint i; /* Figure out what the new sort setting should be. */ for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) { if (sort_type == sort_criteria[i].sort_type) { return &sort_criteria[i]; } } return &sort_criteria[0]; } #define DEFAULT_ZOOM_LEVEL(icon_view) icon_view->details->compact ? default_compact_zoom_level : default_zoom_level static NemoZoomLevel get_default_zoom_level (NemoIconView *icon_view) { NemoZoomLevel default_zoom_level, default_compact_zoom_level; default_zoom_level = g_settings_get_enum (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL); default_compact_zoom_level = g_settings_get_enum (nemo_compact_view_preferences, NEMO_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL); if (NEMO_ICON_VIEW_GET_CLASS (icon_view)->use_grid_container) { return NEMO_ZOOM_LEVEL_STANDARD; } return CLAMP (DEFAULT_ZOOM_LEVEL(icon_view), NEMO_ZOOM_LEVEL_SMALLEST, NEMO_ZOOM_LEVEL_LARGEST); } static void set_labels_beside_icons (NemoIconView *icon_view) { gboolean labels_beside; if (nemo_icon_view_supports_labels_beside_icons (icon_view)) { labels_beside = nemo_icon_view_is_compact (icon_view) || g_settings_get_boolean (nemo_icon_view_preferences, NEMO_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS); if (labels_beside) { nemo_icon_container_set_label_position (get_icon_container (icon_view), NEMO_ICON_LABEL_POSITION_BESIDE); } else { nemo_icon_container_set_label_position (get_icon_container (icon_view), NEMO_ICON_LABEL_POSITION_UNDER); } } } static void set_columns_same_width (NemoIconView *icon_view) { gboolean all_columns_same_width; if (nemo_icon_view_is_compact (icon_view)) { all_columns_same_width = g_settings_get_boolean (nemo_compact_view_preferences, NEMO_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH); nemo_icon_container_set_all_columns_same_width (get_icon_container (icon_view), all_columns_same_width); } } static void nemo_icon_view_begin_loading (NemoView *view) { NemoIconView *icon_view; GtkWidget *icon_container; NemoFile *file; int level; int h_adjust, v_adjust; char *sort_name, *uri; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); icon_view = NEMO_ICON_VIEW (view); file = nemo_view_get_directory_as_file (view); uri = nemo_file_get_uri (file); icon_container = GTK_WIDGET (get_icon_container (icon_view)); nemo_icon_container_begin_loading (NEMO_ICON_CONTAINER (icon_container)); nemo_icon_container_set_allow_moves (NEMO_ICON_CONTAINER (icon_container), !eel_uri_is_search (uri)); g_free (uri); /* Set up the zoom level from the metadata. */ if (nemo_view_supports_zooming (NEMO_VIEW (icon_view))) { if (nemo_global_preferences_get_ignore_view_metadata () && !NEMO_ICON_VIEW_GET_CLASS (view)->use_grid_container) { if (nemo_window_get_ignore_meta_zoom_level (nemo_view_get_nemo_window (view)) == -1) { nemo_window_set_ignore_meta_zoom_level (nemo_view_get_nemo_window (view), get_default_zoom_level (icon_view)); } level = nemo_window_get_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (icon_view))); } else { sync_directory_monitor_number (icon_view, file); if (icon_view->details->compact) { level = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, get_default_zoom_level (icon_view)); } else { level = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, get_default_zoom_level (icon_view)); } } nemo_icon_view_set_zoom_level (icon_view, level, TRUE); } /* Set the sort mode. * It's OK not to resort the icons because the * container doesn't have any icons at this point. */ sort_name = nemo_icon_view_get_directory_sort_by (icon_view, file); set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name), FALSE); g_free (sort_name); /* Set the sort direction from the metadata. */ nemo_icon_view_set_sort_reversed (icon_view, nemo_icon_view_get_directory_sort_reversed (icon_view, file), FALSE); nemo_icon_container_set_horizontal_layout (get_icon_container (icon_view), nemo_icon_view_get_directory_horizontal_layout (icon_view, file)); nemo_icon_container_set_keep_aligned (get_icon_container (icon_view), nemo_icon_view_get_directory_keep_aligned (icon_view, file)); nemo_icon_view_get_directory_grid_adjusts (NEMO_ICON_VIEW (view), file, &h_adjust, &v_adjust); nemo_icon_container_set_grid_adjusts (get_icon_container (icon_view), h_adjust, v_adjust); set_labels_beside_icons (icon_view); set_columns_same_width (icon_view); /* We must set auto-layout last, because it invokes the layout_changed * callback, which works incorrectly if the other layout criteria are * not already set up properly (see bug 6500, e.g.) */ nemo_icon_container_set_auto_layout (get_icon_container (icon_view), nemo_icon_view_get_directory_auto_layout (icon_view, file)); /* e.g. keep aligned may have changed */ update_layout_menus (icon_view); } static void icon_view_notify_clipboard_info (NemoClipboardMonitor *monitor, NemoClipboardInfo *info, NemoIconView *icon_view) { GList *icon_data; icon_data = NULL; if (info && info->cut) { icon_data = info->files; } nemo_icon_container_set_highlighted_for_clipboard ( get_icon_container (icon_view), icon_data); } static void nemo_icon_view_end_loading (NemoView *view, gboolean all_files_seen) { NemoIconView *icon_view; GtkWidget *icon_container; NemoClipboardMonitor *monitor; NemoClipboardInfo *info; icon_view = NEMO_ICON_VIEW (view); icon_container = GTK_WIDGET (get_icon_container (icon_view)); nemo_icon_container_end_loading (NEMO_ICON_CONTAINER (icon_container), all_files_seen); nemo_icon_container_update_selection (NEMO_ICON_CONTAINER (icon_container)); monitor = nemo_clipboard_monitor_get (); info = nemo_clipboard_monitor_get_clipboard_info (monitor); icon_view_notify_clipboard_info (monitor, info, icon_view); } static NemoZoomLevel nemo_icon_view_get_zoom_level (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NEMO_ZOOM_LEVEL_STANDARD); return nemo_icon_container_get_zoom_level (get_icon_container (NEMO_ICON_VIEW (view))); } static void nemo_icon_view_set_zoom_level (NemoIconView *view, NemoZoomLevel new_level, gboolean always_emit) { NemoIconContainer *icon_container; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); g_return_if_fail (new_level >= NEMO_ZOOM_LEVEL_SMALLEST && new_level <= NEMO_ZOOM_LEVEL_LARGEST); icon_container = get_icon_container (view); if (nemo_icon_container_get_zoom_level (icon_container) == new_level) { if (always_emit) { g_signal_emit_by_name (view, "zoom_level_changed"); } return; } if (nemo_global_preferences_get_ignore_view_metadata () && !NEMO_ICON_VIEW_GET_CLASS (view)->use_grid_container) { nemo_window_set_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (view)), new_level); } else { sync_directory_monitor_number (view, nemo_view_get_directory_as_file (NEMO_VIEW (view))); if (view->details->compact) { nemo_file_set_integer_metadata (nemo_view_get_directory_as_file (NEMO_VIEW (view)), NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, get_default_zoom_level (view), new_level); } else { nemo_file_set_integer_metadata (nemo_view_get_directory_as_file (NEMO_VIEW (view)), NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, get_default_zoom_level (view), new_level); } } nemo_icon_container_set_zoom_level (icon_container, new_level); g_signal_emit_by_name (view, "zoom_level_changed"); if (nemo_view_get_active (NEMO_VIEW (view))) { nemo_view_update_menus (NEMO_VIEW (view)); } } static void nemo_icon_view_bump_zoom_level (NemoView *view, int zoom_increment) { NemoZoomLevel new_level; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); new_level = nemo_icon_view_get_zoom_level (view) + zoom_increment; if (new_level >= NEMO_ZOOM_LEVEL_SMALLEST && new_level <= NEMO_ZOOM_LEVEL_LARGEST) { nemo_view_zoom_to_level (view, new_level); } } static void nemo_icon_view_zoom_to_level (NemoView *view, NemoZoomLevel zoom_level) { NemoIconView *icon_view; g_assert (NEMO_IS_ICON_VIEW (view)); icon_view = NEMO_ICON_VIEW (view); nemo_icon_view_set_zoom_level (icon_view, zoom_level, FALSE); } static void nemo_icon_view_restore_default_zoom_level (NemoView *view) { NemoIconView *icon_view; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); icon_view = NEMO_ICON_VIEW (view); nemo_view_zoom_to_level (view, get_default_zoom_level (icon_view)); } static NemoZoomLevel nemo_icon_view_get_default_zoom_level (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NEMO_ZOOM_LEVEL_NULL); return get_default_zoom_level(NEMO_ICON_VIEW (view)); } static gboolean nemo_icon_view_can_zoom_in (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return nemo_icon_view_get_zoom_level (view) < NEMO_ZOOM_LEVEL_LARGEST; } static gboolean nemo_icon_view_can_zoom_out (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return nemo_icon_view_get_zoom_level (view) > NEMO_ZOOM_LEVEL_SMALLEST; } static gboolean nemo_icon_view_is_empty (NemoView *view) { g_assert (NEMO_IS_ICON_VIEW (view)); return nemo_icon_container_is_empty (get_icon_container (NEMO_ICON_VIEW (view))); } static GList * nemo_icon_view_get_selection (NemoView *view) { GList *list; g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NULL); list = nemo_icon_container_get_selection (get_icon_container (NEMO_ICON_VIEW (view))); nemo_file_list_ref (list); return list; } static GList * nemo_icon_view_peek_selection (NemoView *view) { GList *list; g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NULL); list = nemo_icon_container_peek_selection (get_icon_container (NEMO_ICON_VIEW (view))); nemo_file_list_ref (list); return list; } static gint nemo_icon_view_get_selection_count (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), 0); return nemo_icon_container_get_selection_count (get_icon_container (NEMO_ICON_VIEW (view))); } static void count_item (NemoIconData *icon_data, gpointer callback_data) { guint *count; count = callback_data; (*count)++; } static guint nemo_icon_view_get_item_count (NemoView *view) { guint count; g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), 0); count = 0; nemo_icon_container_for_each (get_icon_container (NEMO_ICON_VIEW (view)), count_item, &count); return count; } void nemo_icon_view_set_sort_criterion_by_sort_type (NemoIconView *icon_view, NemoFileSortType sort_type) { const SortCriterion *sort; g_assert (NEMO_IS_ICON_VIEW (icon_view)); sort = get_sort_criterion_by_sort_type (sort_type); g_return_if_fail (sort != NULL); if (sort == icon_view->details->sort && nemo_icon_view_using_auto_layout (icon_view)) { return; } set_sort_criterion (icon_view, sort, TRUE); nemo_icon_container_sort (get_icon_container (icon_view)); nemo_icon_view_reveal_selection (NEMO_VIEW (icon_view)); } static void action_reversed_order_callback (GtkAction *action, gpointer user_data) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (user_data); if (nemo_icon_view_set_sort_reversed (icon_view, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)), TRUE)) { nemo_icon_container_sort (get_icon_container (icon_view)); nemo_icon_view_reveal_selection (NEMO_VIEW (icon_view)); } } static void action_keep_aligned_callback (GtkAction *action, gpointer user_data) { NemoIconView *icon_view; NemoFile *file; gboolean keep_aligned; icon_view = NEMO_ICON_VIEW (user_data); keep_aligned = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); nemo_icon_view_set_directory_keep_aligned (icon_view, file, keep_aligned); nemo_icon_container_set_keep_aligned (get_icon_container (icon_view), keep_aligned); } static void switch_to_manual_layout (NemoIconView *icon_view) { if (!nemo_icon_view_using_auto_layout (icon_view)) { return; } icon_view->details->sort = &sort_criteria[0]; nemo_icon_container_set_auto_layout (get_icon_container (icon_view), FALSE); } static void layout_changed_callback (NemoIconContainer *container, NemoIconView *icon_view) { NemoFile *file; g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); if (file != NULL) { nemo_icon_view_set_directory_auto_layout (icon_view, file, nemo_icon_view_using_auto_layout (icon_view)); } update_layout_menus (icon_view); } static gboolean nemo_icon_view_can_rename_file (NemoView *view, NemoFile *file) { if (!(nemo_icon_view_get_zoom_level (view) > NEMO_ZOOM_LEVEL_SMALLEST)) { return FALSE; } return NEMO_VIEW_CLASS(nemo_icon_view_parent_class)->can_rename_file (view, file); } static void nemo_icon_view_start_renaming_file (NemoView *view, NemoFile *file, gboolean select_all) { /* call parent class to make sure the right icon is selected */ NEMO_VIEW_CLASS(nemo_icon_view_parent_class)->start_renaming_file (view, file, select_all); /* start renaming */ nemo_icon_container_start_renaming_selected_item (get_icon_container (NEMO_ICON_VIEW (view)), select_all); } static const GtkActionEntry icon_view_entries[] = { /* name, stock id, label */ { "Arrange Items", NULL, N_("Arran_ge Items") }, /* name, stock id */ { "Clean Up", NULL, /* label, accelerator */ N_("_Organize by Name"), NULL, /* tooltip */ N_("Reposition icons to better fit in the window and avoid overlapping"), G_CALLBACK (action_clean_up_callback) }, }; static const GtkToggleActionEntry icon_view_toggle_entries[] = { /* name, stock id */ { "Reversed Order", NULL, /* label, accelerator */ N_("Re_versed Order"), NULL, /* tooltip */ N_("Display icons in the opposite order"), G_CALLBACK (action_reversed_order_callback), 0 }, /* name, stock id */ { "Keep Aligned", NULL, /* label, accelerator */ N_("_Keep Aligned"), NULL, /* tooltip */ N_("Keep icons lined up on a grid"), G_CALLBACK (action_keep_aligned_callback), 0 }, }; static const GtkRadioActionEntry arrange_radio_entries[] = { { "Manual Layout", NULL, N_("_Manually"), NULL, N_("Leave icons wherever they are dropped"), NEMO_FILE_SORT_NONE }, { "Sort by Name", NULL, N_("By _Name"), NULL, N_("Keep icons sorted by name in rows"), NEMO_FILE_SORT_BY_DISPLAY_NAME }, { "Sort by Size", NULL, N_("By _Size"), NULL, N_("Keep icons sorted by size in rows"), NEMO_FILE_SORT_BY_SIZE }, { "Sort by Type", NULL, N_("By _Type"), NULL, N_("Keep icons sorted by type in rows"), NEMO_FILE_SORT_BY_TYPE }, { "Sort by Detailed Type", NULL, N_("By _Detailed Type"), NULL, N_("Keep icons sorted by detailed type in rows"), NEMO_FILE_SORT_BY_DETAILED_TYPE }, { "Sort by Modification Date", NULL, N_("By Modification _Date"), NULL, N_("Keep icons sorted by modification date in rows"), NEMO_FILE_SORT_BY_MTIME }, { "Sort by Trash Time", NULL, N_("By T_rash Time"), NULL, N_("Keep icons sorted by trash time in rows"), NEMO_FILE_SORT_BY_TRASHED_TIME }, }; static void nemo_icon_view_merge_menus (NemoView *view) { NemoIconView *icon_view; GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkAction *action; g_assert (NEMO_IS_ICON_VIEW (view)); NEMO_VIEW_CLASS (nemo_icon_view_parent_class)->merge_menus (view); icon_view = NEMO_ICON_VIEW (view); ui_manager = nemo_view_get_ui_manager (NEMO_VIEW (icon_view)); action_group = gtk_action_group_new ("IconViewActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); icon_view->details->icon_action_group = action_group; gtk_action_group_add_actions (action_group, icon_view_entries, G_N_ELEMENTS (icon_view_entries), icon_view); gtk_action_group_add_toggle_actions (action_group, icon_view_toggle_entries, G_N_ELEMENTS (icon_view_toggle_entries), icon_view); gtk_action_group_add_radio_actions (action_group, arrange_radio_entries, G_N_ELEMENTS (arrange_radio_entries), -1, G_CALLBACK (action_sort_radio_callback), icon_view); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui manager */ icon_view->details->icon_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-icon-view-ui.xml", NULL); /* Do one-time state-setting here; context-dependent state-setting * is done in update_menus. */ if (!nemo_icon_view_supports_auto_layout (icon_view)) { action = gtk_action_group_get_action (action_group, NEMO_ACTION_ARRANGE_ITEMS); gtk_action_set_visible (action, FALSE); } update_layout_menus (icon_view); } static void nemo_icon_view_unmerge_menus (NemoView *view) { NemoIconView *icon_view; GtkUIManager *ui_manager; icon_view = NEMO_ICON_VIEW (view); NEMO_VIEW_CLASS (nemo_icon_view_parent_class)->unmerge_menus (view); ui_manager = nemo_view_get_ui_manager (view); if (ui_manager != NULL) { nemo_ui_unmerge_ui (ui_manager, &icon_view->details->icon_merge_id, &icon_view->details->icon_action_group); } } static void nemo_icon_view_update_menus (NemoView *view) { NemoIconView *icon_view; GtkAction *action; gboolean editable; icon_view = NEMO_ICON_VIEW (view); NEMO_VIEW_CLASS (nemo_icon_view_parent_class)->update_menus(view); editable = nemo_view_is_editable (view); action = gtk_action_group_get_action (icon_view->details->icon_action_group, NEMO_ACTION_MANUAL_LAYOUT); gtk_action_set_sensitive (action, editable); } static void nemo_icon_view_reset_to_defaults (NemoView *view) { NemoIconContainer *icon_container; NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (view); icon_container = get_icon_container (icon_view); clear_sort_criterion (icon_view); nemo_icon_container_set_keep_aligned (icon_container, get_default_directory_keep_aligned ()); nemo_icon_container_sort (icon_container); update_layout_menus (icon_view); nemo_icon_view_restore_default_zoom_level (view); if (nemo_global_preferences_get_ignore_view_metadata ()) { NemoWindow *window = nemo_view_get_nemo_window (view); nemo_window_set_ignore_meta_zoom_level (window, NEMO_ZOOM_LEVEL_NULL); } } static void nemo_icon_view_select_all (NemoView *view) { NemoIconContainer *icon_container; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); icon_container = get_icon_container (NEMO_ICON_VIEW (view)); nemo_icon_container_select_all (icon_container); } static void nemo_icon_view_reveal_selection (NemoView *view) { GList *selection; g_return_if_fail (NEMO_IS_ICON_VIEW (view)); selection = nemo_view_get_selection (view); /* Make sure at least one of the selected items is scrolled into view */ if (selection != NULL) { nemo_icon_container_reveal (get_icon_container (NEMO_ICON_VIEW (view)), selection->data); } nemo_file_list_free (selection); } static GArray * nemo_icon_view_get_selected_icon_locations (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), NULL); return nemo_icon_container_get_selected_icon_locations (get_icon_container (NEMO_ICON_VIEW (view))); } static void nemo_icon_view_set_selection (NemoView *view, GList *selection) { g_return_if_fail (NEMO_IS_ICON_VIEW (view)); nemo_icon_container_set_selection (get_icon_container (NEMO_ICON_VIEW (view)), selection); } static void nemo_icon_view_invert_selection (NemoView *view) { g_return_if_fail (NEMO_IS_ICON_VIEW (view)); nemo_icon_container_invert_selection (get_icon_container (NEMO_ICON_VIEW (view))); } static gboolean nemo_icon_view_using_manual_layout (NemoView *view) { g_return_val_if_fail (NEMO_IS_ICON_VIEW (view), FALSE); return !nemo_icon_view_using_auto_layout (NEMO_ICON_VIEW (view)); } static void nemo_icon_view_widget_to_file_operation_position (NemoView *view, GdkPoint *position) { g_assert (NEMO_IS_ICON_VIEW (view)); nemo_icon_container_widget_to_file_operation_position (get_icon_container (NEMO_ICON_VIEW (view)), position); } static void icon_container_activate_callback (NemoIconContainer *container, GList *file_list, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); nemo_view_activate_files (NEMO_VIEW (icon_view), file_list, 0, TRUE); } static void icon_container_activate_previewer_callback (NemoIconContainer *container, GList *file_list, GArray *locations, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); nemo_view_preview_files (NEMO_VIEW (icon_view), file_list, locations); } /* this is called in one of these cases: * - we activate with enter holding shift * - we activate with space holding shift * - we double click an icon holding shift * - we middle click an icon * * If we don't open in new windows by default, the behavior should be * - middle click, shift + activate -> open in new tab * - shift + double click -> open in new window * * If we open in new windows by default, the behaviour should be * - middle click, or shift + activate, or shift + double-click -> close parent */ static void icon_container_activate_alternate_callback (NemoIconContainer *container, GList *file_list, NemoIconView *icon_view) { GdkEvent *event; GdkEventButton *button_event; GdkEventKey *key_event; gboolean open_in_tab, open_in_window, close_behind; NemoWindowOpenFlags flags; g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); flags = 0; event = gtk_get_current_event (); open_in_tab = FALSE; open_in_window = FALSE; close_behind = FALSE; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) { if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE || event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { button_event = (GdkEventButton *) event; open_in_window = ((button_event->state & GDK_SHIFT_MASK) != 0); open_in_tab = !open_in_window; } else if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) { key_event = (GdkEventKey *) event; open_in_tab = ((key_event->state & GDK_SHIFT_MASK) != 0); } } else { close_behind = TRUE; } if (open_in_tab) { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } if (open_in_window) { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } if (close_behind) { flags |= NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND; } DEBUG ("Activate alternate, open in tab %d, close behind %d, new window %d\n", open_in_tab, close_behind, open_in_window); nemo_view_activate_files (NEMO_VIEW (icon_view), file_list, flags, TRUE); } static void band_select_started_callback (NemoIconContainer *container, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); nemo_view_start_batching_selection_changes (NEMO_VIEW (icon_view)); } static void band_select_ended_callback (NemoIconContainer *container, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); nemo_view_stop_batching_selection_changes (NEMO_VIEW (icon_view)); } int nemo_icon_view_compare_files (NemoIconView *icon_view, NemoFile *a, NemoFile *b) { return nemo_file_compare_for_sort (a, b, icon_view->details->sort->sort_type, /* Use type-unsafe cast for performance */ nemo_view_should_sort_directories_first ((NemoView *)icon_view), icon_view->details->sort_reversed); } static int compare_files (NemoView *icon_view, NemoFile *a, NemoFile *b) { return nemo_icon_view_compare_files ((NemoIconView *)icon_view, a, b); } static void nemo_icon_view_screen_changed (GtkWidget *widget, GdkScreen *previous_screen) { NemoView *view; GList *files, *l; NemoFile *file; NemoDirectory *directory; NemoIconContainer *icon_container; if (GTK_WIDGET_CLASS (nemo_icon_view_parent_class)->screen_changed) { GTK_WIDGET_CLASS (nemo_icon_view_parent_class)->screen_changed (widget, previous_screen); } view = NEMO_VIEW (widget); if (NEMO_ICON_VIEW (view)->details->is_desktop) { icon_container = get_icon_container (NEMO_ICON_VIEW (view)); directory = nemo_view_get_model (view); files = nemo_directory_get_file_list (directory); for (l = files; l != NULL; l = l->next) { file = l->data; if (!should_show_file_on_screen (view, file)) { nemo_icon_view_remove_file (view, file, directory); } else { if (nemo_icon_container_add (icon_container, NEMO_ICON_CONTAINER_ICON_DATA (file))) { nemo_file_ref (file); } } } nemo_file_list_unref (files); g_list_free (files); } } static gboolean nemo_icon_view_scroll_event (GtkWidget *widget, GdkEventScroll *scroll_event) { NemoIconView *icon_view; GdkEvent *event_copy; GdkEventScroll *scroll_event_copy; gboolean ret; icon_view = NEMO_ICON_VIEW (widget); if (icon_view->details->compact && (scroll_event->direction == GDK_SCROLL_UP || scroll_event->direction == GDK_SCROLL_DOWN || scroll_event->direction == GDK_SCROLL_SMOOTH)) { ret = nemo_view_handle_scroll_event (NEMO_VIEW (icon_view), scroll_event); if (!ret) { /* in column-wise layout, re-emit vertical mouse scroll events as horizontal ones, * if they don't bump zoom */ event_copy = gdk_event_copy ((GdkEvent *) scroll_event); scroll_event_copy = (GdkEventScroll *) event_copy; /* transform vertical integer smooth scroll events into horizontal events */ if (scroll_event_copy->direction == GDK_SCROLL_SMOOTH && scroll_event_copy->delta_x == 0) { if (scroll_event_copy->delta_y == 1.0) { scroll_event_copy->direction = GDK_SCROLL_DOWN; } else if (scroll_event_copy->delta_y == -1.0) { scroll_event_copy->direction = GDK_SCROLL_UP; } } if (scroll_event_copy->direction == GDK_SCROLL_UP) { scroll_event_copy->direction = GDK_SCROLL_LEFT; } else if (scroll_event_copy->direction == GDK_SCROLL_DOWN) { scroll_event_copy->direction = GDK_SCROLL_RIGHT; } ret = GTK_WIDGET_CLASS (nemo_icon_view_parent_class)->scroll_event (widget, scroll_event_copy); gdk_event_free (event_copy); } return ret; } return GTK_WIDGET_CLASS (nemo_icon_view_parent_class)->scroll_event (widget, scroll_event); } static void selection_changed_callback (NemoIconContainer *container, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); nemo_icon_container_update_selection (container); nemo_view_notify_selection_changed (NEMO_VIEW (icon_view)); } static void icon_container_context_click_selection_callback (NemoIconContainer *container, GdkEventButton *event, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (NEMO_IS_ICON_VIEW (icon_view)); nemo_view_pop_up_selection_context_menu (NEMO_VIEW (icon_view), event); } static void icon_container_context_click_background_callback (NemoIconContainer *container, GdkEventButton *event, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (NEMO_IS_ICON_VIEW (icon_view)); nemo_view_pop_up_background_context_menu (NEMO_VIEW (icon_view), event); } static gboolean nemo_icon_view_react_to_icon_change_idle_callback (gpointer data) { NemoIconView *icon_view; g_assert (NEMO_IS_ICON_VIEW (data)); icon_view = NEMO_ICON_VIEW (data); icon_view->details->react_to_icon_change_idle_id = 0; /* Rebuild the menus since some of them (e.g. Restore Stretched Icons) * may be different now. */ nemo_view_update_menus (NEMO_VIEW (icon_view)); /* Don't call this again (unless rescheduled) */ return FALSE; } static void icon_position_changed_callback (NemoIconContainer *container, NemoFile *file, const NemoIconPosition *position, NemoIconView *icon_view) { char scale_string[G_ASCII_DTOSTR_BUF_SIZE]; g_assert (NEMO_IS_ICON_VIEW (icon_view)); g_assert (container == get_icon_container (icon_view)); g_assert (NEMO_IS_FILE (file)); /* Schedule updating menus for the next idle. Doing it directly here * noticeably slows down icon stretching. The other work here to * store the icon position and scale does not seem to noticeably * slow down icon stretching. It would be trickier to move to an * idle call, because we'd have to keep track of potentially multiple * sets of file/geometry info. */ if (nemo_view_get_active (NEMO_VIEW (icon_view)) && icon_view->details->react_to_icon_change_idle_id == 0) { icon_view->details->react_to_icon_change_idle_id = g_idle_add (nemo_icon_view_react_to_icon_change_idle_callback, icon_view); } /* Store the new position of the icon in the metadata. */ if (!nemo_file_get_is_desktop_orphan (file)) { nemo_file_set_position (file, position->x, position->y); nemo_file_set_monitor_number (file, position->monitor); } g_ascii_dtostr (scale_string, sizeof (scale_string), position->scale); sync_directory_monitor_number (icon_view, file); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_SCALE, "1.0", scale_string); } /* Attempt to change the filename to the new text. Notify user if operation fails. */ static void icon_rename_ended_cb (NemoIconContainer *container, NemoFile *file, const char *new_name, NemoIconView *icon_view) { g_assert (NEMO_IS_FILE (file)); nemo_view_set_is_renaming (NEMO_VIEW (icon_view), FALSE); /* Don't allow a rename with an empty string. Revert to original * without notifying the user. */ if ((new_name == NULL) || (new_name[0] == '\0')) { return; } nemo_rename_file (file, new_name, NULL, NULL); } static void icon_rename_started_cb (NemoIconContainer *container, GtkWidget *widget, gpointer callback_data) { NemoView *directory_view; directory_view = NEMO_VIEW (callback_data); nemo_clipboard_set_up_editable (GTK_EDITABLE (widget), nemo_view_get_ui_manager (directory_view), FALSE); } static char * get_icon_uri_callback (NemoIconContainer *container, NemoFile *file, NemoIconView *icon_view) { g_assert (NEMO_IS_ICON_CONTAINER (container)); g_assert (NEMO_IS_FILE (file)); g_assert (NEMO_IS_ICON_VIEW (icon_view)); return nemo_file_get_uri (file); } static char * get_icon_drop_target_uri_callback (NemoIconContainer *container, NemoFile *file, NemoIconView *icon_view) { g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), NULL); g_return_val_if_fail (NEMO_IS_FILE (file), NULL); g_return_val_if_fail (NEMO_IS_ICON_VIEW (icon_view), NULL); return nemo_file_get_drop_target_uri (file); } /* Preferences changed callbacks */ static void nemo_icon_view_click_policy_changed (NemoView *directory_view) { g_assert (NEMO_IS_ICON_VIEW (directory_view)); nemo_icon_view_update_click_mode (NEMO_ICON_VIEW (directory_view)); } static void nemo_icon_view_click_to_rename_mode_changed (NemoView *directory_view) { g_assert (NEMO_IS_ICON_VIEW (directory_view)); nemo_icon_view_update_click_to_rename_mode (NEMO_ICON_VIEW (directory_view)); } static void image_display_policy_changed_callback (gpointer callback_data) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (callback_data); nemo_icon_container_request_update_all (get_icon_container (icon_view)); } static void text_attribute_names_changed_callback (gpointer callback_data) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (callback_data); nemo_icon_container_request_update_all (get_icon_container (icon_view)); } static void default_sort_order_changed_callback (gpointer callback_data) { NemoIconView *icon_view; NemoFile *file; char *sort_name; NemoIconContainer *icon_container; g_return_if_fail (NEMO_IS_ICON_VIEW (callback_data)); icon_view = NEMO_ICON_VIEW (callback_data); file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); sort_name = nemo_icon_view_get_directory_sort_by (icon_view, file); set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name), FALSE); g_free (sort_name); icon_container = get_icon_container (icon_view); g_return_if_fail (NEMO_IS_ICON_CONTAINER (icon_container)); nemo_icon_container_request_update_all (icon_container); } static void default_sort_in_reverse_order_changed_callback (gpointer callback_data) { NemoIconView *icon_view; NemoFile *file; NemoIconContainer *icon_container; g_return_if_fail (NEMO_IS_ICON_VIEW (callback_data)); icon_view = NEMO_ICON_VIEW (callback_data); file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); nemo_icon_view_set_sort_reversed (icon_view, nemo_icon_view_get_directory_sort_reversed (icon_view, file), FALSE); icon_container = get_icon_container (icon_view); g_return_if_fail (NEMO_IS_ICON_CONTAINER (icon_container)); nemo_icon_container_request_update_all (icon_container); } static void default_zoom_level_changed_callback (gpointer callback_data) { NemoIconView *icon_view; NemoFile *file; int level; g_return_if_fail (NEMO_IS_ICON_VIEW (callback_data)); icon_view = NEMO_ICON_VIEW (callback_data); if (nemo_view_supports_zooming (NEMO_VIEW (icon_view))) { file = nemo_view_get_directory_as_file (NEMO_VIEW (icon_view)); if (nemo_global_preferences_get_ignore_view_metadata () && nemo_window_get_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (icon_view))) > -1) { level = nemo_window_get_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (icon_view))); } else { sync_directory_monitor_number (icon_view, file); if (nemo_icon_view_is_compact (icon_view)) { level = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, get_default_zoom_level (icon_view)); } else { level = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, get_default_zoom_level (icon_view)); } } nemo_view_zoom_to_level (NEMO_VIEW (icon_view), level); } } static void labels_beside_icons_changed_callback (gpointer callback_data) { NemoIconView *icon_view; g_return_if_fail (NEMO_IS_ICON_VIEW (callback_data)); icon_view = NEMO_ICON_VIEW (callback_data); set_labels_beside_icons (icon_view); } static void all_columns_same_width_changed_callback (gpointer callback_data) { NemoIconView *icon_view; g_assert (NEMO_IS_ICON_VIEW (callback_data)); icon_view = NEMO_ICON_VIEW (callback_data); set_columns_same_width (icon_view); } static void nemo_icon_view_sort_directories_first_changed (NemoView *directory_view) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (directory_view); if (nemo_icon_view_using_auto_layout (icon_view)) { nemo_icon_container_sort (get_icon_container (icon_view)); } } static gboolean icon_view_can_accept_item (NemoIconContainer *container, NemoFile *target_item, const char *item_uri, NemoView *view) { return nemo_drag_can_accept_item (target_item, item_uri); } static char * icon_view_get_container_uri (NemoIconContainer *container, NemoView *view) { return nemo_view_get_uri (view); } static void icon_view_move_copy_items (NemoIconContainer *container, const GList *item_uris, GArray *relative_item_points, const char *target_dir, int copy_action, int x, int y, NemoView *view) { nemo_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), item_uris, nemo_view_get_copied_files_atom (view)); nemo_view_move_copy_items (view, item_uris, relative_item_points, target_dir, copy_action, x, y); } static void nemo_icon_view_update_click_mode (NemoIconView *icon_view) { NemoIconContainer *icon_container; int click_mode; icon_container = get_icon_container (icon_view); g_assert (icon_container != NULL); click_mode = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_CLICK_POLICY); nemo_icon_container_set_single_click_mode (icon_container, click_mode == NEMO_CLICK_POLICY_SINGLE); } static void nemo_icon_view_update_click_to_rename_mode (NemoIconView *icon_view) { NemoIconContainer *icon_container; gboolean enabled; icon_container = get_icon_container (icon_view); g_assert (icon_container != NULL); enabled = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CLICK_TO_RENAME); nemo_icon_container_set_click_to_rename_enabled (icon_container, enabled); } static gboolean get_stored_layout_timestamp (NemoIconContainer *container, NemoIconData *icon_data, time_t *timestamp, NemoIconView *view) { NemoFile *file; NemoDirectory *directory; if (icon_data == NULL) { directory = nemo_view_get_model (NEMO_VIEW (view)); if (directory == NULL) { return FALSE; } file = nemo_directory_get_corresponding_file (directory); sync_directory_monitor_number (view, file); *timestamp = nemo_file_get_time_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP); nemo_file_unref (file); } else { sync_directory_monitor_number (view, NEMO_FILE (icon_data)); *timestamp = nemo_file_get_time_metadata (NEMO_FILE (icon_data), NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP); } return TRUE; } static gboolean store_layout_timestamp (NemoIconContainer *container, NemoIconData *icon_data, const time_t *timestamp, NemoIconView *view) { NemoFile *file; NemoDirectory *directory; if (icon_data == NULL) { directory = nemo_view_get_model (NEMO_VIEW (view)); if (directory == NULL) { return FALSE; } file = nemo_directory_get_corresponding_file (directory); sync_directory_monitor_number (view, file); nemo_file_set_time_metadata (file, NEMO_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP, (time_t) *timestamp); nemo_file_unref (file); } else { sync_directory_monitor_number (view, NEMO_FILE (icon_data)); nemo_file_set_time_metadata (NEMO_FILE (icon_data), NEMO_METADATA_KEY_ICON_POSITION_TIMESTAMP, (time_t) *timestamp); } return TRUE; } static gboolean focus_in_event_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { NemoWindowSlot *slot; NemoIconView *icon_view = NEMO_ICON_VIEW (user_data); /* make the corresponding slot (and the pane that contains it) active */ slot = nemo_view_get_nemo_window_slot (NEMO_VIEW (icon_view)); nemo_window_slot_make_hosting_pane_active (slot); return FALSE; } static gboolean button_press_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { NemoView *view = NEMO_VIEW (user_data); GdkEventButton *event_button = (GdkEventButton *)event; int selection_count; if (!nemo_view_get_active (view)) { NemoWindowSlot *slot = nemo_view_get_nemo_window_slot (view); nemo_window_slot_make_hosting_pane_active (slot); return TRUE; } /* double left click on blank will go to parent folder */ if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CLICK_DOUBLE_PARENT_FOLDER) && (event_button->button == 1) && (event_button->type == GDK_2BUTTON_PRESS)) { selection_count = nemo_view_get_selection_count (NEMO_VIEW (view)); if (selection_count == 0) { NemoWindowSlot *slot = nemo_view_get_nemo_window_slot (view); nemo_window_slot_go_up (slot, 0); return TRUE; } } return FALSE; } static NemoIconContainer * create_icon_container (NemoIconView *icon_view) { NemoIconContainer *icon_container; if (NEMO_ICON_VIEW_GET_CLASS (icon_view)->use_grid_container) { icon_container = nemo_icon_view_grid_container_new (icon_view, icon_view->details->is_desktop); } else { icon_container = nemo_icon_view_container_new (icon_view, icon_view->details->is_desktop); } icon_view->details->icon_container = GTK_WIDGET (icon_container); g_object_add_weak_pointer (G_OBJECT (icon_container), (gpointer *) &icon_view->details->icon_container); gtk_widget_set_can_focus (GTK_WIDGET (icon_container), TRUE); g_signal_connect_object (icon_container, "button_press_event", G_CALLBACK (button_press_callback), icon_view, 0); g_signal_connect_object (icon_container, "focus_in_event", G_CALLBACK (focus_in_event_callback), icon_view, 0); g_signal_connect_object (icon_container, "activate", G_CALLBACK (icon_container_activate_callback), icon_view, 0); g_signal_connect_object (icon_container, "activate_alternate", G_CALLBACK (icon_container_activate_alternate_callback), icon_view, 0); g_signal_connect_object (icon_container, "activate_previewer", G_CALLBACK (icon_container_activate_previewer_callback), icon_view, 0); g_signal_connect_object (icon_container, "band_select_started", G_CALLBACK (band_select_started_callback), icon_view, 0); g_signal_connect_object (icon_container, "band_select_ended", G_CALLBACK (band_select_ended_callback), icon_view, 0); g_signal_connect_object (icon_container, "context_click_selection", G_CALLBACK (icon_container_context_click_selection_callback), icon_view, 0); g_signal_connect_object (icon_container, "context_click_background", G_CALLBACK (icon_container_context_click_background_callback), icon_view, 0); g_signal_connect_object (icon_container, "icon_position_changed", G_CALLBACK (icon_position_changed_callback), icon_view, 0); g_signal_connect_object (icon_container, "selection_changed", G_CALLBACK (selection_changed_callback), icon_view, 0); /* FIXME: many of these should move into fm-icon-container as virtual methods */ g_signal_connect_object (icon_container, "get_icon_uri", G_CALLBACK (get_icon_uri_callback), icon_view, 0); g_signal_connect_object (icon_container, "get_icon_drop_target_uri", G_CALLBACK (get_icon_drop_target_uri_callback), icon_view, 0); g_signal_connect_object (icon_container, "move_copy_items", G_CALLBACK (icon_view_move_copy_items), icon_view, 0); g_signal_connect_object (icon_container, "get_container_uri", G_CALLBACK (icon_view_get_container_uri), icon_view, 0); g_signal_connect_object (icon_container, "can_accept_item", G_CALLBACK (icon_view_can_accept_item), icon_view, 0); g_signal_connect_object (icon_container, "layout_changed", G_CALLBACK (layout_changed_callback), icon_view, 0); g_signal_connect_object (icon_container, "icon_rename_started", G_CALLBACK (icon_rename_started_cb), icon_view, 0); g_signal_connect_object (icon_container, "icon_rename_ended", G_CALLBACK (icon_rename_ended_cb), icon_view, 0); g_signal_connect_object (icon_container, "icon_stretch_started", G_CALLBACK (nemo_view_update_menus), icon_view, G_CONNECT_SWAPPED); g_signal_connect_object (icon_container, "icon_stretch_ended", G_CALLBACK (nemo_view_update_menus), icon_view, G_CONNECT_SWAPPED); g_signal_connect_object (icon_container, "get_stored_layout_timestamp", G_CALLBACK (get_stored_layout_timestamp), icon_view, 0); g_signal_connect_object (icon_container, "store_layout_timestamp", G_CALLBACK (store_layout_timestamp), icon_view, 0); gtk_container_add (GTK_CONTAINER (icon_view), GTK_WIDGET (icon_container)); nemo_icon_view_update_click_mode (icon_view); nemo_icon_view_update_click_to_rename_mode (icon_view); gtk_widget_show (GTK_WIDGET (icon_container)); return icon_container; } /* Handles an URL received from Mozilla */ static void icon_view_handle_netscape_url (NemoIconContainer *container, const char *encoded_url, const char *target_uri, GdkDragAction action, int x, int y, NemoIconView *view) { nemo_view_handle_netscape_url_drop (NEMO_VIEW (view), encoded_url, target_uri, action, x, y); } static void icon_view_handle_uri_list (NemoIconContainer *container, const char *item_uris, const char *target_uri, GdkDragAction action, int x, int y, NemoIconView *view) { nemo_view_handle_uri_list_drop (NEMO_VIEW (view), item_uris, target_uri, action, x, y); } static void icon_view_handle_text (NemoIconContainer *container, const char *text, const char *target_uri, GdkDragAction action, int x, int y, NemoIconView *view) { nemo_view_handle_text_drop (NEMO_VIEW (view), text, target_uri, action, x, y); } static void icon_view_handle_raw (NemoIconContainer *container, const char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y, NemoIconView *view) { nemo_view_handle_raw_drop (NEMO_VIEW (view), raw_data, length, target_uri, direct_save_uri, action, x, y); } static char * icon_view_get_first_visible_file (NemoView *view) { NemoFile *file; NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (view); file = NEMO_FILE (nemo_icon_container_get_first_visible_icon (get_icon_container (icon_view))); if (file) { return nemo_file_get_uri (file); } return NULL; } static void icon_view_scroll_to_file (NemoView *view, const char *uri) { NemoFile *file; NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (view); if (uri != NULL) { /* Only if existing, since we don't want to add the file to the directory if it has been removed since then */ file = nemo_file_get_existing_by_uri (uri); if (file != NULL) { nemo_icon_container_scroll_to_icon (get_icon_container (icon_view), NEMO_ICON_CONTAINER_ICON_DATA (file)); nemo_file_unref (file); } } } static const char * nemo_icon_view_get_id (NemoView *view) { if (nemo_icon_view_is_compact (NEMO_ICON_VIEW (view))) { return FM_COMPACT_VIEW_ID; } return NEMO_ICON_VIEW_ID; } static void set_compact_view (NemoIconView *icon_view, gboolean compact) { icon_view->details->compact = compact; if (compact) { nemo_icon_container_set_layout_mode (get_icon_container (icon_view), gtk_widget_get_direction (GTK_WIDGET(icon_view)) == GTK_TEXT_DIR_RTL ? NEMO_ICON_LAYOUT_T_B_R_L : NEMO_ICON_LAYOUT_T_B_L_R); nemo_icon_container_set_forced_icon_size (get_icon_container (icon_view), NEMO_COMPACT_FORCED_ICON_SIZE); } else { nemo_icon_container_set_layout_mode (get_icon_container (icon_view), gtk_widget_get_direction (GTK_WIDGET(icon_view)) == GTK_TEXT_DIR_RTL ? NEMO_ICON_LAYOUT_R_L_T_B : NEMO_ICON_LAYOUT_L_R_T_B); nemo_icon_container_set_forced_icon_size (get_icon_container (icon_view), 0); } } static void nemo_icon_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (object); switch (prop_id) { case PROP_COMPACT: set_compact_view (icon_view, g_value_get_boolean (value)); break; case PROP_SUPPORTS_AUTO_LAYOUT: icon_view->details->supports_auto_layout = g_value_get_boolean (value); break; case PROP_IS_DESKTOP: icon_view->details->is_desktop = g_value_get_boolean (value); break; case PROP_SUPPORTS_KEEP_ALIGNED: icon_view->details->supports_keep_aligned = g_value_get_boolean (value); break; case PROP_SUPPORTS_LABELS_BESIDE_ICONS: icon_view->details->supports_labels_beside_icons = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_icon_view_finalize (GObject *object) { NemoIconView *icon_view; icon_view = NEMO_ICON_VIEW (object); g_free (icon_view->details); g_signal_handlers_disconnect_by_func (nemo_preferences, default_sort_order_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_preferences, default_sort_in_reverse_order_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_preferences, image_display_policy_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, default_zoom_level_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, labels_beside_icons_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_icon_view_preferences, text_attribute_names_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_compact_view_preferences, default_zoom_level_changed_callback, icon_view); g_signal_handlers_disconnect_by_func (nemo_compact_view_preferences, all_columns_same_width_changed_callback, icon_view); G_OBJECT_CLASS (nemo_icon_view_parent_class)->finalize (object); } static void nemo_icon_view_constructed (GObject *object) { NemoIconView *icon_view; NemoIconContainer *icon_container; icon_view = NEMO_ICON_VIEW (object); G_OBJECT_CLASS (nemo_icon_view_parent_class)->constructed (G_OBJECT (icon_view)); g_return_if_fail (gtk_bin_get_child (GTK_BIN (icon_view)) == NULL); icon_container = create_icon_container (icon_view); /* Set our default layout mode */ if (!icon_view->details->is_desktop) { nemo_icon_container_set_layout_mode (icon_container, gtk_widget_get_direction (GTK_WIDGET(icon_container)) == GTK_TEXT_DIR_RTL ? NEMO_ICON_LAYOUT_R_L_T_B : NEMO_ICON_LAYOUT_L_R_T_B); } g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DEFAULT_SORT_ORDER, G_CALLBACK (default_sort_order_changed_callback), icon_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER, G_CALLBACK (default_sort_in_reverse_order_changed_callback), icon_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, G_CALLBACK (image_display_policy_changed_callback), icon_view); g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, G_CALLBACK (default_zoom_level_changed_callback), icon_view); g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS, G_CALLBACK (labels_beside_icons_changed_callback), icon_view); g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_CAPTIONS, G_CALLBACK (text_attribute_names_changed_callback), icon_view); g_signal_connect_swapped (nemo_compact_view_preferences, "changed::" NEMO_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL, G_CALLBACK (default_zoom_level_changed_callback), icon_view); g_signal_connect_swapped (nemo_compact_view_preferences, "changed::" NEMO_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH, G_CALLBACK (all_columns_same_width_changed_callback), icon_view); g_signal_connect_object (get_icon_container (icon_view), "handle_netscape_url", G_CALLBACK (icon_view_handle_netscape_url), icon_view, 0); g_signal_connect_object (get_icon_container (icon_view), "handle_uri_list", G_CALLBACK (icon_view_handle_uri_list), icon_view, 0); g_signal_connect_object (get_icon_container (icon_view), "handle_text", G_CALLBACK (icon_view_handle_text), icon_view, 0); g_signal_connect_object (get_icon_container (icon_view), "handle_raw", G_CALLBACK (icon_view_handle_raw), icon_view, 0); icon_view->details->clipboard_handler_id = g_signal_connect (nemo_clipboard_monitor_get (), "clipboard_info", G_CALLBACK (icon_view_notify_clipboard_info), icon_view); nemo_icon_container_set_is_desktop (icon_container, FALSE); } static void nemo_icon_view_class_init (NemoIconViewClass *klass) { NemoViewClass *nemo_view_class; GObjectClass *oclass; klass->use_grid_container = FALSE; nemo_view_class = NEMO_VIEW_CLASS (klass); oclass = G_OBJECT_CLASS (klass); oclass->set_property = nemo_icon_view_set_property; oclass->finalize = nemo_icon_view_finalize; oclass->constructed = nemo_icon_view_constructed; GTK_WIDGET_CLASS (klass)->destroy = nemo_icon_view_destroy; GTK_WIDGET_CLASS (klass)->screen_changed = nemo_icon_view_screen_changed; GTK_WIDGET_CLASS (klass)->scroll_event = nemo_icon_view_scroll_event; nemo_view_class->add_file = nemo_icon_view_add_file; nemo_view_class->begin_loading = nemo_icon_view_begin_loading; nemo_view_class->bump_zoom_level = nemo_icon_view_bump_zoom_level; nemo_view_class->can_rename_file = nemo_icon_view_can_rename_file; nemo_view_class->can_zoom_in = nemo_icon_view_can_zoom_in; nemo_view_class->can_zoom_out = nemo_icon_view_can_zoom_out; nemo_view_class->clear = nemo_icon_view_clear; nemo_view_class->end_loading = nemo_icon_view_end_loading; nemo_view_class->file_changed = nemo_icon_view_file_changed; nemo_view_class->get_selected_icon_locations = nemo_icon_view_get_selected_icon_locations; nemo_view_class->get_selection = nemo_icon_view_get_selection; nemo_view_class->peek_selection = nemo_icon_view_peek_selection; nemo_view_class->get_selection_count = nemo_icon_view_get_selection_count; nemo_view_class->get_selection_for_file_transfer = nemo_icon_view_get_selection; nemo_view_class->get_item_count = nemo_icon_view_get_item_count; nemo_view_class->is_empty = nemo_icon_view_is_empty; nemo_view_class->remove_file = nemo_icon_view_remove_file; nemo_view_class->reset_to_defaults = nemo_icon_view_reset_to_defaults; nemo_view_class->restore_default_zoom_level = nemo_icon_view_restore_default_zoom_level; nemo_view_class->get_default_zoom_level = nemo_icon_view_get_default_zoom_level; nemo_view_class->reveal_selection = nemo_icon_view_reveal_selection; nemo_view_class->select_all = nemo_icon_view_select_all; nemo_view_class->set_selection = nemo_icon_view_set_selection; nemo_view_class->invert_selection = nemo_icon_view_invert_selection; nemo_view_class->compare_files = compare_files; nemo_view_class->zoom_to_level = nemo_icon_view_zoom_to_level; nemo_view_class->get_zoom_level = nemo_icon_view_get_zoom_level; nemo_view_class->click_policy_changed = nemo_icon_view_click_policy_changed; nemo_view_class->click_to_rename_mode_changed = nemo_icon_view_click_to_rename_mode_changed; nemo_view_class->merge_menus = nemo_icon_view_merge_menus; nemo_view_class->unmerge_menus = nemo_icon_view_unmerge_menus; nemo_view_class->sort_directories_first_changed = nemo_icon_view_sort_directories_first_changed; nemo_view_class->start_renaming_file = nemo_icon_view_start_renaming_file; nemo_view_class->update_menus = nemo_icon_view_update_menus; nemo_view_class->using_manual_layout = nemo_icon_view_using_manual_layout; nemo_view_class->widget_to_file_operation_position = nemo_icon_view_widget_to_file_operation_position; nemo_view_class->get_view_id = nemo_icon_view_get_id; nemo_view_class->get_first_visible_file = icon_view_get_first_visible_file; nemo_view_class->scroll_to_file = icon_view_scroll_to_file; properties[PROP_COMPACT] = g_param_spec_boolean ("compact", "Compact", "Whether this view provides a compact listing", FALSE, G_PARAM_WRITABLE); properties[PROP_SUPPORTS_AUTO_LAYOUT] = g_param_spec_boolean ("supports-auto-layout", "Supports auto layout", "Whether this view supports auto layout", TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_IS_DESKTOP] = g_param_spec_boolean ("is-desktop", "Is a desktop view", "Whether this view is on a desktop", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_SUPPORTS_KEEP_ALIGNED] = g_param_spec_boolean ("supports-keep-aligned", "Supports keep aligned", "Whether this view supports keep aligned", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_SUPPORTS_LABELS_BESIDE_ICONS] = g_param_spec_boolean ("supports-labels-beside-icons", "Supports labels beside icons", "Whether this view supports labels beside icons", TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } static void nemo_icon_view_init (NemoIconView *icon_view) { icon_view->details = g_new0 (NemoIconViewDetails, 1); icon_view->details->sort = &sort_criteria[0]; } static NemoView * nemo_icon_view_create (NemoWindowSlot *slot) { NemoIconView *view; view = g_object_new (NEMO_TYPE_ICON_VIEW, "window-slot", slot, NULL); #if GTK_CHECK_VERSION (3, 20, 0) gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(view)), GTK_STYLE_CLASS_VIEW); #endif set_compact_view (view, FALSE); return NEMO_VIEW (view); } static NemoView * nemo_compact_view_create (NemoWindowSlot *slot) { NemoIconView *view; view = g_object_new (NEMO_TYPE_ICON_VIEW, "window-slot", slot, NULL); #if GTK_CHECK_VERSION (3, 20, 0) gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(view)), GTK_STYLE_CLASS_VIEW); #endif set_compact_view (view, TRUE); return NEMO_VIEW (view); } static gboolean nemo_icon_view_supports_uri (const char *uri, GFileType file_type, const char *mime_type) { if (file_type == G_FILE_TYPE_DIRECTORY) { return TRUE; } if (strcmp (mime_type, NEMO_SAVED_SEARCH_MIMETYPE) == 0){ return TRUE; } if (g_str_has_prefix (uri, "trash:")) { return TRUE; } if (g_str_has_prefix (uri, EEL_SEARCH_URI)) { return TRUE; } return FALSE; } #define TRANSLATE_VIEW_INFO(view_info) \ view_info.view_combo_label = _(view_info.view_combo_label); \ view_info.view_menu_label_with_mnemonic = _(view_info.view_menu_label_with_mnemonic); \ view_info.error_label = _(view_info.error_label); \ view_info.startup_error_label = _(view_info.startup_error_label); \ view_info.display_location_label = _(view_info.display_location_label); \ static NemoViewInfo nemo_icon_view = { (char *)NEMO_ICON_VIEW_ID, /* translators: this is used in the view selection dropdown * of navigation windows and in the preferences dialog */ (char *)N_("Icon View"), /* translators: this is used in the view menu */ (char *)N_("_Icons"), (char *)N_("The icon view encountered an error."), (char *)N_("The icon view encountered an error while starting up."), (char *)N_("Display this location with the icon view."), nemo_icon_view_create, nemo_icon_view_supports_uri }; static NemoViewInfo nemo_compact_view = { (char *)FM_COMPACT_VIEW_ID, /* translators: this is used in the view selection dropdown * of navigation windows and in the preferences dialog */ (char *)N_("Compact View"), /* translators: this is used in the view menu */ (char *)N_("_Compact"), (char *)N_("The compact view encountered an error."), (char *)N_("The compact view encountered an error while starting up."), (char *)N_("Display this location with the compact view."), nemo_compact_view_create, nemo_icon_view_supports_uri }; gboolean nemo_icon_view_is_compact (NemoIconView *view) { return view->details->compact; } void nemo_icon_view_register (void) { TRANSLATE_VIEW_INFO (nemo_icon_view) nemo_view_factory_register (&nemo_icon_view); } void nemo_icon_view_compact_register (void) { TRANSLATE_VIEW_INFO (nemo_compact_view) nemo_view_factory_register (&nemo_compact_view); } nemo-4.4.2/src/nemo-icon-view.h000066400000000000000000000104621357442400300162600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-icon-view.h - interface for icon view of directory. * * Copyright (C) 2000 Eazel, Inc. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: John Sullivan * */ #ifndef NEMO_ICON_VIEW_H #define NEMO_ICON_VIEW_H #include "nemo-view.h" typedef struct NemoIconView NemoIconView; typedef struct NemoIconViewClass NemoIconViewClass; #define NEMO_TYPE_ICON_VIEW nemo_icon_view_get_type() #define NEMO_ICON_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_ICON_VIEW, NemoIconView)) #define NEMO_ICON_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_ICON_VIEW, NemoIconViewClass)) #define NEMO_IS_ICON_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_ICON_VIEW)) #define NEMO_IS_ICON_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_ICON_VIEW)) #define NEMO_ICON_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_ICON_VIEW, NemoIconViewClass)) #define NEMO_ICON_VIEW_ID "OAFIID:Nemo_File_Manager_Icon_View" #define FM_COMPACT_VIEW_ID "OAFIID:Nemo_File_Manager_Compact_View" typedef struct NemoIconViewDetails NemoIconViewDetails; struct NemoIconView { NemoView parent; NemoIconViewDetails *details; }; struct NemoIconViewClass { NemoViewClass parent_class; gboolean use_grid_container; }; /* GObject support */ GType nemo_icon_view_get_type (void); int nemo_icon_view_compare_files (NemoIconView *icon_view, NemoFile *a, NemoFile *b); gboolean nemo_icon_view_is_compact (NemoIconView *icon_view); void nemo_icon_view_register (void); void nemo_icon_view_compact_register (void); NemoIconContainer * nemo_icon_view_get_icon_container (NemoIconView *view); void nemo_icon_view_set_sort_criterion_by_sort_type (NemoIconView *icon_view, NemoFileSortType sort_type); void nemo_icon_view_set_directory_keep_aligned (NemoIconView *icon_view, NemoFile *file, gboolean keep_aligned); gchar *nemo_icon_view_get_directory_sort_by (NemoIconView *icon_view, NemoFile *file); gboolean nemo_icon_view_get_directory_sort_reversed (NemoIconView *icon_view, NemoFile *file); void nemo_icon_view_flip_sort_reversed (NemoIconView *icon_view); gboolean nemo_icon_view_set_sort_reversed (NemoIconView *icon_view, gboolean new_value, gboolean set_metadata); void nemo_icon_view_set_directory_horizontal_layout (NemoIconView *icon_view, NemoFile *file, gboolean horizontal); gboolean nemo_icon_view_get_directory_horizontal_layout (NemoIconView *icon_view, NemoFile *file); void nemo_icon_view_set_directory_grid_adjusts (NemoIconView *icon_view, NemoFile *file, gint horizontal, gint vertical); void nemo_icon_view_get_directory_grid_adjusts (NemoIconView *icon_view, NemoFile *file, gint *horizontal, gint *vertical); #endif /* NEMO_ICON_VIEW_H */ nemo-4.4.2/src/nemo-image-properties-page.c000066400000000000000000000514241357442400300205440ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2004 Red Hat, Inc * Copyright (c) 2007 Novell, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson * XMP support by Hubert Figuiere */ #include #include "nemo-image-properties-page.h" #include #include #include #include #include #include #include #ifdef HAVE_EXIF #include #include #include #endif #ifdef HAVE_EXEMPI #include #include #endif #define LOAD_BUFFER_SIZE 8192 struct NemoImagePropertiesPageDetails { GCancellable *cancellable; GtkWidget *grid; GdkPixbufLoader *loader; gboolean got_size; gboolean pixbuf_still_loading; char buffer[LOAD_BUFFER_SIZE]; int width; int height; #ifdef HAVE_EXIF ExifLoader *exifldr; #endif /*HAVE_EXIF*/ #ifdef HAVE_EXEMPI XmpPtr xmp; #endif }; #ifdef HAVE_EXIF struct ExifAttribute { ExifTag tag; char *value; gboolean found; }; #endif /*HAVE_EXIF*/ enum { PROP_URI }; typedef struct { GObject parent; } NemoImagePropertiesPageProvider; typedef struct { GObjectClass parent; } NemoImagePropertiesPageProviderClass; static GType nemo_image_properties_page_provider_get_type (void); static void property_page_provider_iface_init (NemoPropertyPageProviderIface *iface); G_DEFINE_TYPE (NemoImagePropertiesPage, nemo_image_properties_page, GTK_TYPE_BOX); G_DEFINE_TYPE_WITH_CODE (NemoImagePropertiesPageProvider, nemo_image_properties_page_provider, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (NEMO_TYPE_PROPERTY_PAGE_PROVIDER, property_page_provider_iface_init)); static void nemo_image_properties_page_finalize (GObject *object) { NemoImagePropertiesPage *page; page = NEMO_IMAGE_PROPERTIES_PAGE (object); if (page->details->cancellable) { g_cancellable_cancel (page->details->cancellable); g_object_unref (page->details->cancellable); page->details->cancellable = NULL; } G_OBJECT_CLASS (nemo_image_properties_page_parent_class)->finalize (object); } static void file_close_callback (GObject *object, GAsyncResult *res, gpointer data) { NemoImagePropertiesPage *page; GInputStream *stream; page = NEMO_IMAGE_PROPERTIES_PAGE (data); stream = G_INPUT_STREAM (object); g_input_stream_close_finish (stream, res, NULL); g_object_unref (page->details->cancellable); page->details->cancellable = NULL; } static void append_item (NemoImagePropertiesPage *page, const char *name, const char *value) { GtkWidget *name_label; GtkWidget *label; PangoAttrList *attrs; name_label = gtk_label_new (name); attrs = pango_attr_list_new (); pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); gtk_label_set_attributes (GTK_LABEL (name_label), attrs); pango_attr_list_unref (attrs); gtk_misc_set_alignment (GTK_MISC (name_label), 0, 0); gtk_container_add (GTK_CONTAINER (page->details->grid), name_label); gtk_widget_show (name_label); if (value != NULL) { label = gtk_label_new (value); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_grid_attach_next_to (GTK_GRID (page->details->grid), label, name_label, GTK_POS_RIGHT, 1, 1); gtk_widget_show (label); } } #ifdef HAVE_EXIF static char * exif_string_to_utf8 (const char *exif_str) { char *utf8_str; if (g_utf8_validate (exif_str, -1, NULL)) { return g_strdup (exif_str); } utf8_str = g_locale_to_utf8 (exif_str, -1, NULL, NULL, NULL); if (utf8_str != NULL) { return utf8_str; } return eel_make_valid_utf8 (exif_str); } static void exif_content_callback (ExifContent *content, gpointer data) { struct ExifAttribute *attribute; char b[1024]; attribute = (struct ExifAttribute *)data; if (attribute->found) { return; } attribute->value = g_strdup (exif_content_get_value (content, attribute->tag, b, sizeof(b))); if (attribute->value != NULL) { attribute->found = TRUE; } } static char * exifdata_get_tag_name_utf8 (ExifTag tag) { return exif_string_to_utf8 (exif_tag_get_name (tag)); } static char * exifdata_get_tag_value_utf8 (ExifData *data, ExifTag tag) { struct ExifAttribute attribute; char *utf8_value; attribute.tag = tag; attribute.value = NULL; attribute.found = FALSE; exif_data_foreach_content (data, exif_content_callback, &attribute); if (attribute.found) { utf8_value = exif_string_to_utf8 (attribute.value); g_free (attribute.value); } else { utf8_value = NULL; } return utf8_value; } static gboolean append_tag_value_pair (NemoImagePropertiesPage *page, ExifData *data, ExifTag tag, char *description) { char *utf_attribute; char *utf_value; utf_attribute = exifdata_get_tag_name_utf8 (tag); utf_value = exifdata_get_tag_value_utf8 (data, tag); if ((utf_attribute == NULL) || (utf_value == NULL)) { g_free (utf_attribute); g_free (utf_value); return FALSE; } append_item (page, description ? description : utf_attribute, utf_value); g_free (utf_attribute); g_free (utf_value); return TRUE; } #endif /*HAVE_EXIF*/ #ifdef HAVE_EXEMPI static void append_xmp_value_pair (NemoImagePropertiesPage *page, XmpPtr xmp, const char *ns, const char *propname, char *descr) { uint32_t options; XmpStringPtr value; value = xmp_string_new(); if (xmp_get_property (xmp, ns, propname, value, &options)) { if (XMP_IS_PROP_SIMPLE (options)) { append_item (page, descr, xmp_string_cstr (value)); } else if (XMP_IS_PROP_ARRAY (options)) { XmpIteratorPtr iter; iter = xmp_iterator_new (xmp, ns, propname, XMP_ITER_JUSTLEAFNODES); if (iter) { GString *str; gboolean first = TRUE; str = g_string_new (NULL); while (xmp_iterator_next (iter, NULL, NULL, value, &options) && !XMP_IS_PROP_QUALIFIER(options)) { if (!first) { g_string_append_printf (str, ", "); } else { first = FALSE; } g_string_append_printf (str, "%s", xmp_string_cstr(value)); } xmp_iterator_free(iter); append_item (page, descr, g_string_free (str, FALSE)); } } } xmp_string_free(value); } #endif /*HAVE EXEMPI*/ static gboolean append_option_value_pair (NemoImagePropertiesPage *page, GdkPixbuf *pixbuf, const char *key, char *description) { const char *value; value = gdk_pixbuf_get_option (pixbuf, key); if (value == NULL) return FALSE; append_item (page, description, value); return TRUE; } static void append_basic_info (NemoImagePropertiesPage *page) { GdkPixbufFormat *format; char *name; char *desc; char *value; format = gdk_pixbuf_loader_get_format (page->details->loader); name = gdk_pixbuf_format_get_name (format); desc = gdk_pixbuf_format_get_description (format); value = g_strdup_printf ("%s (%s)", name, desc); g_free (name); g_free (desc); append_item (page, _("Image Type"), value); g_free (value); value = g_strdup_printf (ngettext ("%d pixel", "%d pixels", page->details->width), page->details->width); append_item (page, _("Width"), value); g_free (value); value = g_strdup_printf (ngettext ("%d pixel", "%d pixels", page->details->height), page->details->height); append_item (page, _("Height"), value); g_free (value); } static void append_options_info (NemoImagePropertiesPage *page) { GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_loader_get_pixbuf (page->details->loader); if (pixbuf == NULL) return; if (!append_option_value_pair (page, pixbuf, "Title", _("Title"))) append_option_value_pair (page, pixbuf, "tEXt::Title", _("Title")); if (!append_option_value_pair (page, pixbuf, "Author", _("Author"))) append_option_value_pair (page, pixbuf, "tEXt::Author", _("Author")); append_option_value_pair (page, pixbuf, "tEXt::Description", _("Description")); append_option_value_pair (page, pixbuf, "tEXt::Copyright", _("Copyright")); append_option_value_pair (page, pixbuf, "tEXt::Creation Time", _("Created On")); append_option_value_pair (page, pixbuf, "tEXt::Software", _("Created By")); append_option_value_pair (page, pixbuf, "tEXt::Disclaimer", _("Disclaimer")); append_option_value_pair (page, pixbuf, "tEXt::Warning", _("Warning")); append_option_value_pair (page, pixbuf, "tEXt::Source", _("Source")); append_option_value_pair (page, pixbuf, "tEXt::Comment", _("Comment")); } static void append_exif_info (NemoImagePropertiesPage *page) { #ifdef HAVE_EXIF ExifData *exifdata; exifdata = exif_loader_get_data (page->details->exifldr); if (exifdata == NULL) return; if (exifdata->ifd[0] && exifdata->ifd[0]->count) { append_tag_value_pair (page, exifdata, EXIF_TAG_MAKE, _("Camera Brand")); append_tag_value_pair (page, exifdata, EXIF_TAG_MODEL, _("Camera Model")); /* Choose which date to show in order of relevance */ if (!append_tag_value_pair (page, exifdata, EXIF_TAG_DATE_TIME_ORIGINAL, _("Date Taken"))) { if (!append_tag_value_pair (page, exifdata, EXIF_TAG_DATE_TIME_DIGITIZED, _("Date Digitized"))) { append_tag_value_pair (page, exifdata, EXIF_TAG_DATE_TIME, _("Date Modified")); } } append_tag_value_pair (page, exifdata, EXIF_TAG_EXPOSURE_TIME, _("Exposure Time")); append_tag_value_pair (page, exifdata, EXIF_TAG_APERTURE_VALUE, _("Aperture Value")); append_tag_value_pair (page, exifdata, EXIF_TAG_ISO_SPEED_RATINGS, _("ISO Speed Rating")); append_tag_value_pair (page, exifdata, EXIF_TAG_FLASH,_("Flash Fired")); append_tag_value_pair (page, exifdata, EXIF_TAG_METERING_MODE, _("Metering Mode")); append_tag_value_pair (page, exifdata, EXIF_TAG_EXPOSURE_PROGRAM, _("Exposure Program")); append_tag_value_pair (page, exifdata, EXIF_TAG_FOCAL_LENGTH,_("Focal Length")); append_tag_value_pair (page, exifdata, EXIF_TAG_SOFTWARE, _("Software")); } exif_data_unref (exifdata); #endif } static void append_xmp_info (NemoImagePropertiesPage *page) { #ifdef HAVE_EXEMPI if (page->details->xmp == NULL) return; append_xmp_value_pair (page, page->details->xmp, NS_IPTC4XMP, "Location", _("Location")); append_xmp_value_pair (page, page->details->xmp, NS_DC, "description", _("Description")); append_xmp_value_pair (page, page->details->xmp, NS_DC, "subject", _("Keywords")); append_xmp_value_pair (page, page->details->xmp, NS_DC, "creator", _("Creator")); append_xmp_value_pair (page, page->details->xmp, NS_DC, "rights", _("Copyright")); append_xmp_value_pair (page, page->details->xmp, NS_XAP,"Rating", _("Rating")); /* TODO add CC licenses */ #endif /*HAVE EXEMPI*/ } static void load_finished (NemoImagePropertiesPage *page) { GtkWidget *label; label = gtk_grid_get_child_at (GTK_GRID (page->details->grid), 0, 0); gtk_container_remove (GTK_CONTAINER (page->details->grid), label); if (page->details->loader != NULL) { gdk_pixbuf_loader_close (page->details->loader, NULL); } if (page->details->got_size) { append_basic_info (page); append_options_info (page); append_exif_info (page); append_xmp_info (page); } else { append_item (page, _("Failed to load image information"), NULL); } if (page->details->loader != NULL) { g_object_unref (page->details->loader); page->details->loader = NULL; } #ifdef HAVE_EXIF if (page->details->exifldr != NULL) { exif_loader_unref (page->details->exifldr); page->details->exifldr = NULL; } #endif /*HAVE_EXIF*/ #ifdef HAVE_EXEMPI if (page->details->xmp != NULL) { xmp_free (page->details->xmp); page->details->xmp = NULL; } #endif } static void file_read_callback (GObject *object, GAsyncResult *res, gpointer data) { NemoImagePropertiesPage *page; GInputStream *stream; gssize count_read; GError *error; int exif_still_loading; gboolean done_reading; page = NEMO_IMAGE_PROPERTIES_PAGE (data); stream = G_INPUT_STREAM (object); error = NULL; done_reading = FALSE; count_read = g_input_stream_read_finish (stream, res, &error); if (count_read > 0) { g_assert (count_read <= (int)sizeof(page->details->buffer)); #ifdef HAVE_EXIF exif_still_loading = exif_loader_write (page->details->exifldr, (guchar *) page->details->buffer, count_read); #else exif_still_loading = 0; #endif if (page->details->pixbuf_still_loading) { if (!gdk_pixbuf_loader_write (page->details->loader, (const guchar *) page->details->buffer, count_read, NULL)) { page->details->pixbuf_still_loading = FALSE; } } if (page->details->pixbuf_still_loading || (exif_still_loading == 1)) { g_input_stream_read_async (G_INPUT_STREAM (stream), page->details->buffer, sizeof (page->details->buffer), 0, page->details->cancellable, file_read_callback, page); } else { done_reading = TRUE; } } else { /* either EOF, cancelled or an error occurred */ done_reading = TRUE; } if (error != NULL) { char *uri = g_file_get_uri (G_FILE (object)); g_warning ("Error reading %s: %s", uri, error->message); g_free (uri); g_clear_error (&error); } if (done_reading) { load_finished (page); g_input_stream_close_async (stream, 0, page->details->cancellable, file_close_callback, page); } } static void size_prepared_callback (GdkPixbufLoader *loader, int width, int height, gpointer callback_data) { NemoImagePropertiesPage *page; page = NEMO_IMAGE_PROPERTIES_PAGE (callback_data); page->details->height = height; page->details->width = width; page->details->got_size = TRUE; page->details->pixbuf_still_loading = FALSE; } typedef struct { NemoImagePropertiesPage *page; NemoFileInfo *info; } FileOpenData; static void file_open_callback (GObject *object, GAsyncResult *res, gpointer user_data) { FileOpenData *data = user_data; NemoImagePropertiesPage *page = data->page; GFile *file; GFileInputStream *stream; GError *error; char *uri; file = G_FILE (object); uri = g_file_get_uri (file); error = NULL; stream = g_file_read_finish (file, res, &error); if (stream) { char *mime_type; mime_type = nemo_file_info_get_mime_type (data->info); page->details->loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error); if (error != NULL) { g_warning ("Error creating loader for %s: %s", uri, error->message); g_clear_error (&error); } page->details->pixbuf_still_loading = TRUE; page->details->width = 0; page->details->height = 0; #ifdef HAVE_EXIF page->details->exifldr = exif_loader_new (); #endif /*HAVE_EXIF*/ g_free (mime_type); g_signal_connect (page->details->loader, "size_prepared", G_CALLBACK (size_prepared_callback), page); g_input_stream_read_async (G_INPUT_STREAM (stream), page->details->buffer, sizeof (page->details->buffer), 0, page->details->cancellable, file_read_callback, page); g_object_unref (stream); } else { g_warning ("Error reading %s: %s", uri, error->message); g_clear_error (&error); load_finished (page); } g_free (uri); g_free (data); } static void load_location (NemoImagePropertiesPage *page, NemoFileInfo *info) { GFile *file; char *uri; FileOpenData *data; g_assert (NEMO_IS_IMAGE_PROPERTIES_PAGE (page)); g_assert (info != NULL); page->details->cancellable = g_cancellable_new (); uri = nemo_file_info_get_uri (info); file = g_file_new_for_uri (uri); #ifdef HAVE_EXEMPI { /* Current Exempi does not support setting custom IO to be able to use Gnome-vfs */ /* So it will only work with local files. Future version might remove this limitation */ XmpFilePtr xf; char *localname; localname = g_filename_from_uri (uri, NULL, NULL); if (localname) { xf = xmp_files_open_new (localname, 0); page->details->xmp = xmp_files_get_new_xmp (xf); /* only load when loading */ xmp_files_close (xf, 0); g_free (localname); } else { page->details->xmp = NULL; } } #endif /*HAVE_EXEMPI*/ data = g_new0 (FileOpenData, 1); data->page = page; data->info = info; g_file_read_async (file, 0, page->details->cancellable, file_open_callback, data); g_object_unref (file); g_free (uri); } static void nemo_image_properties_page_class_init (NemoImagePropertiesPageClass *class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (class); object_class->finalize = nemo_image_properties_page_finalize; g_type_class_add_private (object_class, sizeof(NemoImagePropertiesPageDetails)); } static void nemo_image_properties_page_init (NemoImagePropertiesPage *page) { GtkWidget *sw; page->details = G_TYPE_INSTANCE_GET_PRIVATE (page, NEMO_TYPE_IMAGE_PROPERTIES_PAGE, NemoImagePropertiesPageDetails); gtk_orientable_set_orientation (GTK_ORIENTABLE (page), GTK_ORIENTATION_VERTICAL); gtk_box_set_homogeneous (GTK_BOX (page), FALSE); gtk_box_set_spacing (GTK_BOX (page), 0); gtk_container_set_border_width (GTK_CONTAINER (page), 0); sw = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (sw), 0); gtk_widget_set_vexpand (GTK_WIDGET (sw), TRUE); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (page), sw, FALSE, TRUE, 2); page->details->grid = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (page->details->grid), 6); gtk_orientable_set_orientation (GTK_ORIENTABLE (page->details->grid), GTK_ORIENTATION_VERTICAL); gtk_grid_set_row_spacing (GTK_GRID (page->details->grid), 6); gtk_grid_set_column_spacing (GTK_GRID (page->details->grid), 20); append_item (page, _("Loading..."), NULL); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), page->details->grid); gtk_widget_show_all (GTK_WIDGET (page)); } static gboolean is_mime_type_supported (const char *mime_type) { gboolean supported; GSList *formats; GSList *l; supported = FALSE; formats = gdk_pixbuf_get_formats (); for (l = formats; supported == FALSE && l != NULL; l = l->next) { GdkPixbufFormat *format = l->data; char **mime_types = gdk_pixbuf_format_get_mime_types (format); int i; for (i = 0; mime_types[i] != NULL; i++) { if (strcmp (mime_types[i], mime_type) == 0) { supported = TRUE; break; } } g_strfreev (mime_types); } g_slist_free (formats); return supported; } static GList * get_property_pages (NemoPropertyPageProvider *provider, GList *files) { GList *pages; NemoFileInfo *file; char *mime_type; /* Only show the property page if 1 file is selected */ if (!files || files->next != NULL) { return NULL; } pages = NULL; file = NEMO_FILE_INFO (files->data); mime_type = nemo_file_info_get_mime_type (file); if (mime_type != NULL && is_mime_type_supported (mime_type)) { NemoImagePropertiesPage *page; NemoPropertyPage *real_page; page = g_object_new (nemo_image_properties_page_get_type (), NULL); load_location (page, file); real_page = nemo_property_page_new ("NemoImagePropertiesPage::property_page", gtk_label_new (_("Image")), GTK_WIDGET (page)); pages = g_list_append (pages, real_page); } g_free (mime_type); return pages; } static void property_page_provider_iface_init (NemoPropertyPageProviderIface *iface) { iface->get_pages = get_property_pages; } static void nemo_image_properties_page_provider_init (NemoImagePropertiesPageProvider *sidebar) { } static void nemo_image_properties_page_provider_class_init (NemoImagePropertiesPageProviderClass *class) { } void nemo_image_properties_page_register (void) { nemo_module_add_type (nemo_image_properties_page_provider_get_type ()); } nemo-4.4.2/src/nemo-image-properties-page.h000066400000000000000000000041471357442400300205510ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2004 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson */ #ifndef NEMO_IMAGE_PROPERTIES_PAGE_H #define NEMO_IMAGE_PROPERTIES_PAGE_H #include #define NEMO_TYPE_IMAGE_PROPERTIES_PAGE nemo_image_properties_page_get_type() #define NEMO_IMAGE_PROPERTIES_PAGE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_IMAGE_PROPERTIES_PAGE, NemoImagePropertiesPage)) #define NEMO_IMAGE_PROPERTIES_PAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_IMAGE_PROPERTIES_PAGE, NemoImagePropertiesPageClass)) #define NEMO_IS_IMAGE_PROPERTIES_PAGE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_IMAGE_PROPERTIES_PAGE)) #define NEMO_IS_IMAGE_PROPERTIES_PAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_IMAGE_PROPERTIES_PAGE)) #define NEMO_IMAGE_PROPERTIES_PAGE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_IMAGE_PROPERTIES_PAGE, NemoImagePropertiesPageClass)) typedef struct NemoImagePropertiesPageDetails NemoImagePropertiesPageDetails; typedef struct { GtkBox parent; NemoImagePropertiesPageDetails *details; } NemoImagePropertiesPage; typedef struct { GtkBoxClass parent; } NemoImagePropertiesPageClass; GType nemo_image_properties_page_get_type (void); void nemo_image_properties_page_register (void); #endif /* NEMO_IMAGE_PROPERTIES_PAGE_H */ nemo-4.4.2/src/nemo-interesting-folder-bar.c000066400000000000000000000171601357442400300207230ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include "nemo-interesting-folder-bar.h" #include "nemo-application.h" #include "nemo-view.h" #include #include #include #include #include #define NEMO_INTERESTING_FOLDER_BAR_GET_PRIVATE(o)\ (G_TYPE_INSTANCE_GET_PRIVATE ((o), NEMO_TYPE_INTERESTING_FOLDER_BAR, NemoInterestingFolderBarPrivate)) enum { PROP_VIEW = 1, PROP_TYPE, NUM_PROPERTIES }; enum { INTERESTING_FOLDER_BAR_ACTION_OPEN_DOC = 1, INTERESTING_FOLDER_BAR_SCRIPT_OPEN_DOC }; struct NemoInterestingFolderBarPrivate { NemoView *view; InterestingFolderType type; gulong selection_handler_id; }; G_DEFINE_TYPE (NemoInterestingFolderBar, nemo_interesting_folder_bar, GTK_TYPE_INFO_BAR); static void interesting_folder_bar_response_cb (GtkInfoBar *infobar, gint response_id, gpointer user_data) { NemoInterestingFolderBar *bar; GFile *f = NULL; bar = NEMO_INTERESTING_FOLDER_BAR (infobar); switch (response_id) { case INTERESTING_FOLDER_BAR_ACTION_OPEN_DOC: f = g_file_new_for_path (NEMO_DATADIR "/actions/sample.nemo_action"); if (g_file_query_exists (f, NULL)) nemo_view_activate_file (bar->priv->view, nemo_file_get (f), NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); g_object_unref (f); break; case INTERESTING_FOLDER_BAR_SCRIPT_OPEN_DOC: f = g_file_new_for_path (NEMO_DATADIR "/script-info.md"); if (g_file_query_exists (f, NULL)) nemo_view_activate_file (bar->priv->view, nemo_file_get (f), NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); g_object_unref (f); break; default: break; } } static void nemo_interesting_folder_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoInterestingFolderBar *bar; bar = NEMO_INTERESTING_FOLDER_BAR (object); switch (prop_id) { case PROP_VIEW: bar->priv->view = g_value_get_object (value); break; case PROP_TYPE: bar->priv->type = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_interesting_folder_bar_constructed (GObject *obj) { G_OBJECT_CLASS (nemo_interesting_folder_bar_parent_class)->constructed (obj); NemoInterestingFolderBar *bar = NEMO_INTERESTING_FOLDER_BAR (obj); GtkWidget *content_area, *action_area, *w; GtkWidget *label; content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar)); action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (bar)); gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL); switch (bar->priv->type) { case TYPE_ACTIONS_FOLDER: label = gtk_label_new (_("Actions: Action files can be added to this folder and will appear in the menu.")); w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("More info"), INTERESTING_FOLDER_BAR_ACTION_OPEN_DOC); gtk_widget_set_tooltip_text (w, _("View a sample action file with documentation")); break; case TYPE_SCRIPTS_FOLDER: label = gtk_label_new (_("Scripts: All executable files in this folder will appear in the " "Scripts menu.")); w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("More info"), INTERESTING_FOLDER_BAR_SCRIPT_OPEN_DOC); gtk_widget_set_tooltip_text (w, _("View additional information about creating scripts")); break; case TYPE_NONE_FOLDER: default: label = gtk_label_new ("undefined"); break; } gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (label), "nemo-cluebar-label"); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (content_area), label); g_signal_connect (bar, "response", G_CALLBACK (interesting_folder_bar_response_cb), bar); } static void nemo_interesting_folder_bar_class_init (NemoInterestingFolderBarClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = nemo_interesting_folder_bar_set_property; object_class->constructed = nemo_interesting_folder_bar_constructed; g_object_class_install_property (object_class, PROP_VIEW, g_param_spec_object ("view", "view", "the NemoView", NEMO_TYPE_VIEW, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_TYPE, g_param_spec_int ("type", "type", "the InterestingFolderType", TYPE_NONE_FOLDER, TYPE_SCRIPTS_FOLDER, TYPE_NONE_FOLDER, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (klass, sizeof (NemoInterestingFolderBarPrivate)); } static void nemo_interesting_folder_bar_init (NemoInterestingFolderBar *bar) { bar->priv = NEMO_INTERESTING_FOLDER_BAR_GET_PRIVATE (bar); bar->priv->type = TYPE_NONE_FOLDER; } GtkWidget * nemo_interesting_folder_bar_new (NemoView *view, InterestingFolderType type) { return g_object_new (NEMO_TYPE_INTERESTING_FOLDER_BAR, "view", view, "type", type, NULL); } GtkWidget * nemo_interesting_folder_bar_new_for_location (NemoView *view, GFile *location) { InterestingFolderType type = TYPE_NONE_FOLDER; gchar *path = NULL; GFile *tmp_loc = NULL; path = nemo_action_manager_get_user_directory_path (); tmp_loc = g_file_new_for_path (path); if (g_file_equal (location, tmp_loc)) { type = TYPE_ACTIONS_FOLDER; goto out; } g_free (path); g_object_unref (tmp_loc); path = nemo_get_scripts_directory_path (); tmp_loc = g_file_new_for_path (path); if (g_file_equal (location, tmp_loc)) type = TYPE_SCRIPTS_FOLDER; out: g_free (path); g_object_unref (tmp_loc); return type == TYPE_NONE_FOLDER ? NULL : nemo_interesting_folder_bar_new (view, type); } nemo-4.4.2/src/nemo-interesting-folder-bar.h000066400000000000000000000045621357442400300207320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __NEMO_INTERESTING_FOLDER_BAR_H #define __NEMO_INTERESTING_FOLDER_BAR_H #include "nemo-view.h" #include G_BEGIN_DECLS #define NEMO_TYPE_INTERESTING_FOLDER_BAR (nemo_interesting_folder_bar_get_type ()) #define NEMO_INTERESTING_FOLDER_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_INTERESTING_FOLDER_BAR, NemoInterestingFolderBar)) #define NEMO_INTERESTING_FOLDER_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_INTERESTING_FOLDER_BAR, NemoInterestingFolderBarClass)) #define NEMO_IS_INTERESTING_FOLDER_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_INTERESTING_FOLDER_BAR)) #define NEMO_IS_INTERESTING_FOLDER_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_INTERESTING_FOLDER_BAR)) #define NEMO_INTERESTING_FOLDER_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_INTERESTING_FOLDER_BAR, NemoInterestingFolderBarClass)) typedef struct NemoInterestingFolderBarPrivate NemoInterestingFolderBarPrivate; typedef struct { GtkInfoBar parent; NemoInterestingFolderBarPrivate *priv; } NemoInterestingFolderBar; typedef struct { GtkInfoBarClass parent_class; } NemoInterestingFolderBarClass; typedef enum { TYPE_NONE_FOLDER = 1, TYPE_ACTIONS_FOLDER, TYPE_SCRIPTS_FOLDER } InterestingFolderType; GType nemo_interesting_folder_bar_get_type (void) G_GNUC_CONST; GtkWidget *nemo_interesting_folder_bar_new (NemoView *view, InterestingFolderType type); GtkWidget *nemo_interesting_folder_bar_new_for_location (NemoView *view, GFile *location); G_END_DECLS #endif /* __GS_INTERESTING_FOLDER_BAR_H */ nemo-4.4.2/src/nemo-list-model.c000066400000000000000000001371351357442400300164330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-list-model.h - a GtkTreeModel for file lists. Copyright (C) 2001, 2002 Anders Carlsson Copyright (C) 2003, Soeren Sandmann Copyright (C) 2004, Novell, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Anders Carlsson , Soeren Sandmann (sandmann@daimi.au.dk), Dave Camp */ #include #include "nemo-list-model.h" #include #include #include #include #include #include #include #include #include enum { SUBDIRECTORY_UNLOADED, GET_ICON_SCALE, LAST_SIGNAL }; static GQuark attribute_name_q, attribute_modification_date_q, attribute_date_modified_q; /* msec delay after Loading... dummy row turns into (empty) */ #define LOADING_TO_EMPTY_DELAY 100 static guint list_model_signals[LAST_SIGNAL] = { 0 }; static int nemo_list_model_file_entry_compare_func (gconstpointer a, gconstpointer b, gpointer user_data); static void nemo_list_model_tree_model_init (GtkTreeModelIface *iface); static void nemo_list_model_sortable_init (GtkTreeSortableIface *iface); static void nemo_list_model_multi_drag_source_init (EggTreeMultiDragSourceIface *iface); struct NemoListModelDetails { GSequence *files; GHashTable *directory_reverse_map; /* map from directory to GSequenceIter's */ GHashTable *top_reverse_map; /* map from files in top dir to GSequenceIter's */ int stamp; GQuark sort_attribute; GtkSortType order; gboolean sort_directories_first; GtkTreeView *drag_view; int drag_begin_x; int drag_begin_y; GPtrArray *columns; GList *highlight_files; gboolean temp_unsorted; }; typedef struct { NemoListModel *model; GList *path_list; } DragDataGetInfo; typedef struct FileEntry FileEntry; struct FileEntry { NemoFile *file; GHashTable *reverse_map; /* map from files to GSequenceIter's */ NemoDirectory *subdirectory; FileEntry *parent; GSequence *files; GSequenceIter *ptr; guint loaded : 1; guint expanding : 1; }; G_DEFINE_TYPE_WITH_CODE (NemoListModel, nemo_list_model, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, nemo_list_model_tree_model_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE, nemo_list_model_sortable_init) G_IMPLEMENT_INTERFACE (EGG_TYPE_TREE_MULTI_DRAG_SOURCE, nemo_list_model_multi_drag_source_init)); static const GtkTargetEntry drag_types [] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST }, { (char *)NEMO_ICON_DND_URI_LIST_TYPE, 0, NEMO_ICON_DND_URI_LIST }, }; static GtkTargetList *drag_target_list = NULL; static void file_entry_free (FileEntry *file_entry) { nemo_file_unref (file_entry->file); if (file_entry->reverse_map) { g_hash_table_destroy (file_entry->reverse_map); file_entry->reverse_map = NULL; } if (file_entry->subdirectory != NULL) { nemo_directory_unref (file_entry->subdirectory); } if (file_entry->files != NULL) { g_sequence_free (file_entry->files); } g_free (file_entry); } static GtkTreeModelFlags nemo_list_model_get_flags (GtkTreeModel *tree_model) { return GTK_TREE_MODEL_ITERS_PERSIST; } static int nemo_list_model_get_n_columns (GtkTreeModel *tree_model) { return NEMO_LIST_MODEL_NUM_COLUMNS + NEMO_LIST_MODEL (tree_model)->details->columns->len; } static GType nemo_list_model_get_column_type (GtkTreeModel *tree_model, int index) { switch (index) { case NEMO_LIST_MODEL_FILE_COLUMN: return NEMO_TYPE_FILE; case NEMO_LIST_MODEL_SUBDIRECTORY_COLUMN: return NEMO_TYPE_DIRECTORY; case NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN: case NEMO_LIST_MODEL_SMALLER_ICON_COLUMN: case NEMO_LIST_MODEL_SMALL_ICON_COLUMN: case NEMO_LIST_MODEL_STANDARD_ICON_COLUMN: case NEMO_LIST_MODEL_LARGE_ICON_COLUMN: case NEMO_LIST_MODEL_LARGER_ICON_COLUMN: case NEMO_LIST_MODEL_LARGEST_ICON_COLUMN: return CAIRO_GOBJECT_TYPE_SURFACE; case NEMO_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN: return G_TYPE_BOOLEAN; case NEMO_LIST_MODEL_TEXT_WEIGHT_COLUMN: return G_TYPE_INT; default: if (index < (int)(NEMO_LIST_MODEL_NUM_COLUMNS + NEMO_LIST_MODEL (tree_model)->details->columns->len)) { return G_TYPE_STRING; } else { return G_TYPE_INVALID; } } } static void nemo_list_model_ptr_to_iter (NemoListModel *model, GSequenceIter *ptr, GtkTreeIter *iter) { g_assert (!g_sequence_iter_is_end (ptr)); if (iter != NULL) { iter->stamp = model->details->stamp; iter->user_data = ptr; } } static gboolean nemo_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { NemoListModel *model; GSequence *files; GSequenceIter *ptr; FileEntry *file_entry; int i, d; model = (NemoListModel *)tree_model; ptr = NULL; files = model->details->files; for (d = 0; d < gtk_tree_path_get_depth (path); d++) { i = gtk_tree_path_get_indices (path)[d]; if (files == NULL || i >= g_sequence_get_length (files)) { return FALSE; } ptr = g_sequence_get_iter_at_pos (files, i); file_entry = g_sequence_get (ptr); files = file_entry->files; } nemo_list_model_ptr_to_iter (model, ptr, iter); return TRUE; } static GtkTreePath * nemo_list_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkTreePath *path; NemoListModel *model; GSequenceIter *ptr; FileEntry *file_entry; model = (NemoListModel *)tree_model; g_return_val_if_fail (iter->stamp == model->details->stamp, NULL); if (g_sequence_iter_is_end (iter->user_data)) { /* FIXME is this right? */ return NULL; } path = gtk_tree_path_new (); ptr = iter->user_data; while (ptr != NULL) { gtk_tree_path_prepend_index (path, g_sequence_iter_get_position (ptr)); file_entry = g_sequence_get (ptr); if (file_entry->parent != NULL) { ptr = file_entry->parent->ptr; } else { ptr = NULL; } } return path; } static gint nemo_list_model_get_icon_scale (NemoListModel *model) { gint retval = -1; g_signal_emit (model, list_model_signals[GET_ICON_SCALE], 0, &retval); if (retval == -1) { retval = gdk_screen_get_monitor_scale_factor (gdk_screen_get_default (), 0); } return retval; } static void nemo_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column, GValue *value) { NemoListModel *model; NemoFile *parent_file; FileEntry *file_entry; NemoFile *file; char *str; model = (NemoListModel *)tree_model; g_return_if_fail (model->details->stamp == iter->stamp); g_return_if_fail (!g_sequence_iter_is_end (iter->user_data)); file_entry = g_sequence_get (iter->user_data); file = file_entry->file; parent_file = file_entry->parent ? file_entry->parent->file : NULL; switch (column) { case NEMO_LIST_MODEL_FILE_COLUMN: g_value_init (value, NEMO_TYPE_FILE); g_value_set_object (value, file); break; case NEMO_LIST_MODEL_SUBDIRECTORY_COLUMN: g_value_init (value, NEMO_TYPE_DIRECTORY); g_value_set_object (value, file_entry->subdirectory); break; case NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN: case NEMO_LIST_MODEL_SMALLER_ICON_COLUMN: case NEMO_LIST_MODEL_SMALL_ICON_COLUMN: case NEMO_LIST_MODEL_STANDARD_ICON_COLUMN: case NEMO_LIST_MODEL_LARGE_ICON_COLUMN: case NEMO_LIST_MODEL_LARGER_ICON_COLUMN: case NEMO_LIST_MODEL_LARGEST_ICON_COLUMN: g_value_init (value, CAIRO_GOBJECT_TYPE_SURFACE); if (file != NULL) { NemoFileIconFlags flags; cairo_surface_t *surface; int icon_size, icon_scale; NemoZoomLevel zoom_level; GdkPixbuf *icon, *rendered_icon; NemoIconInfo *icon_info; GList *emblem_icons, *l; zoom_level = nemo_list_model_get_zoom_level_from_column_id (column); icon_size = nemo_get_list_icon_size_for_zoom_level (zoom_level); icon_scale = nemo_list_model_get_icon_scale (model); flags = NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS | NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE | NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM; if (model->details->drag_view != NULL) { GtkTreePath *path_a, *path_b; gtk_tree_view_get_drag_dest_row (model->details->drag_view, &path_a, NULL); if (path_a != NULL) { path_b = gtk_tree_model_get_path (tree_model, iter); if (gtk_tree_path_compare (path_a, path_b) == 0) { flags |= NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT; } gtk_tree_path_free (path_a); gtk_tree_path_free (path_b); } } icon_info = nemo_file_get_icon (file, icon_size, 0, icon_scale, flags); emblem_icons = nemo_file_get_emblem_icons (file, parent_file); if (emblem_icons) { GdkPixbuf *initial_pixbuf; GIcon *gicon, *emblemed_icon, *emblem_icon; GEmblem *emblem; gint w, h, s; gboolean bad_ratio; initial_pixbuf = nemo_icon_info_get_pixbuf_at_size (icon_info, icon_size); w = gdk_pixbuf_get_width (initial_pixbuf); h = gdk_pixbuf_get_height (initial_pixbuf); s = MAX (w, h); if (s < icon_size) icon_size = s; bad_ratio = (int)(nemo_icon_get_emblem_size_for_icon_size (icon_size) * icon_scale) > w || (int)(nemo_icon_get_emblem_size_for_icon_size (icon_size) * icon_scale) > h; gicon = G_ICON (initial_pixbuf); /* pick only the first emblem we can render for the list view */ for (l = emblem_icons; !bad_ratio && l != NULL; l = l->next) { emblem_icon = l->data; emblem = g_emblem_new (emblem_icon); emblemed_icon = g_emblemed_icon_new (gicon, emblem); g_object_unref (gicon); g_object_unref (emblem); gicon = emblemed_icon; break; } nemo_icon_info_clear (&icon_info); icon_info = nemo_icon_info_lookup (gicon, icon_size, icon_scale); g_list_free_full (emblem_icons, g_object_unref); g_object_unref (gicon); } icon = nemo_icon_info_get_pixbuf_at_size (icon_info, icon_size); nemo_icon_info_unref (icon_info); if (model->details->highlight_files != NULL && g_list_find_custom (model->details->highlight_files, file, (GCompareFunc) nemo_file_compare_location)) { rendered_icon = eel_create_spotlight_pixbuf (icon); if (rendered_icon != NULL) { g_object_unref (icon); icon = rendered_icon; } } surface = gdk_cairo_surface_create_from_pixbuf (icon, icon_scale, NULL); g_value_take_boxed (value, surface); g_object_unref (icon); } break; case NEMO_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN: g_value_init (value, G_TYPE_BOOLEAN); g_value_set_boolean (value, file != NULL && nemo_file_can_rename (file)); break; case NEMO_LIST_MODEL_TEXT_WEIGHT_COLUMN: g_value_init (value, G_TYPE_INT); if (file != NULL) { g_value_set_int (value, nemo_file_get_pinning (file) ? PINNED_TEXT_WEIGHT : UNPINNED_TEXT_WEIGHT); } else { g_value_set_int (value, UNPINNED_TEXT_WEIGHT); } break; default: if (column >= NEMO_LIST_MODEL_NUM_COLUMNS || column < (int)(NEMO_LIST_MODEL_NUM_COLUMNS + model->details->columns->len)) { NemoColumn *nemo_column; GQuark attribute; nemo_column = model->details->columns->pdata[column - NEMO_LIST_MODEL_NUM_COLUMNS]; g_value_init (value, G_TYPE_STRING); g_object_get (nemo_column, "attribute_q", &attribute, NULL); if (file != NULL) { str = nemo_file_get_string_attribute_with_default_q (file, attribute); g_value_take_string (value, str); } else if (attribute == attribute_name_q) { if (file_entry->parent->loaded) { g_value_set_string (value, _("(Empty)")); } else { g_value_set_string (value, _("Loading...")); } } } else { g_assert_not_reached (); } } } static gboolean nemo_list_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) { NemoListModel *model; model = (NemoListModel *)tree_model; g_return_val_if_fail (model->details->stamp == iter->stamp, FALSE); iter->user_data = g_sequence_iter_next (iter->user_data); return !g_sequence_iter_is_end (iter->user_data); } static gboolean nemo_list_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { NemoListModel *model; GSequence *files; FileEntry *file_entry; model = (NemoListModel *)tree_model; if (parent == NULL) { files = model->details->files; } else { file_entry = g_sequence_get (parent->user_data); files = file_entry->files; } if (files == NULL || g_sequence_get_length (files) == 0) { return FALSE; } iter->stamp = model->details->stamp; iter->user_data = g_sequence_get_begin_iter (files); return TRUE; } static gboolean nemo_list_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) { FileEntry *file_entry; if (iter == NULL) { return !nemo_list_model_is_empty (NEMO_LIST_MODEL (tree_model)); } file_entry = g_sequence_get (iter->user_data); return (file_entry->files != NULL && g_sequence_get_length (file_entry->files) > 0); } static int nemo_list_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { NemoListModel *model; GSequence *files; FileEntry *file_entry; model = (NemoListModel *)tree_model; if (iter == NULL) { files = model->details->files; } else { file_entry = g_sequence_get (iter->user_data); files = file_entry->files; } return g_sequence_get_length (files); } static gboolean nemo_list_model_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, int n) { NemoListModel *model; GSequenceIter *child; GSequence *files; FileEntry *file_entry; model = (NemoListModel *)tree_model; if (parent != NULL) { file_entry = g_sequence_get (parent->user_data); files = file_entry->files; } else { files = model->details->files; } child = g_sequence_get_iter_at_pos (files, n); if (g_sequence_iter_is_end (child)) { return FALSE; } iter->stamp = model->details->stamp; iter->user_data = child; return TRUE; } static gboolean nemo_list_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { NemoListModel *model; FileEntry *file_entry; model = (NemoListModel *)tree_model; file_entry = g_sequence_get (child->user_data); if (file_entry->parent == NULL) { return FALSE; } iter->stamp = model->details->stamp; iter->user_data = file_entry->parent->ptr; return TRUE; } static GSequenceIter * lookup_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory) { FileEntry *file_entry; GSequenceIter *ptr, *parent_ptr; parent_ptr = NULL; if (directory) { parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map, directory); } if (parent_ptr) { file_entry = g_sequence_get (parent_ptr); ptr = g_hash_table_lookup (file_entry->reverse_map, file); } else { ptr = g_hash_table_lookup (model->details->top_reverse_map, file); } if (ptr) { g_assert (((FileEntry *)g_sequence_get (ptr))->file == file); } return ptr; } struct GetIters { NemoListModel *model; NemoFile *file; GList *iters; }; static void dir_to_iters (struct GetIters *data, GHashTable *reverse_map) { GSequenceIter *ptr; ptr = g_hash_table_lookup (reverse_map, data->file); if (ptr) { GtkTreeIter *iter; iter = g_new0 (GtkTreeIter, 1); nemo_list_model_ptr_to_iter (data->model, ptr, iter); data->iters = g_list_prepend (data->iters, iter); } } static void file_to_iter_cb (gpointer key, gpointer value, gpointer user_data) { struct GetIters *data; FileEntry *dir_file_entry; data = user_data; dir_file_entry = g_sequence_get ((GSequenceIter *)value); dir_to_iters (data, dir_file_entry->reverse_map); } GList * nemo_list_model_get_all_iters_for_file (NemoListModel *model, NemoFile *file) { struct GetIters data; data.file = file; data.model = model; data.iters = NULL; dir_to_iters (&data, model->details->top_reverse_map); g_hash_table_foreach (model->details->directory_reverse_map, file_to_iter_cb, &data); return g_list_reverse (data.iters); } gboolean nemo_list_model_get_first_iter_for_file (NemoListModel *model, NemoFile *file, GtkTreeIter *iter) { GList *list; gboolean res; res = FALSE; list = nemo_list_model_get_all_iters_for_file (model, file); if (list != NULL) { res = TRUE; *iter = *(GtkTreeIter *)list->data; } g_list_free_full (list, g_free); return res; } gboolean nemo_list_model_get_tree_iter_from_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory, GtkTreeIter *iter) { GSequenceIter *ptr; ptr = lookup_file (model, file, directory); if (!ptr) { return FALSE; } nemo_list_model_ptr_to_iter (model, ptr, iter); return TRUE; } static int nemo_list_model_file_entry_compare_func (gconstpointer a, gconstpointer b, gpointer user_data) { FileEntry *file_entry1; FileEntry *file_entry2; NemoListModel *model; int result; model = (NemoListModel *)user_data; file_entry1 = (FileEntry *)a; file_entry2 = (FileEntry *)b; if (file_entry1->file != NULL && file_entry2->file != NULL) { result = nemo_file_compare_for_sort_by_attribute_q (file_entry1->file, file_entry2->file, model->details->sort_attribute, model->details->sort_directories_first, (model->details->order == GTK_SORT_DESCENDING)); } else if (file_entry1->file == NULL) { return -1; } else { return 1; } return result; } int nemo_list_model_compare_func (NemoListModel *model, NemoFile *file1, NemoFile *file2) { int result; result = nemo_file_compare_for_sort_by_attribute_q (file1, file2, model->details->sort_attribute, model->details->sort_directories_first, (model->details->order == GTK_SORT_DESCENDING)); return result; } static void nemo_list_model_sort_file_entries (NemoListModel *model, GSequence *files, GtkTreePath *path) { GSequenceIter **old_order; GtkTreeIter iter; int *new_order; int length; int i; FileEntry *file_entry; gboolean has_iter; length = g_sequence_get_length (files); if (length <= 1) { return; } /* generate old order of GSequenceIter's */ old_order = g_new (GSequenceIter *, length); for (i = 0; i < length; ++i) { GSequenceIter *ptr = g_sequence_get_iter_at_pos (files, i); file_entry = g_sequence_get (ptr); if (file_entry->files != NULL) { gtk_tree_path_append_index (path, i); nemo_list_model_sort_file_entries (model, file_entry->files, path); gtk_tree_path_up (path); } old_order[i] = ptr; } /* sort */ g_sequence_sort (files, nemo_list_model_file_entry_compare_func, model); /* generate new order */ new_order = g_new (int, length); /* Note: new_order[newpos] = oldpos */ for (i = 0; i < length; ++i) { new_order[g_sequence_iter_get_position (old_order[i])] = i; } /* Let the world know about our new order */ g_assert (new_order != NULL); has_iter = FALSE; if (gtk_tree_path_get_depth (path) != 0) { gboolean get_iter_result; has_iter = TRUE; get_iter_result = gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path); g_assert (get_iter_result); } gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), path, has_iter ? &iter : NULL, new_order); g_free (old_order); g_free (new_order); } static void nemo_list_model_sort (NemoListModel *model) { GtkTreePath *path; path = gtk_tree_path_new (); nemo_list_model_sort_file_entries (model, model->details->files, path); gtk_tree_path_free (path); } static gboolean nemo_list_model_get_sort_column_id (GtkTreeSortable *sortable, gint *sort_column_id, GtkSortType *order) { NemoListModel *model; int id; model = (NemoListModel *)sortable; id = nemo_list_model_get_sort_column_id_from_attribute (model, model->details->sort_attribute); if (id == -1) { return FALSE; } if (sort_column_id != NULL) { *sort_column_id = id; } if (order != NULL) { *order = model->details->order; } return TRUE; } static void nemo_list_model_set_sort_column_id (GtkTreeSortable *sortable, gint sort_column_id, GtkSortType order) { NemoListModel *model; model = (NemoListModel *)sortable; model->details->sort_attribute = nemo_list_model_get_attribute_from_sort_column_id (model, sort_column_id); model->details->order = order; nemo_list_model_sort (model); gtk_tree_sortable_sort_column_changed (sortable); } static gboolean nemo_list_model_has_default_sort_func (GtkTreeSortable *sortable) { return FALSE; } static gboolean nemo_list_model_multi_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list) { return TRUE; } static void each_path_get_data_binder (NemoDragEachSelectedItemDataGet data_get, gpointer context, gpointer data) { DragDataGetInfo *info; GList *l; NemoFile *file; GtkTreeRowReference *row; GtkTreePath *path; char *uri; GdkRectangle cell_area; GtkTreeViewColumn *column; info = context; g_return_if_fail (info->model->details->drag_view); column = gtk_tree_view_get_column (info->model->details->drag_view, 0); for (l = info->path_list; l != NULL; l = l->next) { row = l->data; path = gtk_tree_row_reference_get_path (row); file = nemo_list_model_file_for_path (info->model, path); if (file) { gtk_tree_view_get_cell_area (info->model->details->drag_view, path, column, &cell_area); uri = nemo_file_get_uri (file); (*data_get) (uri, 0, cell_area.y - info->model->details->drag_begin_y, cell_area.width, cell_area.height, data); g_free (uri); nemo_file_unref (file); } gtk_tree_path_free (path); } } static gboolean nemo_list_model_multi_drag_data_get (EggTreeMultiDragSource *drag_source, GList *path_list, GtkSelectionData *selection_data) { NemoListModel *model; DragDataGetInfo context; guint target_info; model = NEMO_LIST_MODEL (drag_source); context.model = model; context.path_list = path_list; if (!drag_target_list) { drag_target_list = nemo_list_model_get_drag_target_list (); } if (gtk_target_list_find (drag_target_list, gtk_selection_data_get_target (selection_data), &target_info)) { nemo_drag_drag_data_get (NULL, NULL, selection_data, target_info, GDK_CURRENT_TIME, &context, each_path_get_data_binder); return TRUE; } else { return FALSE; } } static gboolean nemo_list_model_multi_drag_data_delete (EggTreeMultiDragSource *drag_source, GList *path_list) { return TRUE; } static void add_dummy_row (NemoListModel *model, FileEntry *parent_entry) { FileEntry *dummy_file_entry; GtkTreeIter iter; GtkTreePath *path; dummy_file_entry = g_new0 (FileEntry, 1); dummy_file_entry->parent = parent_entry; dummy_file_entry->ptr = g_sequence_insert_sorted (parent_entry->files, dummy_file_entry, nemo_list_model_file_entry_compare_func, model); iter.stamp = model->details->stamp; iter.user_data = dummy_file_entry->ptr; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); gtk_tree_path_free (path); } gboolean nemo_list_model_add_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory) { GtkTreeIter iter; GtkTreePath *path; FileEntry *file_entry; GSequenceIter *ptr, *parent_ptr; GSequence *files; gboolean replace_dummy; GHashTable *parent_hash; parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map, directory); if (parent_ptr) { file_entry = g_sequence_get (parent_ptr); ptr = g_hash_table_lookup (file_entry->reverse_map, file); } else { file_entry = NULL; ptr = g_hash_table_lookup (model->details->top_reverse_map, file); } if (ptr != NULL) { g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr); return FALSE; } file_entry = g_new0 (FileEntry, 1); file_entry->file = nemo_file_ref (file); file_entry->parent = NULL; file_entry->subdirectory = NULL; file_entry->files = NULL; files = model->details->files; parent_hash = model->details->top_reverse_map; replace_dummy = FALSE; if (parent_ptr != NULL) { file_entry->parent = g_sequence_get (parent_ptr); /* At this point we set loaded. Either we saw * "done" and ignored it waiting for this, or we do this * earlier, but then we replace the dummy row anyway, * so it doesn't matter */ file_entry->parent->loaded = 1; parent_hash = file_entry->parent->reverse_map; files = file_entry->parent->files; if (g_sequence_get_length (files) == 1) { GSequenceIter *dummy_ptr = g_sequence_get_iter_at_pos (files, 0); FileEntry *dummy_entry = g_sequence_get (dummy_ptr); if (dummy_entry->file == NULL) { /* replace the dummy loading entry */ model->details->stamp++; g_sequence_remove (dummy_ptr); replace_dummy = TRUE; } } } if (model->details->temp_unsorted) file_entry->ptr = g_sequence_append (files, file_entry); else file_entry->ptr = g_sequence_insert_sorted (files, file_entry, nemo_list_model_file_entry_compare_func, model); g_hash_table_insert (parent_hash, file, file_entry->ptr); iter.stamp = model->details->stamp; iter.user_data = file_entry->ptr; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (replace_dummy) { gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); } else { gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); } if (nemo_file_is_directory (file)) { guint count; gboolean got_count, unreadable; file_entry->files = g_sequence_new ((GDestroyNotify)file_entry_free); got_count = nemo_file_get_directory_item_count (file, &count, &unreadable); if ((!got_count && !unreadable) || count > 0) { add_dummy_row (model, file_entry); gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter); } } gtk_tree_path_free (path); return TRUE; } static gboolean update_dummy_row (NemoListModel *model, NemoFile *file, FileEntry *file_entry) { GSequence *files; gboolean changed; guint count; gboolean got_count, unreadable; changed = FALSE; got_count = nemo_file_get_directory_item_count (file, &count, &unreadable); if ((got_count && count == 0) || (!got_count && unreadable)) { files = file_entry->files; if (g_sequence_get_length (files) == 1) { GSequenceIter *dummy_ptr = g_sequence_get_iter_at_pos (files, 0); FileEntry *dummy_entry = g_sequence_get (dummy_ptr); if (dummy_entry->file == NULL) { if (!file_entry->expanding) { model->details->stamp++; g_sequence_remove (dummy_ptr); changed = TRUE; } } } } file_entry->expanding = FALSE; return changed; } void nemo_list_model_file_changed (NemoListModel *model, NemoFile *file, NemoDirectory *directory) { FileEntry *parent_file_entry; GtkTreeIter iter; GtkTreePath *path, *parent_path; GSequenceIter *ptr; int pos_before, pos_after, length, i, old; int *new_order; gboolean has_iter; GSequence *files; ptr = lookup_file (model, file, directory); if (!ptr) { return; } pos_before = g_sequence_iter_get_position (ptr); if (!model->details->temp_unsorted) g_sequence_sort_changed (ptr, nemo_list_model_file_entry_compare_func, model); pos_after = g_sequence_iter_get_position (ptr); if (pos_before != pos_after) { /* The file moved, we need to send rows_reordered */ parent_file_entry = ((FileEntry *)g_sequence_get (ptr))->parent; if (parent_file_entry == NULL) { has_iter = FALSE; parent_path = gtk_tree_path_new (); files = model->details->files; } else { has_iter = TRUE; nemo_list_model_ptr_to_iter (model, parent_file_entry->ptr, &iter); parent_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); files = parent_file_entry->files; } length = g_sequence_get_length (files); new_order = g_new (int, length); /* Note: new_order[newpos] = oldpos */ for (i = 0, old = 0; i < length; ++i) { if (i == pos_after) { new_order[i] = pos_before; } else { if (old == pos_before) old++; new_order[i] = old++; } } gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), parent_path, has_iter ? &iter : NULL, new_order); gtk_tree_path_free (parent_path); g_free (new_order); } nemo_list_model_ptr_to_iter (model, ptr, &iter); path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); if (nemo_file_is_directory (file)) { if (update_dummy_row (model, file, g_sequence_get (ptr))) { gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter); } } gtk_tree_path_free (path); } gboolean nemo_list_model_is_empty (NemoListModel *model) { return (g_sequence_get_length (model->details->files) == 0); } guint nemo_list_model_get_length (NemoListModel *model) { return g_sequence_get_length (model->details->files); } static void nemo_list_model_remove (NemoListModel *model, GtkTreeIter *iter) { GSequenceIter *ptr, *child_ptr; FileEntry *file_entry, *child_file_entry, *parent_file_entry; GtkTreePath *path; GtkTreeIter parent_iter; ptr = iter->user_data; file_entry = g_sequence_get (ptr); if (file_entry->files != NULL) { while (g_sequence_get_length (file_entry->files) > 0) { child_ptr = g_sequence_get_begin_iter (file_entry->files); child_file_entry = g_sequence_get (child_ptr); if (child_file_entry->file != NULL) { nemo_list_model_remove_file (model, child_file_entry->file, file_entry->subdirectory); } else { path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); gtk_tree_path_append_index (path, 0); model->details->stamp++; g_sequence_remove (child_ptr); gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); } /* the parent iter didn't actually change */ iter->stamp = model->details->stamp; } } if (file_entry->file != NULL) { /* Don't try to remove dummy row */ if (file_entry->parent != NULL) { g_hash_table_remove (file_entry->parent->reverse_map, file_entry->file); } else { g_hash_table_remove (model->details->top_reverse_map, file_entry->file); } } parent_file_entry = file_entry->parent; if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 1 && file_entry->file != NULL) { /* this is the last non-dummy child, add a dummy node */ /* We need to do this before removing the last file to avoid * collapsing the row. */ guint count; gboolean got_count, unreadable; got_count = nemo_file_get_directory_item_count (parent_file_entry->file, &count, &unreadable); if ((!got_count && !unreadable) || count > 0) { add_dummy_row (model, parent_file_entry); } } if (file_entry->subdirectory != NULL) { g_signal_emit (model, list_model_signals[SUBDIRECTORY_UNLOADED], 0, file_entry->subdirectory); g_hash_table_remove (model->details->directory_reverse_map, file_entry->subdirectory); } path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); g_sequence_remove (ptr); model->details->stamp++; gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 0) { parent_iter.stamp = model->details->stamp; parent_iter.user_data = parent_file_entry->ptr; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &parent_iter); gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &parent_iter); gtk_tree_path_free (path); } } void nemo_list_model_remove_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory) { GtkTreeIter iter; if (nemo_list_model_get_tree_iter_from_file (model, file, directory, &iter)) { nemo_list_model_remove (model, &iter); } } static void nemo_list_model_clear_directory (NemoListModel *model, GSequence *files) { GtkTreeIter iter; FileEntry *file_entry; while (g_sequence_get_length (files) > 0) { iter.user_data = g_sequence_get_begin_iter (files); file_entry = g_sequence_get (iter.user_data); if (file_entry->files != NULL) { nemo_list_model_clear_directory (model, file_entry->files); } iter.stamp = model->details->stamp; nemo_list_model_remove (model, &iter); } } void nemo_list_model_clear (NemoListModel *model) { g_return_if_fail (model != NULL); nemo_list_model_clear_directory (model, model->details->files); } NemoFile * nemo_list_model_file_for_path (NemoListModel *model, GtkTreePath *path) { NemoFile *file; GtkTreeIter iter; file = NULL; if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) { gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); } return file; } gboolean nemo_list_model_load_subdirectory (NemoListModel *model, GtkTreePath *path, NemoDirectory **directory) { GtkTreeIter iter; FileEntry *file_entry; NemoDirectory *subdirectory; if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) { return FALSE; } file_entry = g_sequence_get (iter.user_data); if (file_entry->file == NULL || file_entry->subdirectory != NULL) { return FALSE; } subdirectory = nemo_directory_get_for_file (file_entry->file); if (g_hash_table_lookup (model->details->directory_reverse_map, subdirectory) != NULL) { nemo_directory_unref (subdirectory); g_warning ("Already in directory_reverse_map, failing\n"); return FALSE; } file_entry->subdirectory = subdirectory, g_hash_table_insert (model->details->directory_reverse_map, subdirectory, file_entry->ptr); file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal); /* Return a ref too */ nemo_directory_ref (subdirectory); *directory = subdirectory; return TRUE; } /* removes all children of the subfolder and unloads the subdirectory */ void nemo_list_model_unload_subdirectory (NemoListModel *model, GtkTreeIter *iter) { GSequenceIter *child_ptr; FileEntry *file_entry, *child_file_entry; GtkTreeIter child_iter; file_entry = g_sequence_get (iter->user_data); if (file_entry->file == NULL || file_entry->subdirectory == NULL) { return; } file_entry->loaded = 0; /* Remove all children */ while (g_sequence_get_length (file_entry->files) > 0) { child_ptr = g_sequence_get_begin_iter (file_entry->files); child_file_entry = g_sequence_get (child_ptr); if (child_file_entry->file == NULL) { /* Don't delete the dummy node */ break; } else { nemo_list_model_ptr_to_iter (model, child_ptr, &child_iter); nemo_list_model_remove (model, &child_iter); } } /* Emit unload signal */ g_signal_emit (model, list_model_signals[SUBDIRECTORY_UNLOADED], 0, file_entry->subdirectory); /* actually unload */ g_hash_table_remove (model->details->directory_reverse_map, file_entry->subdirectory); nemo_directory_unref (file_entry->subdirectory); file_entry->subdirectory = NULL; g_assert (g_hash_table_size (file_entry->reverse_map) == 0); g_hash_table_destroy (file_entry->reverse_map); file_entry->reverse_map = NULL; } void nemo_list_model_set_should_sort_directories_first (NemoListModel *model, gboolean sort_directories_first) { if (model->details->sort_directories_first == sort_directories_first) { return; } model->details->sort_directories_first = sort_directories_first; nemo_list_model_sort (model); } int nemo_list_model_get_sort_column_id_from_attribute (NemoListModel *model, GQuark attribute) { guint i; if (attribute == 0) { return -1; } /* Hack - the preferences dialog sets modification_date for some * rather than date_modified for some reason. Make sure that * works. */ if (attribute == attribute_modification_date_q) { attribute = attribute_date_modified_q; } for (i = 0; i < model->details->columns->len; i++) { NemoColumn *column; GQuark column_attribute; column = NEMO_COLUMN (model->details->columns->pdata[i]); g_object_get (G_OBJECT (column), "attribute_q", &column_attribute, NULL); if (column_attribute == attribute) { return NEMO_LIST_MODEL_NUM_COLUMNS + i; } } return -1; } GQuark nemo_list_model_get_attribute_from_sort_column_id (NemoListModel *model, int sort_column_id) { NemoColumn *column; int index; GQuark attribute; index = sort_column_id - NEMO_LIST_MODEL_NUM_COLUMNS; if (index < 0 || index >= (int)model->details->columns->len) { g_warning ("unknown sort column id: %d", sort_column_id); return 0; } column = NEMO_COLUMN (model->details->columns->pdata[index]); g_object_get (G_OBJECT (column), "attribute_q", &attribute, NULL); return attribute; } NemoZoomLevel nemo_list_model_get_zoom_level_from_column_id (int column) { switch (column) { case NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN: return NEMO_ZOOM_LEVEL_SMALLEST; case NEMO_LIST_MODEL_SMALLER_ICON_COLUMN: return NEMO_ZOOM_LEVEL_SMALLER; case NEMO_LIST_MODEL_SMALL_ICON_COLUMN: return NEMO_ZOOM_LEVEL_SMALL; case NEMO_LIST_MODEL_STANDARD_ICON_COLUMN: return NEMO_ZOOM_LEVEL_STANDARD; case NEMO_LIST_MODEL_LARGE_ICON_COLUMN: return NEMO_ZOOM_LEVEL_LARGE; case NEMO_LIST_MODEL_LARGER_ICON_COLUMN: return NEMO_ZOOM_LEVEL_LARGER; case NEMO_LIST_MODEL_LARGEST_ICON_COLUMN: return NEMO_ZOOM_LEVEL_LARGEST; default: break; } g_return_val_if_reached (NEMO_ZOOM_LEVEL_STANDARD); } int nemo_list_model_get_column_id_from_zoom_level (NemoZoomLevel zoom_level) { switch (zoom_level) { case NEMO_ZOOM_LEVEL_SMALLEST: return NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN; case NEMO_ZOOM_LEVEL_SMALLER: return NEMO_LIST_MODEL_SMALLER_ICON_COLUMN; case NEMO_ZOOM_LEVEL_SMALL: return NEMO_LIST_MODEL_SMALL_ICON_COLUMN; case NEMO_ZOOM_LEVEL_STANDARD: return NEMO_LIST_MODEL_STANDARD_ICON_COLUMN; case NEMO_ZOOM_LEVEL_LARGE: return NEMO_LIST_MODEL_LARGE_ICON_COLUMN; case NEMO_ZOOM_LEVEL_LARGER: return NEMO_LIST_MODEL_LARGER_ICON_COLUMN; case NEMO_ZOOM_LEVEL_LARGEST: return NEMO_LIST_MODEL_LARGEST_ICON_COLUMN; case NEMO_ZOOM_LEVEL_NULL: default: g_return_val_if_reached (NEMO_LIST_MODEL_STANDARD_ICON_COLUMN); } } void nemo_list_model_set_drag_view (NemoListModel *model, GtkTreeView *view, int drag_begin_x, int drag_begin_y) { g_return_if_fail (model != NULL); g_return_if_fail (NEMO_IS_LIST_MODEL (model)); g_return_if_fail (!view || GTK_IS_TREE_VIEW (view)); model->details->drag_view = view; model->details->drag_begin_x = drag_begin_x; model->details->drag_begin_y = drag_begin_y; } GtkTargetList * nemo_list_model_get_drag_target_list (void) { GtkTargetList *target_list; target_list = gtk_target_list_new (drag_types, G_N_ELEMENTS (drag_types)); gtk_target_list_add_text_targets (target_list, NEMO_ICON_DND_TEXT); return target_list; } int nemo_list_model_add_column (NemoListModel *model, NemoColumn *column) { g_ptr_array_add (model->details->columns, column); g_object_ref (column); return NEMO_LIST_MODEL_NUM_COLUMNS + (model->details->columns->len - 1); } int nemo_list_model_get_column_number (NemoListModel *model, const char *column_name) { guint i; for (i = 0; i < model->details->columns->len; i++) { NemoColumn *column; char *name; column = model->details->columns->pdata[i]; g_object_get (G_OBJECT (column), "name", &name, NULL); if (!strcmp (name, column_name)) { g_free (name); return NEMO_LIST_MODEL_NUM_COLUMNS + i; } g_free (name); } return -1; } static void nemo_list_model_dispose (GObject *object) { NemoListModel *model; guint i; model = NEMO_LIST_MODEL (object); if (model->details->columns) { for (i = 0; i < model->details->columns->len; i++) { g_object_unref (model->details->columns->pdata[i]); } g_ptr_array_free (model->details->columns, TRUE); model->details->columns = NULL; } if (model->details->files) { g_sequence_free (model->details->files); model->details->files = NULL; } if (model->details->top_reverse_map) { g_hash_table_destroy (model->details->top_reverse_map); model->details->top_reverse_map = NULL; } if (model->details->directory_reverse_map) { g_hash_table_destroy (model->details->directory_reverse_map); model->details->directory_reverse_map = NULL; } G_OBJECT_CLASS (nemo_list_model_parent_class)->dispose (object); } static void nemo_list_model_finalize (GObject *object) { NemoListModel *model; model = NEMO_LIST_MODEL (object); if (model->details->highlight_files != NULL) { nemo_file_list_free (model->details->highlight_files); model->details->highlight_files = NULL; } g_free (model->details); G_OBJECT_CLASS (nemo_list_model_parent_class)->finalize (object); } static void nemo_list_model_init (NemoListModel *model) { model->details = g_new0 (NemoListModelDetails, 1); model->details->files = g_sequence_new ((GDestroyNotify)file_entry_free); model->details->top_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal); model->details->directory_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal); model->details->stamp = g_random_int (); model->details->sort_attribute = 0; model->details->columns = g_ptr_array_new (); } static void nemo_list_model_class_init (NemoListModelClass *klass) { GObjectClass *object_class; attribute_name_q = g_quark_from_static_string ("name"); attribute_modification_date_q = g_quark_from_static_string ("modification_date"); attribute_date_modified_q = g_quark_from_static_string ("date_modified"); object_class = (GObjectClass *)klass; object_class->finalize = nemo_list_model_finalize; object_class->dispose = nemo_list_model_dispose; list_model_signals[SUBDIRECTORY_UNLOADED] = g_signal_new ("subdirectory_unloaded", NEMO_TYPE_LIST_MODEL, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NemoListModelClass, subdirectory_unloaded), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NEMO_TYPE_DIRECTORY); list_model_signals[GET_ICON_SCALE] = g_signal_new ("get-icon-scale", NEMO_TYPE_LIST_MODEL, G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_INT, 0); } static void nemo_list_model_tree_model_init (GtkTreeModelIface *iface) { iface->get_flags = nemo_list_model_get_flags; iface->get_n_columns = nemo_list_model_get_n_columns; iface->get_column_type = nemo_list_model_get_column_type; iface->get_iter = nemo_list_model_get_iter; iface->get_path = nemo_list_model_get_path; iface->get_value = nemo_list_model_get_value; iface->iter_next = nemo_list_model_iter_next; iface->iter_children = nemo_list_model_iter_children; iface->iter_has_child = nemo_list_model_iter_has_child; iface->iter_n_children = nemo_list_model_iter_n_children; iface->iter_nth_child = nemo_list_model_iter_nth_child; iface->iter_parent = nemo_list_model_iter_parent; } static void nemo_list_model_sortable_init (GtkTreeSortableIface *iface) { iface->get_sort_column_id = nemo_list_model_get_sort_column_id; iface->set_sort_column_id = nemo_list_model_set_sort_column_id; iface->has_default_sort_func = nemo_list_model_has_default_sort_func; } static void nemo_list_model_multi_drag_source_init (EggTreeMultiDragSourceIface *iface) { iface->row_draggable = nemo_list_model_multi_row_draggable; iface->drag_data_get = nemo_list_model_multi_drag_data_get; iface->drag_data_delete = nemo_list_model_multi_drag_data_delete; } void nemo_list_model_subdirectory_done_loading (NemoListModel *model, NemoDirectory *directory) { GtkTreeIter iter; GtkTreePath *path; FileEntry *file_entry, *dummy_entry; GSequenceIter *parent_ptr, *dummy_ptr; GSequence *files; if (model == NULL || model->details->directory_reverse_map == NULL) { return; } parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map, directory); if (parent_ptr == NULL) { return; } file_entry = g_sequence_get (parent_ptr); files = file_entry->files; /* Only swap loading -> empty if we saw no files yet at "done", * otherwise, toggle loading at first added file to the model. */ if (!nemo_directory_is_not_empty (directory) && g_sequence_get_length (files) == 1) { dummy_ptr = g_sequence_get_iter_at_pos (file_entry->files, 0); dummy_entry = g_sequence_get (dummy_ptr); if (dummy_entry->file == NULL) { /* was the dummy file */ file_entry->loaded = 1; iter.stamp = model->details->stamp; iter.user_data = dummy_ptr; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); gtk_tree_path_free (path); } } } static void refresh_row (gpointer data, gpointer user_data) { NemoFile *file; NemoListModel *model; GList *iters, *l; GtkTreePath *path; model = user_data; file = data; iters = nemo_list_model_get_all_iters_for_file (model, file); for (l = iters; l != NULL; l = l->next) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), l->data); gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, l->data); gtk_tree_path_free (path); } g_list_free_full (iters, g_free); } void nemo_list_model_set_highlight_for_files (NemoListModel *model, GList *files) { if (model->details->highlight_files != NULL) { g_list_foreach (model->details->highlight_files, refresh_row, model); nemo_file_list_free (model->details->highlight_files); model->details->highlight_files = NULL; } if (files != NULL) { model->details->highlight_files = nemo_file_list_copy (files); g_list_foreach (model->details->highlight_files, refresh_row, model); } } void nemo_list_model_set_temporarily_disable_sort (NemoListModel *model, gboolean disable) { model->details->temp_unsorted = disable; if (!disable) nemo_list_model_sort (model); } gboolean nemo_list_model_get_temporarily_disable_sort (NemoListModel *model) { return model->details->temp_unsorted; } void nemo_list_model_set_expanding (NemoListModel *model, NemoDirectory *directory) { FileEntry *entry; GSequenceIter *ptr; ptr = NULL; if (directory) { ptr = g_hash_table_lookup (model->details->directory_reverse_map, directory); } if (!ptr) { g_warning ("nemo_list_model_set_expanding: No pointer found, something's wrong?"); return; } entry = g_sequence_get (ptr); entry->expanding = TRUE; }nemo-4.4.2/src/nemo-list-model.h000066400000000000000000000136031357442400300164310ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-list-model.h - a GtkTreeModel for file lists. Copyright (C) 2001, 2002 Anders Carlsson The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Anders Carlsson */ #include #include #include #include #include #ifndef NEMO_LIST_MODEL_H #define NEMO_LIST_MODEL_H #define NEMO_TYPE_LIST_MODEL nemo_list_model_get_type() #define NEMO_LIST_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_LIST_MODEL, NemoListModel)) #define NEMO_LIST_MODEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_LIST_MODEL, NemoListModelClass)) #define NEMO_IS_LIST_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_LIST_MODEL)) #define NEMO_IS_LIST_MODEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_LIST_MODEL)) #define NEMO_LIST_MODEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_LIST_MODEL, NemoListModelClass)) enum { NEMO_LIST_MODEL_FILE_COLUMN, NEMO_LIST_MODEL_SUBDIRECTORY_COLUMN, NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN, NEMO_LIST_MODEL_SMALLER_ICON_COLUMN, NEMO_LIST_MODEL_SMALL_ICON_COLUMN, NEMO_LIST_MODEL_STANDARD_ICON_COLUMN, NEMO_LIST_MODEL_LARGE_ICON_COLUMN, NEMO_LIST_MODEL_LARGER_ICON_COLUMN, NEMO_LIST_MODEL_LARGEST_ICON_COLUMN, NEMO_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN, NEMO_LIST_MODEL_TEXT_WEIGHT_COLUMN, NEMO_LIST_MODEL_NUM_COLUMNS }; typedef struct NemoListModelDetails NemoListModelDetails; typedef struct NemoListModel { GObject parent_instance; NemoListModelDetails *details; } NemoListModel; typedef struct { GObjectClass parent_class; void (* subdirectory_unloaded)(NemoListModel *model, NemoDirectory *subdirectory); } NemoListModelClass; GType nemo_list_model_get_type (void); gboolean nemo_list_model_add_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory); void nemo_list_model_file_changed (NemoListModel *model, NemoFile *file, NemoDirectory *directory); gboolean nemo_list_model_is_empty (NemoListModel *model); guint nemo_list_model_get_length (NemoListModel *model); void nemo_list_model_remove_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory); void nemo_list_model_clear (NemoListModel *model); gboolean nemo_list_model_get_tree_iter_from_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory, GtkTreeIter *iter); GList * nemo_list_model_get_all_iters_for_file (NemoListModel *model, NemoFile *file); gboolean nemo_list_model_get_first_iter_for_file (NemoListModel *model, NemoFile *file, GtkTreeIter *iter); void nemo_list_model_set_should_sort_directories_first (NemoListModel *model, gboolean sort_directories_first); int nemo_list_model_get_sort_column_id_from_attribute (NemoListModel *model, GQuark attribute); GQuark nemo_list_model_get_attribute_from_sort_column_id (NemoListModel *model, int sort_column_id); void nemo_list_model_sort_files (NemoListModel *model, GList **files); NemoZoomLevel nemo_list_model_get_zoom_level_from_column_id (int column); int nemo_list_model_get_column_id_from_zoom_level (NemoZoomLevel zoom_level); NemoFile * nemo_list_model_file_for_path (NemoListModel *model, GtkTreePath *path); gboolean nemo_list_model_load_subdirectory (NemoListModel *model, GtkTreePath *path, NemoDirectory **directory); void nemo_list_model_unload_subdirectory (NemoListModel *model, GtkTreeIter *iter); void nemo_list_model_set_drag_view (NemoListModel *model, GtkTreeView *view, int begin_x, int begin_y); GtkTargetList * nemo_list_model_get_drag_target_list (void); int nemo_list_model_compare_func (NemoListModel *model, NemoFile *file1, NemoFile *file2); int nemo_list_model_add_column (NemoListModel *model, NemoColumn *column); int nemo_list_model_get_column_number (NemoListModel *model, const char *column_name); void nemo_list_model_subdirectory_done_loading (NemoListModel *model, NemoDirectory *directory); void nemo_list_model_set_highlight_for_files (NemoListModel *model, GList *files); void nemo_list_model_set_temporarily_disable_sort (NemoListModel *model, gboolean disable); gboolean nemo_list_model_get_temporarily_disable_sort (NemoListModel *model); void nemo_list_model_set_expanding (NemoListModel *model, NemoDirectory *directory); #endif /* NEMO_LIST_MODEL_H */ nemo-4.4.2/src/nemo-list-view-private.h000066400000000000000000000030571357442400300177550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-list-view-private.h - Private functions for both the list and search list view to share Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Rebecca Schulman */ struct FMListViewColumn { const char *attribute; const char *title; NemoFileSortType sort_criterion; int minimum_width, default_width, maximum_width; gboolean right_justified; }; void fm_list_view_column_set (FMListViewColumn *column, const char *attribute, const char *title, NemoFileSortType sort_criterion, int minimum_width, int default_width, int maximum_width, gboolean right_justified); nemo-4.4.2/src/nemo-list-view.c000066400000000000000000003672131357442400300163070ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-list-view.c - implementation of list view of directory. Copyright (C) 2000 Eazel, Inc. Copyright (C) 2001, 2002 Anders Carlsson The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan Anders Carlsson David Emory Watson */ #include #include "nemo-list-view.h" #include "nemo-application.h" #include "nemo-list-model.h" #include "nemo-error-reporting.h" #include "nemo-view-dnd.h" #include "nemo-view-factory.h" #include "nemo-window.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_LIST_VIEW #include struct NemoListViewDetails { GtkTreeView *tree_view; NemoListModel *model; GtkActionGroup *list_action_group; guint list_merge_id; GtkTreeViewColumn *file_name_column; int file_name_column_num; GtkCellRendererPixbuf *pixbuf_cell; GtkCellRendererText *file_name_cell; GList *cells; GtkCellEditable *editable_widget; NemoZoomLevel zoom_level; NemoTreeViewDragDest *drag_dest; GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */ GtkTreePath *new_selection_path; /* Path of the new selection after removing a file */ GtkTreePath *hover_path; guint drag_button; int drag_x; int drag_y; gboolean rename_on_release; gboolean drag_started; gboolean ignore_button_release; gboolean row_selected_on_button_down; gboolean menus_ready; gboolean active; gboolean rubber_banding; GHashTable *columns; GtkWidget *column_editor; char *original_name; NemoFile *renaming_file; gboolean rename_done; guint renaming_file_activate_timeout; gulong clipboard_handler_id; GQuark last_sort_attr; gboolean tooltip_flags; gboolean show_tooltips; gboolean click_to_rename; GList *current_selection; gint current_selection_count; }; struct SelectionForeachData { GList *list; GtkTreeSelection *selection; }; /* * The row height should be large enough to not clip emblems. * Computing this would be costly, so we just choose a number * that works well with the set of emblems we've designed. */ #define LIST_VIEW_MINIMUM_ROW_HEIGHT 28 /* We wait two seconds after row is collapsed to unload the subdirectory */ #define COLLAPSE_TO_UNLOAD_DELAY 2 /* Wait for the rename to end when activating a file being renamed */ #define WAIT_FOR_RENAME_ON_ACTIVATE 200 static GdkCursor * hand_cursor = NULL; static GtkTargetList * source_target_list = NULL; static GList *nemo_list_view_get_selection (NemoView *view); static void nemo_list_view_update_selection (NemoView *view); static GList *nemo_list_view_get_selection_for_file_transfer (NemoView *view); static void nemo_list_view_set_zoom_level (NemoListView *view, NemoZoomLevel new_level, gboolean always_set_level); static void nemo_list_view_scale_font_size (NemoListView *view, NemoZoomLevel new_level); static void nemo_list_view_scroll_to_file (NemoListView *view, NemoFile *file); static void nemo_list_view_rename_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data); static void nemo_list_view_start_renaming_file (NemoView *view, NemoFile *file, gboolean select_all); static void apply_columns_settings (NemoListView *list_view, char **column_order, char **visible_columns); static char **get_visible_columns (NemoListView *list_view); static char **get_default_visible_columns (NemoListView *list_view); static char **get_column_order (NemoListView *list_view); static char **get_default_column_order (NemoListView *list_view); static void set_columns_settings_from_metadata_and_preferences (NemoListView *list_view); G_DEFINE_TYPE (NemoListView, nemo_list_view, NEMO_TYPE_VIEW); static const char * default_trash_visible_columns[] = { "name", "size", "type", "trashed_on", "trash_orig_path", NULL }; static const char * default_trash_columns_order[] = { "name", "size", "type", "trashed_on", "trash_orig_path", NULL }; static const char * default_recent_visible_columns[] = { "name", "size", "type", "date_accessed", NULL }; static const char * default_recent_columns_order[] = { "name", "size", "type", "date_accessed", NULL }; static gchar ** string_array_from_string_glist (GList *list) { GPtrArray *res; GList *l; gchar **ret; res = g_ptr_array_new (); for (l = list; l != NULL; l = l->next) { g_ptr_array_add (res, g_strdup (l->data)); } g_ptr_array_add (res, NULL); ret = (char **) g_ptr_array_free (res, FALSE); return ret; } static const gchar* get_default_sort_order (NemoFile *file, gboolean *reversed) { NemoFileSortType default_sort_order; gboolean default_sort_reversed; const gchar *retval; const char *attributes[] = { "name", /* is really "manually" which doesn't apply to lists */ "name", "size", "type", "detailed_type", "date_modified", "date_accessed", "trashed_on", NULL }; retval = nemo_file_get_default_sort_attribute (file, reversed); if (retval == NULL) { default_sort_order = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_DEFAULT_SORT_ORDER); default_sort_reversed = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER); retval = attributes[default_sort_order]; *reversed = default_sort_reversed; } return retval; } static void tooltip_prefs_changed_callback (NemoListView *view) { view->details->show_tooltips = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_TOOLTIPS_LIST_VIEW); view->details->tooltip_flags = nemo_global_preferences_get_tooltip_flags (); } static void list_selection_changed_callback (GtkTreeSelection *selection, gpointer user_data) { NemoView *view; view = NEMO_VIEW (user_data); nemo_list_view_update_selection (view); nemo_view_notify_selection_changed (view); } /* Move these to eel? */ static void tree_selection_foreach_set_boolean (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer callback_data) { * (gboolean *) callback_data = TRUE; } static gboolean tree_selection_not_empty (GtkTreeSelection *selection) { gboolean not_empty; not_empty = FALSE; gtk_tree_selection_selected_foreach (selection, tree_selection_foreach_set_boolean, ¬_empty); return not_empty; } static gboolean tree_view_has_selection (GtkTreeView *view) { return tree_selection_not_empty (gtk_tree_view_get_selection (view)); } static void preview_selected_items (NemoListView *view) { GList *file_list; file_list = nemo_list_view_get_selection (NEMO_VIEW (view)); if (file_list != NULL) { nemo_view_preview_files (NEMO_VIEW (view), file_list, NULL); nemo_file_list_free (file_list); } } static void activate_selected_items (NemoListView *view) { GList *file_list; file_list = nemo_list_view_get_selection (NEMO_VIEW (view)); if (view->details->renaming_file) { /* We're currently renaming a file, wait until the rename is finished, or the activation uri will be wrong */ if (view->details->renaming_file_activate_timeout == 0) { view->details->renaming_file_activate_timeout = g_timeout_add (WAIT_FOR_RENAME_ON_ACTIVATE, (GSourceFunc) activate_selected_items, view); } return; } if (view->details->renaming_file_activate_timeout != 0) { g_source_remove (view->details->renaming_file_activate_timeout); view->details->renaming_file_activate_timeout = 0; } nemo_view_activate_files (NEMO_VIEW (view), file_list, 0, TRUE); nemo_file_list_free (file_list); } static void activate_selected_items_alternate (NemoListView *view, NemoFile *file, gboolean open_in_tab) { GList *file_list; NemoWindowOpenFlags flags; flags = 0; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) { if (open_in_tab) { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } } else { flags |= NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND; } if (file != NULL) { nemo_file_ref (file); file_list = g_list_prepend (NULL, file); } else { file_list = nemo_list_view_get_selection (NEMO_VIEW (view)); } nemo_view_activate_files (NEMO_VIEW (view), file_list, flags, TRUE); nemo_file_list_free (file_list); } static gboolean button_event_modifies_selection (GdkEventButton *event) { return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0; } static int get_click_policy (void) { return g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_CLICK_POLICY); } static void nemo_list_view_did_not_drag (NemoListView *view, GdkEventButton *event) { GtkTreeView *tree_view; GtkTreeSelection *selection; GtkTreePath *path; tree_view = view->details->tree_view; selection = gtk_tree_view_get_selection (tree_view); if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL)) { if ((event->button == 1 || event->button == 2) && ((event->state & GDK_CONTROL_MASK) != 0 || (event->state & GDK_SHIFT_MASK) == 0) && view->details->row_selected_on_button_down) { if (!button_event_modifies_selection (event)) { gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_path (selection, path); } else { gtk_tree_selection_unselect_path (selection, path); } } if ((get_click_policy () == NEMO_CLICK_POLICY_SINGLE) && !button_event_modifies_selection(event)) { if (event->button == 1) { activate_selected_items (view); } else if (event->button == 2) { activate_selected_items_alternate (view, NULL, TRUE); } } if (view->details->rename_on_release) { NemoFile *file = nemo_list_model_file_for_path (view->details->model, path); nemo_list_view_start_renaming_file (NEMO_VIEW (view), file, nemo_file_is_directory (file)); nemo_file_unref (file); view->details->rename_on_release = FALSE; } gtk_tree_path_free (path); } } static void drag_data_get_callback (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time) { GtkTreeView *tree_view; GtkTreeModel *model; GList *ref_list; tree_view = GTK_TREE_VIEW (widget); model = gtk_tree_view_get_model (tree_view); if (model == NULL) { return; } ref_list = g_object_get_data (G_OBJECT (context), "drag-info"); if (ref_list == NULL) { return; } if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) { egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), ref_list, selection_data); } } static void filtered_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { struct SelectionForeachData *selection_data; GtkTreeIter parent; GtkTreeIter child; selection_data = data; /* If the parent folder is also selected, don't include this file in the * file operation, since that would copy it to the toplevel target instead * of keeping it as a child of the copied folder */ child = *iter; while (gtk_tree_model_iter_parent (model, &parent, &child)) { if (gtk_tree_selection_iter_is_selected (selection_data->selection, &parent)) { return; } child = parent; } selection_data->list = g_list_prepend (selection_data->list, gtk_tree_row_reference_new (model, path)); } static GList * get_filtered_selection_refs (GtkTreeView *tree_view) { struct SelectionForeachData selection_data; selection_data.list = NULL; selection_data.selection = gtk_tree_view_get_selection (tree_view); gtk_tree_selection_selected_foreach (selection_data.selection, filtered_selection_foreach, &selection_data); return g_list_reverse (selection_data.list); } static void ref_list_free (GList *ref_list) { g_list_foreach (ref_list, (GFunc) gtk_tree_row_reference_free, NULL); g_list_free (ref_list); } static void stop_drag_check (NemoListView *view) { view->details->drag_button = 0; } static cairo_surface_t * get_drag_surface (NemoListView *view) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; cairo_surface_t *ret; GdkRectangle cell_area; ret = NULL; if (gtk_tree_view_get_path_at_pos (view->details->tree_view, view->details->drag_x, view->details->drag_y, &path, NULL, NULL, NULL)) { model = gtk_tree_view_get_model (view->details->tree_view); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, nemo_list_model_get_column_id_from_zoom_level (view->details->zoom_level), &ret, -1); gtk_tree_view_get_cell_area (view->details->tree_view, path, view->details->file_name_column, &cell_area); gtk_tree_path_free (path); } return ret; } static void drag_begin_callback (GtkWidget *widget, GdkDragContext *context, NemoListView *view) { GList *ref_list; cairo_surface_t *surface; surface = get_drag_surface (view); if (surface) { gtk_drag_set_icon_surface (context, surface); cairo_surface_destroy (surface); } else { gtk_drag_set_icon_default (context); } stop_drag_check (view); view->details->drag_started = TRUE; ref_list = get_filtered_selection_refs (GTK_TREE_VIEW (widget)); g_object_set_data_full (G_OBJECT (context), "drag-info", ref_list, (GDestroyNotify)ref_list_free); } static gboolean motion_notify_callback (GtkWidget *widget, GdkEventMotion *event, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) { return GDK_EVENT_PROPAGATE; } if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE) { GtkTreePath *old_hover_path; old_hover_path = view->details->hover_path; gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &view->details->hover_path, NULL, NULL, NULL); if ((old_hover_path != NULL) != (view->details->hover_path != NULL)) { if (view->details->hover_path != NULL) { gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor); } else { gdk_window_set_cursor (gtk_widget_get_window (widget), NULL); } } if (old_hover_path != NULL) { gtk_tree_path_free (old_hover_path); } } /* If we're already rubber-banding, we can skip all of this logic and just let the parent * class continue to handle selection */ if (view->details->drag_button != 0 && !view->details->rubber_banding) { GtkTreePath *path; GtkTreeSelection *selection; gboolean is_new_self_selection; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &path, NULL, NULL, NULL); /* This looks complicated but it's just verbose: We'll only consider allowing rubber-banding * to begin if the following are TRUE: a) The current row is the only row currently selected, * and b) This is the first click that's been made on this row - meaning, the button-press-event * that preceded this motion-event was the one that caused this row to be selected. */ is_new_self_selection = gtk_tree_selection_count_selected_rows (selection) == 1 && gtk_tree_selection_path_is_selected (selection, path) && (!view->details->double_click_path[1] || (view->details->double_click_path[1] && gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) != 0)); gtk_tree_path_free (path); /* We also want to further restrict rubber-banding to be initiated only in blank areas of the row. * This allows DnD to operate on a new selection like before, when the motion begins over text or * icons */ if (is_new_self_selection && gtk_tree_view_is_blank_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, NULL, NULL, NULL, NULL)) { /* If this is a candidate for rubber-banding, track that state in the view, and allow the event * to continue into Gtk (which handles rubber-band selection for us) */ view->details->rubber_banding = TRUE; return GDK_EVENT_PROPAGATE; } /* All other cases, allow DnD to potentially begin */ if (!source_target_list) { source_target_list = nemo_list_model_get_drag_target_list (); } if (gtk_drag_check_threshold (widget, view->details->drag_x, view->details->drag_y, event->x, event->y)) { gtk_drag_begin (widget, source_target_list, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK, view->details->drag_button, (GdkEvent*) event); } /* The event is handled by the DnD begin, don't propagate further */ return GDK_EVENT_STOP; } return GDK_EVENT_PROPAGATE; } static gboolean query_tooltip_callback (GtkWidget *widget, gint x, gint y, gboolean kb_mode, GtkTooltip *tooltip, gpointer user_data) { NemoListView *list_view; gboolean ret; ret = FALSE; list_view = NEMO_LIST_VIEW (user_data); if (list_view->details->show_tooltips) { GtkTreeIter iter; NemoFile *file; GtkTreePath *path = NULL; GtkTreeModel *model = GTK_TREE_MODEL (list_view->details->model); if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y, kb_mode, &model, &path, &iter)) { if (!gtk_tree_view_is_blank_at_pos (GTK_TREE_VIEW (widget), x, y, NULL, NULL, NULL, NULL)) { gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model), &iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); if (file) { gchar *tooltip_text; tooltip_text = nemo_file_construct_tooltip (file, list_view->details->tooltip_flags); gtk_tooltip_set_text (tooltip, tooltip_text); gtk_tree_view_set_tooltip_cell (GTK_TREE_VIEW (widget), tooltip, path, NULL, NULL); g_free (tooltip_text); ret = TRUE; } } } gtk_tree_path_free (path); } return ret; } static gboolean leave_notify_callback (GtkWidget *widget, GdkEventCrossing *event, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE && view->details->hover_path != NULL) { gtk_tree_path_free (view->details->hover_path); view->details->hover_path = NULL; } return FALSE; } static gboolean enter_notify_callback (GtkWidget *widget, GdkEventCrossing *event, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE) { if (view->details->hover_path != NULL) { gtk_tree_path_free (view->details->hover_path); } gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &view->details->hover_path, NULL, NULL, NULL); if (view->details->hover_path != NULL) { gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor); } } return FALSE; } static void do_popup_menu (GtkWidget *widget, NemoListView *view, GdkEventButton *event) { if (tree_view_has_selection (GTK_TREE_VIEW (widget))) { nemo_view_pop_up_selection_context_menu (NEMO_VIEW (view), event); } else { nemo_view_pop_up_background_context_menu (NEMO_VIEW (view), event); } } static void row_activated_callback (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, NemoListView *view) { activate_selected_items (view); } static void columns_reordered_callback (AtkObject *atk, gpointer user_data) { NemoListView *view = NEMO_LIST_VIEW (user_data); NemoDirectory *directory; gchar **columns; GList *vis_columns = NULL; int i; NemoFile *file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); columns = get_visible_columns (view); for (i = 0; columns[i] != NULL; ++i) { vis_columns = g_list_prepend (vis_columns, columns[i]); } vis_columns = g_list_reverse (vis_columns); GList *tv_list, *iter, *l; GList *list = NULL; tv_list = gtk_tree_view_get_columns (view->details->tree_view); for (iter = tv_list; iter != NULL; iter = iter->next) { for (l = vis_columns; l != NULL; l = l->next) { if (iter->data == g_hash_table_lookup (view->details->columns, l->data)) list = g_list_prepend (list, (gchar *)l->data); } } list = g_list_reverse (list); directory = nemo_view_get_model (NEMO_VIEW (view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { nemo_window_set_ignore_meta_column_order (nemo_view_get_nemo_window (NEMO_VIEW (view)), list); } else if (NEMO_IS_SEARCH_DIRECTORY (directory)) { gchar **column_array = string_array_from_string_glist (list); g_settings_set_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS, (const gchar **) column_array); g_strfreev (column_array); } else { nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, list); } g_list_free_full (list, g_free); g_free (columns); g_list_free (vis_columns); g_list_free (tv_list); } static gboolean clicked_on_text_in_name_cell (NemoListView *view, GtkTreePath *path, GdkEventButton *event) { gboolean ret = FALSE; NemoListViewDetails *details = view->details; int x_col_offset, x_cell_offset, width, expander_size, horizontal_separator, expansion_offset; x_col_offset = gtk_tree_view_column_get_x_offset (details->file_name_column); gtk_tree_view_column_cell_get_position (details->file_name_column, GTK_CELL_RENDERER (details->file_name_cell), &x_cell_offset, &width); gtk_widget_style_get (GTK_WIDGET (details->tree_view), "expander-size", &expander_size, "horizontal-separator", &horizontal_separator, NULL); expander_size += 4; expansion_offset = ((horizontal_separator / 2) + gtk_tree_path_get_depth (path) * expander_size); ret = (event->x > (expansion_offset + x_col_offset + x_cell_offset) && event->x < (x_col_offset + x_cell_offset + width)) && !gtk_tree_view_is_blank_at_pos (GTK_TREE_VIEW (view->details->tree_view), event->x, event->y, NULL, NULL, NULL, NULL); return ret; } static gboolean clicked_within_double_click_interval (NemoListView *view) { static gint64 last_click_time = 0; static int click_count = 0; gint64 current_time; gint interval; /* fetch system double-click time */ g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (view))), "gtk-double-click-time", &interval, NULL); current_time = g_get_monotonic_time (); if (current_time - last_click_time < interval * 1000) { click_count++; } else { click_count = 0; } /* Stash time for next compare */ last_click_time = current_time; /* Only allow double click */ if (click_count == 1) { click_count = 0; last_click_time = 0; return TRUE; } else { return FALSE; } } static gboolean clicked_within_slow_click_interval_on_text (NemoListView *view, GtkTreePath *path, GdkEventButton *event) { static gint64 last_slow_click_time = 0; static gint slow_click_count = 0; gint64 current_time; gint interval; gint double_click_interval; /* fetch system double-click time */ g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (view))), "gtk-double-click-time", &double_click_interval, NULL); /* slow click interval is always 2 seconds longer than the system * double-click interval. */ interval = double_click_interval + 2000; current_time = g_get_monotonic_time (); if (current_time - last_slow_click_time < interval * 1000) { slow_click_count = 1; } else { slow_click_count = 0; } /* Stash time for next compare */ last_slow_click_time = current_time; GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_view)); GList *selected = gtk_tree_selection_get_selected_rows (selection, NULL); gint selected_count = g_list_length (selected); g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free); if (selected_count != 1) return FALSE; /* Only allow second click on text to trigger this */ if (slow_click_count == 1 && view->details->double_click_path[1] && gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) == 0 && clicked_on_text_in_name_cell (view, path, event)) { slow_click_count = 0; return TRUE; } else { return FALSE; } } static gboolean handle_icon_double_click (NemoListView *view, GtkTreePath *path, GdkEventButton *event, gboolean on_expander) { /* Ignore double click if we are in single click mode */ if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE) { return FALSE; } if (clicked_within_double_click_interval (view) && view->details->double_click_path[1] && gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) == 0 && !on_expander) { /* NOTE: Activation can actually destroy the view if we're switching */ if (!button_event_modifies_selection (event)) { if ((event->button == 1 || event->button == 3)) { activate_selected_items (view); } else if (event->button == 2) { activate_selected_items_alternate (view, NULL, TRUE); } return TRUE; } else if (event->button == 1 && (event->state & GDK_SHIFT_MASK) != 0) { NemoFile *file; file = nemo_list_model_file_for_path (view->details->model, path); if (file != NULL) { activate_selected_items_alternate (view, file, TRUE); nemo_file_unref (file); } return TRUE; } } return FALSE; } static gboolean handle_icon_slow_two_click (NemoListView *view, GtkTreePath *path, GdkEventButton *event) { NemoListViewDetails *details; NemoFile *file; gboolean can_rename; details = view->details; if (!details->click_to_rename) return FALSE; file = nemo_list_model_file_for_path (view->details->model, path); can_rename = nemo_file_can_rename (file); nemo_file_unref (file); if (!can_rename) return FALSE; if (clicked_within_slow_click_interval_on_text (view, path, event) && !button_event_modifies_selection (event)) { return TRUE; } return FALSE; } static gboolean button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data) { NemoListView *view; GtkTreeView *tree_view; GtkTreePath *path; gboolean call_parent; GtkTreeSelection *selection; GtkWidgetClass *tree_view_class; int expander_size, horizontal_separator; gboolean on_expander; gboolean blank_click; view = NEMO_LIST_VIEW (callback_data); tree_view = GTK_TREE_VIEW (widget); tree_view_class = GTK_WIDGET_GET_CLASS (tree_view); selection = gtk_tree_view_get_selection (tree_view); blank_click = FALSE; /* Don't handle extra mouse buttons here */ if (event->button > 5) { return FALSE; } if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { return TRUE; } if (event->window != gtk_tree_view_get_bin_window (tree_view)) { return FALSE; } if (!nemo_view_get_active (NEMO_VIEW (view))) { NemoWindowSlot *slot = nemo_view_get_nemo_window_slot (NEMO_VIEW (view)); nemo_window_slot_make_hosting_pane_active (slot); return TRUE; } nemo_list_model_set_drag_view (NEMO_LIST_MODEL (gtk_tree_view_get_model (tree_view)), tree_view, event->x, event->y); view->details->ignore_button_release = FALSE; call_parent = TRUE; if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL)) { gtk_widget_style_get (widget, "expander-size", &expander_size, "horizontal-separator", &horizontal_separator, NULL); /* TODO we should not hardcode this extra padding. It is * EXPANDER_EXTRA_PADDING from GtkTreeView. */ expander_size += 4; on_expander = (event->x <= horizontal_separator / 2 + gtk_tree_path_get_depth (path) * expander_size); /* Keep track of path of last click so double clicks only happen * on the same item */ if ((event->button == 1 || event->button == 2) && event->type == GDK_BUTTON_PRESS) { if (view->details->double_click_path[1]) { gtk_tree_path_free (view->details->double_click_path[1]); } view->details->double_click_path[1] = view->details->double_click_path[0]; view->details->double_click_path[0] = gtk_tree_path_copy (path); } if (handle_icon_double_click (view, path, event, on_expander)) { /* Double clicking does not trigger a D&D action. */ view->details->drag_button = 0; } else { /* queue up renaming if we've clicked within the slow-click timeframe. Don't actually do it, however, until there's a button release (this allows dragging to occur on single items, without triggering rename) */ view->details->rename_on_release = handle_icon_slow_two_click (view, path, event); /* We're going to filter out some situations where * we can't let the default code run because all * but one row would be would be deselected. We don't * want that; we want the right click menu or single * click to apply to everything that's currently selected. */ if (event->button == 3) { blank_click = (!gtk_tree_selection_path_is_selected (selection, path) && gtk_tree_view_is_blank_at_pos (tree_view, event->x, event->y, NULL, NULL, NULL, NULL)); } if (event->button == 3 && (blank_click || gtk_tree_selection_path_is_selected (selection, path))) { call_parent = FALSE; } if ((event->button == 1 || event->button == 2) && ((event->state & GDK_CONTROL_MASK) != 0 || (event->state & GDK_SHIFT_MASK) == 0)) { view->details->row_selected_on_button_down = gtk_tree_selection_path_is_selected (selection, path); if (view->details->row_selected_on_button_down) { call_parent = on_expander; view->details->ignore_button_release = call_parent; } else if ((event->state & GDK_CONTROL_MASK) != 0) { GList *selected_rows; GList *l; call_parent = FALSE; if ((event->state & GDK_SHIFT_MASK) != 0) { GtkTreePath *cursor; gtk_tree_view_get_cursor (tree_view, &cursor, NULL); if (cursor != NULL) { gtk_tree_selection_select_range (selection, cursor, path); } else { gtk_tree_selection_select_path (selection, path); } } else { gtk_tree_selection_select_path (selection, path); } selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); /* This unselects everything */ gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE); /* So select it again */ l = selected_rows; while (l != NULL) { GtkTreePath *p = l->data; l = l->next; gtk_tree_selection_select_path (selection, p); gtk_tree_path_free (p); } g_list_free (selected_rows); } else { view->details->ignore_button_release = on_expander; } } if (call_parent) { g_signal_handlers_block_by_func (tree_view, row_activated_callback, view); tree_view_class->button_press_event (widget, event); g_signal_handlers_unblock_by_func (tree_view, row_activated_callback, view); } else if (gtk_tree_selection_path_is_selected (selection, path)) { gtk_widget_grab_focus (widget); } if ((event->button == 1 || event->button == 2) && event->type == GDK_BUTTON_PRESS) { view->details->drag_started = FALSE; view->details->drag_button = event->button; view->details->drag_x = event->x; view->details->drag_y = event->y; } if (event->button == 3) { if (blank_click) { gtk_tree_selection_unselect_all (selection); } do_popup_menu (widget, view, event); } } gtk_tree_path_free (path); } else { if ((event->button == 1 || event->button == 2) && event->type == GDK_BUTTON_PRESS) { if (view->details->double_click_path[1]) { gtk_tree_path_free (view->details->double_click_path[1]); } view->details->double_click_path[1] = view->details->double_click_path[0]; view->details->double_click_path[0] = NULL; } /* Deselect if people click outside any row. It's OK to let default code run; it won't reselect anything. */ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree_view)); tree_view_class->button_press_event (widget, event); if (event->button == 3) { do_popup_menu (widget, view, event); } } /* We chained to the default handler in this method, so never * let the default handler run */ return TRUE; } static gboolean button_release_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); view->details->rubber_banding = FALSE; if (event->button == view->details->drag_button) { stop_drag_check (view); if (!view->details->drag_started && !view->details->ignore_button_release) { nemo_list_view_did_not_drag (view, event); } } return FALSE; } static gboolean popup_menu_callback (GtkWidget *widget, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); do_popup_menu (widget, view, NULL); return TRUE; } static void subdirectory_done_loading_callback (NemoDirectory *directory, NemoListView *view) { nemo_list_model_subdirectory_done_loading (view->details->model, directory); } static void row_expanded_callback (GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer callback_data) { NemoListView *view; NemoDirectory *directory; view = NEMO_LIST_VIEW (callback_data); if (nemo_list_model_load_subdirectory (view->details->model, path, &directory)) { char *uri; uri = nemo_directory_get_uri (directory); DEBUG ("Row expaded callback for uri %s", uri); g_free (uri); nemo_view_add_subdirectory (NEMO_VIEW (view), directory); nemo_list_model_set_expanding (view->details->model, directory); if (nemo_directory_are_all_files_seen (directory)) { nemo_list_model_subdirectory_done_loading (view->details->model, directory); } else { g_signal_connect_object (directory, "done_loading", G_CALLBACK (subdirectory_done_loading_callback), view, 0); } nemo_directory_unref (directory); } } struct UnloadDelayData { NemoFile *file; NemoDirectory *directory; NemoListView *view; }; static gboolean unload_file_timeout (gpointer data) { struct UnloadDelayData *unload_data = data; GtkTreeIter iter; NemoListModel *model; GtkTreePath *path; if (unload_data->view != NULL) { model = unload_data->view->details->model; if (nemo_list_model_get_tree_iter_from_file (model, unload_data->file, unload_data->directory, &iter)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (!gtk_tree_view_row_expanded (unload_data->view->details->tree_view, path)) { nemo_list_model_unload_subdirectory (model, &iter); } gtk_tree_path_free (path); } g_object_remove_weak_pointer (G_OBJECT (unload_data->view), (gpointer *) &unload_data->view); } if (unload_data->directory) { nemo_directory_unref (unload_data->directory); } nemo_file_unref (unload_data->file); g_free (unload_data); return FALSE; } static void row_collapsed_callback (GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer callback_data) { NemoListView *view; NemoFile *file; NemoDirectory *directory; GtkTreeIter parent; struct UnloadDelayData *unload_data; GtkTreeModel *model; char *uri; view = NEMO_LIST_VIEW (callback_data); model = GTK_TREE_MODEL (view->details->model); gtk_tree_model_get (model, iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); directory = NULL; if (gtk_tree_model_iter_parent (model, &parent, iter)) { gtk_tree_model_get (model, &parent, NEMO_LIST_MODEL_SUBDIRECTORY_COLUMN, &directory, -1); } uri = nemo_file_get_uri (file); DEBUG ("Row collapsed callback for uri %s", uri); g_free (uri); unload_data = g_new (struct UnloadDelayData, 1); unload_data->view = view; unload_data->file = file; unload_data->directory = directory; g_object_add_weak_pointer (G_OBJECT (unload_data->view), (gpointer *) &unload_data->view); g_timeout_add_seconds (COLLAPSE_TO_UNLOAD_DELAY, unload_file_timeout, unload_data); } static void subdirectory_unloaded_callback (NemoListModel *model, NemoDirectory *directory, gpointer callback_data) { NemoListView *view; g_return_if_fail (NEMO_IS_LIST_MODEL (model)); g_return_if_fail (NEMO_IS_DIRECTORY (directory)); view = NEMO_LIST_VIEW(callback_data); g_signal_handlers_disconnect_by_func (directory, G_CALLBACK (subdirectory_done_loading_callback), view); nemo_view_remove_subdirectory (NEMO_VIEW (view), directory); } static gboolean key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data) { NemoView *view; GdkEventButton button_event = { 0 }; gboolean handled; GtkTreeView *tree_view; GtkTreePath *path; tree_view = GTK_TREE_VIEW (widget); view = NEMO_VIEW (callback_data); handled = FALSE; switch (event->keyval) { case GDK_KEY_F10: if (event->state & GDK_CONTROL_MASK) { nemo_view_pop_up_background_context_menu (view, &button_event); handled = TRUE; } break; case GDK_KEY_Right: gtk_tree_view_get_cursor (tree_view, &path, NULL); if (path) { gtk_tree_view_expand_row (tree_view, path, FALSE); gtk_tree_path_free (path); } handled = TRUE; break; case GDK_KEY_Left: gtk_tree_view_get_cursor (tree_view, &path, NULL); if (path) { if (!gtk_tree_view_collapse_row (tree_view, path)) { /* if the row is already collapsed or doesn't have any children, * jump to the parent row instead. */ if ((gtk_tree_path_get_depth (path) > 1) && gtk_tree_path_up (path)) { gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE); } } gtk_tree_path_free (path); } handled = TRUE; break; case GDK_KEY_space: if (event->state & GDK_CONTROL_MASK) { handled = FALSE; break; } if (!gtk_widget_has_focus (GTK_WIDGET (NEMO_LIST_VIEW (view)->details->tree_view))) { handled = FALSE; break; } if ((event->state & GDK_SHIFT_MASK) != 0) { activate_selected_items_alternate (NEMO_LIST_VIEW (view), NULL, TRUE); } else { preview_selected_items (NEMO_LIST_VIEW (view)); } handled = TRUE; break; case GDK_KEY_Return: case GDK_KEY_KP_Enter: if ((event->state & GDK_SHIFT_MASK) != 0) { activate_selected_items_alternate (NEMO_LIST_VIEW (view), NULL, TRUE); } else { activate_selected_items (NEMO_LIST_VIEW (view)); } handled = TRUE; break; case GDK_KEY_v: /* Eat Control + v to not enable type ahead */ if ((event->state & GDK_CONTROL_MASK) != 0) { handled = TRUE; } break; default: handled = FALSE; } return handled; } static void nemo_list_view_reveal_selection (NemoView *view) { GList *selection; g_return_if_fail (NEMO_IS_LIST_VIEW (view)); selection = nemo_view_get_selection (view); /* Make sure at least one of the selected items is scrolled into view */ if (selection != NULL) { NemoListView *list_view; NemoFile *file; GtkTreeIter iter; GtkTreePath *path; list_view = NEMO_LIST_VIEW (view); file = selection->data; if (nemo_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter); gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (path); } } nemo_file_list_free (selection); } static gboolean sort_criterion_changes_due_to_user (GtkTreeView *tree_view) { GList *columns, *p; GtkTreeViewColumn *column; GSignalInvocationHint *ihint; gboolean ret; ret = FALSE; columns = gtk_tree_view_get_columns (tree_view); for (p = columns; p != NULL; p = p->next) { column = p->data; ihint = g_signal_get_invocation_hint (column); if (ihint != NULL) { ret = TRUE; break; } } g_list_free (columns); return ret; } static void sort_column_changed_callback (GtkTreeSortable *sortable, NemoListView *view) { NemoFile *file; gint sort_column_id, default_sort_column_id; GtkSortType reversed; GQuark sort_attr, default_sort_attr; char *reversed_attr, *default_reversed_attr; gboolean default_sort_reversed; file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &reversed); sort_attr = nemo_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id); default_sort_column_id = nemo_list_model_get_sort_column_id_from_attribute (view->details->model, g_quark_from_string (get_default_sort_order (file, &default_sort_reversed))); default_sort_attr = nemo_list_model_get_attribute_from_sort_column_id (view->details->model, default_sort_column_id); if (nemo_global_preferences_get_ignore_view_metadata ()) nemo_window_set_ignore_meta_sort_column (nemo_view_get_nemo_window (NEMO_VIEW (view)), g_quark_to_string (sort_attr)); else nemo_file_set_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN, g_quark_to_string (default_sort_attr), g_quark_to_string (sort_attr)); default_reversed_attr = (default_sort_reversed ? (char *)"true" : (char *)"false"); if (view->details->last_sort_attr != sort_attr && sort_criterion_changes_due_to_user (view->details->tree_view)) { /* at this point, the sort order is always GTK_SORT_ASCENDING, if the sort column ID * switched. Invert the sort order, if it's the default criterion with a reversed preference, * or if it makes sense for the attribute (i.e. date). */ if (sort_attr == default_sort_attr) { /* use value from preferences */ reversed = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER); } else { reversed = nemo_file_is_date_sort_attribute_q (sort_attr); } if (reversed) { g_signal_handlers_block_by_func (sortable, sort_column_changed_callback, view); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view->details->model), sort_column_id, GTK_SORT_DESCENDING); g_signal_handlers_unblock_by_func (sortable, sort_column_changed_callback, view); } } if (nemo_global_preferences_get_ignore_view_metadata ()) { nemo_window_set_ignore_meta_sort_direction (nemo_view_get_nemo_window (NEMO_VIEW (view)), reversed ? SORT_DESCENDING : SORT_ASCENDING); } else { reversed_attr = (reversed ? (char *)"true" : (char *)"false"); nemo_file_set_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED, default_reversed_attr, reversed_attr); } /* Make sure selected item(s) is visible after sort */ nemo_list_view_reveal_selection (NEMO_VIEW (view)); view->details->last_sort_attr = sort_attr; } static gboolean editable_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { NemoListView *view = user_data; nemo_view_set_is_renaming (NEMO_VIEW (view), FALSE); nemo_view_unfreeze_updates (NEMO_VIEW (view)); return GDK_EVENT_PROPAGATE; } static void cell_renderer_editing_started_cb (GtkCellRenderer *renderer, GtkCellEditable *editable, const gchar *path_str, NemoListView *list_view) { GtkEntry *entry; entry = GTK_ENTRY (editable); list_view->details->editable_widget = editable; /* Free a previously allocated original_name */ g_free (list_view->details->original_name); list_view->details->original_name = g_strdup (gtk_entry_get_text (entry)); g_signal_connect (entry, "focus-out-event", G_CALLBACK (editable_focus_out_cb), list_view); nemo_clipboard_set_up_editable (GTK_EDITABLE (entry), nemo_view_get_ui_manager (NEMO_VIEW (list_view)), FALSE); } static void cell_renderer_editing_canceled (GtkCellRendererText *cell, NemoListView *view) { view->details->editable_widget = NULL; nemo_view_set_is_renaming (NEMO_VIEW (view), FALSE); nemo_view_unfreeze_updates (NEMO_VIEW (view)); } static void cell_renderer_edited (GtkCellRendererText *cell, const char *path_str, const char *new_text, NemoListView *view) { GtkTreePath *path; NemoFile *file; GtkTreeIter iter; view->details->editable_widget = NULL; nemo_view_set_is_renaming (NEMO_VIEW (view), FALSE); /* Don't allow a rename with an empty string. Revert to original * without notifying the user. */ if (new_text[0] == '\0') { g_object_set (G_OBJECT (view->details->file_name_cell), "editable", FALSE, NULL); nemo_view_unfreeze_updates (NEMO_VIEW (view)); return; } path = gtk_tree_path_new_from_string (path_str); gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model), &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (GTK_TREE_MODEL (view->details->model), &iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); /* Only rename if name actually changed */ if (strcmp (new_text, view->details->original_name) != 0) { view->details->renaming_file = nemo_file_ref (file); view->details->rename_done = FALSE; nemo_rename_file (file, new_text, nemo_list_view_rename_callback, g_object_ref (view)); g_free (view->details->original_name); view->details->original_name = g_strdup (new_text); } nemo_file_unref (file); /*We're done editing - make the filename-cells readonly again.*/ g_object_set (G_OBJECT (view->details->file_name_cell), "editable", FALSE, NULL); nemo_view_unfreeze_updates (NEMO_VIEW (view)); } static char * get_root_uri_callback (NemoTreeViewDragDest *dest, gpointer user_data) { NemoListView *view; view = NEMO_LIST_VIEW (user_data); return nemo_view_get_uri (NEMO_VIEW (view)); } static NemoFile * get_file_for_path_callback (NemoTreeViewDragDest *dest, GtkTreePath *path, gpointer user_data) { NemoListView *view; view = NEMO_LIST_VIEW (user_data); return nemo_list_model_file_for_path (view->details->model, path); } /* Handles an URL received from Mozilla */ static void list_view_handle_netscape_url (NemoTreeViewDragDest *dest, const char *encoded_url, const char *target_uri, GdkDragAction action, int x, int y, NemoListView *view) { nemo_view_handle_netscape_url_drop (NEMO_VIEW (view), encoded_url, target_uri, action, x, y); } static void list_view_handle_uri_list (NemoTreeViewDragDest *dest, const char *item_uris, const char *target_uri, GdkDragAction action, int x, int y, NemoListView *view) { nemo_view_handle_uri_list_drop (NEMO_VIEW (view), item_uris, target_uri, action, x, y); } static void list_view_handle_text (NemoTreeViewDragDest *dest, const char *text, const char *target_uri, GdkDragAction action, int x, int y, NemoListView *view) { nemo_view_handle_text_drop (NEMO_VIEW (view), text, target_uri, action, x, y); } static void list_view_handle_raw (NemoTreeViewDragDest *dest, const char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y, NemoListView *view) { nemo_view_handle_raw_drop (NEMO_VIEW (view), raw_data, length, target_uri, direct_save_uri, action, x, y); } static void move_copy_items_callback (NemoTreeViewDragDest *dest, const GList *item_uris, const char *target_uri, guint action, int x, int y, gpointer user_data) { NemoView *view = user_data; nemo_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), item_uris, nemo_view_get_copied_files_atom (view)); nemo_view_move_copy_items (view, item_uris, NULL, target_uri, action, x, y); } static void column_header_menu_toggled (GtkCheckMenuItem *menu_item, NemoListView *list_view) { NemoFile *file; NemoDirectory *directory; char **visible_columns; const char *menu_item_column_id; GList *list = NULL; GList *l, *current_view_columns; int i; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); menu_item_column_id = g_object_get_data (G_OBJECT (menu_item), "column-name"); current_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view); for (l = current_view_columns; l != NULL; l = l->next) { GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (l->data); const char *current_id = g_object_get_data (G_OBJECT (c), "column-id"); if (g_strcmp0 (current_id, menu_item_column_id) == 0) { if (gtk_check_menu_item_get_active (menu_item)) { list = g_list_prepend (list, g_strdup (current_id)); } } else { if (gtk_tree_view_column_get_visible (c)) list = g_list_prepend (list, g_strdup (current_id)); } } directory = nemo_view_get_model (NEMO_VIEW (list_view)); list = g_list_reverse (list); if (nemo_global_preferences_get_ignore_view_metadata ()) nemo_window_set_ignore_meta_visible_columns (nemo_view_get_nemo_window (NEMO_VIEW (list_view)), list); else if (NEMO_IS_SEARCH_DIRECTORY (directory)) { gchar **column_array = string_array_from_string_glist (list); g_settings_set_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS, (const gchar **) column_array); g_strfreev (column_array); } else nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, list); visible_columns = g_new0 (char *, g_list_length (list) + 1); for (i = 0, l = list; l != NULL; ++i, l = l->next) { visible_columns[i] = l->data; } /* set view values ourselves, as new metadata could not have been * updated yet. */ apply_columns_settings (list_view, visible_columns, visible_columns); g_list_free (list); g_list_free (current_view_columns); g_strfreev (visible_columns); } static void column_header_menu_use_default (GtkMenuItem *menu_item, NemoListView *list_view) { NemoFile *file; NemoDirectory *directory; char **default_columns; char **default_order; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); g_signal_handlers_block_by_func (list_view->details->tree_view, columns_reordered_callback, list_view); if (nemo_global_preferences_get_ignore_view_metadata ()) { NemoWindow *window = nemo_view_get_nemo_window (NEMO_VIEW (list_view)); nemo_window_set_ignore_meta_visible_columns (window, NULL); nemo_window_set_ignore_meta_column_order (window, NULL); } else { nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL); nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL); } directory = nemo_view_get_model (NEMO_VIEW (list_view)); if (NEMO_IS_SEARCH_DIRECTORY (directory)) g_settings_reset (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS); default_columns = get_default_visible_columns (list_view); default_order = get_default_column_order (list_view); /* set view values ourselves, as new metadata could not have been * updated yet. */ apply_columns_settings (list_view, default_order, default_columns); g_signal_handlers_unblock_by_func (list_view->details->tree_view, columns_reordered_callback, list_view); g_strfreev (default_columns); g_strfreev (default_order); } static void column_header_menu_disable_sort (GtkMenuItem *menu_item, NemoListView *list_view) { gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_item)); nemo_list_model_set_temporarily_disable_sort (list_view->details->model, active); } static gboolean column_header_clicked (GtkWidget *column_button, GdkEventButton *event, NemoListView *list_view) { GList *current_view_columns, *l; NemoFile *file; GtkWidget *menu; GtkWidget *menu_item; if (event->button != GDK_BUTTON_SECONDARY) { return FALSE; } file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); menu = gtk_menu_new (); current_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view); for (l = current_view_columns; l != NULL; l = l->next) { const char *name; char *label; char *lowercase; gboolean visible; GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (l->data); name = g_object_get_data (G_OBJECT (c), "column-id"); if (!nemo_file_is_in_trash (file)) { if (g_strcmp0 (name, "trashed_on") == 0 || g_strcmp0 (name, "trash_orig_path") == 0) continue; } g_object_get (G_OBJECT (c), "title", &label, "visible", &visible, NULL); lowercase = g_ascii_strdown (name, -1); menu_item = gtk_check_menu_item_new_with_label (label); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); g_object_set_data_full (G_OBJECT (menu_item), "column-name", g_strdup (name), g_free); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), visible); /* Don't allow hiding the filename */ if (g_strcmp0 (lowercase, "name") == 0) { gtk_widget_set_sensitive (GTK_WIDGET (menu_item), FALSE); } g_signal_connect (menu_item, "toggled", G_CALLBACK (column_header_menu_toggled), list_view); g_clear_pointer (&lowercase, g_free); g_clear_pointer (&label, g_free); } menu_item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); menu_item = gtk_menu_item_new_with_label (_("Use Default")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); g_signal_connect (menu_item, "activate", G_CALLBACK (column_header_menu_use_default), list_view); menu_item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); menu_item = gtk_check_menu_item_new_with_label (_("Temporarily disable auto-sort")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), nemo_list_model_get_temporarily_disable_sort (list_view->details->model)); g_signal_connect (menu_item, "activate", G_CALLBACK (column_header_menu_disable_sort), list_view); gtk_widget_show_all (menu); gtk_menu_popup_for_device (GTK_MENU (menu), gdk_event_get_device ((GdkEvent *) event), NULL, NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } static void apply_columns_settings (NemoListView *list_view, char **column_order, char **visible_columns) { GList *all_columns; NemoFile *file; GList *old_view_columns, *view_columns; GHashTable *visible_columns_hash; GList *l; gint i; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); /* prepare ordered list of view columns using column_order and visible_columns */ view_columns = NULL; all_columns = nemo_get_columns_for_file (file); all_columns = nemo_sort_columns (all_columns, column_order); /* hash table to lookup if a given column should be visible */ visible_columns_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); for (i = 0; visible_columns[i] != NULL; ++i) { g_hash_table_insert (visible_columns_hash, g_ascii_strdown (visible_columns[i], -1), g_ascii_strdown (visible_columns[i], -1)); } for (l = all_columns; l != NULL; l = l->next) { char *name; char *lowercase; g_object_get (G_OBJECT (l->data), "name", &name, NULL); lowercase = g_ascii_strdown (name, -1); if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) { GtkTreeViewColumn *view_column; view_column = g_hash_table_lookup (list_view->details->columns, name); if (view_column != NULL) { view_columns = g_list_prepend (view_columns, view_column); } } g_free (name); g_free (lowercase); } g_hash_table_destroy (visible_columns_hash); nemo_column_list_free (all_columns); view_columns = g_list_reverse (view_columns); /* hide columns that are not present in the configuration */ old_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view); for (l = old_view_columns; l != NULL; l = l->next) { if (g_list_find (view_columns, l->data) == NULL) { gtk_tree_view_column_set_visible (l->data, FALSE); } } g_list_free (old_view_columns); /* see bug: https://github.com/GNOME/gtk/commit/497e877755f1fa1 * Explanation for branching - move_column_after generates useless logfile spam, * and to avoid it, simply removing and adding columns in a different order works * just as well. The problem is, gtk versions < 3.22.25 lack the patch referenced * in the above bug report. An additional problem is that different pre-3.22.25 * versions behave differently depending on other code changes in GtkTreeViewColumn. * Mint 18 (gtk 3.18.9) using the add/remove column method would make a new button * widget upon reparenting, losing existing signal handlers. In 3.22.11, however, * (debian stretch, LMDE3,) we get a nice segfault. * * This may seem a long way to go for a clean log, but the warnings can accumulate * quickly... */ if (gtk_check_version (3, 22, 25) == NULL) { gint prev_view_column; prev_view_column = 0; for (l = view_columns; l != NULL; l = l->next) { g_signal_handlers_disconnect_by_func (gtk_tree_view_column_get_button (l->data), column_header_clicked, list_view); gtk_tree_view_remove_column (list_view->details->tree_view, g_object_ref (l->data)); gtk_tree_view_insert_column (list_view->details->tree_view, l->data, prev_view_column ++); g_signal_connect (gtk_tree_view_column_get_button (l->data), "button-press-event", G_CALLBACK (column_header_clicked), list_view); gtk_tree_view_column_set_visible (l->data, TRUE); g_object_unref (l->data); } } else { GtkTreeViewColumn *prev_view_column; /* show new columns from the configuration */ for (l = view_columns; l != NULL; l = l->next) { gtk_tree_view_column_set_visible (l->data, TRUE); } /* place columns in the correct order */ prev_view_column = NULL; for (l = view_columns; l != NULL; l = l->next) { gtk_tree_view_move_column_after (list_view->details->tree_view, l->data, prev_view_column); prev_view_column = l->data; } } g_list_free (view_columns); } static void filename_cell_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, NemoListView *view) { char *text; GtkTreePath *path; PangoUnderline underline; gint weight; gtk_tree_model_get (model, iter, view->details->file_name_column_num, &text, NEMO_LIST_MODEL_TEXT_WEIGHT_COLUMN, &weight, -1); if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE) { path = gtk_tree_model_get_path (model, iter); if (view->details->hover_path == NULL || gtk_tree_path_compare (path, view->details->hover_path)) { underline = PANGO_UNDERLINE_NONE; } else { underline = PANGO_UNDERLINE_SINGLE; } gtk_tree_path_free (path); } else { underline = PANGO_UNDERLINE_NONE; } g_object_set (G_OBJECT (renderer), "text", text, "underline", underline, "weight", weight, NULL); g_free (text); } static gboolean focus_in_event_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { NemoWindowSlot *slot; NemoListView *list_view = NEMO_LIST_VIEW (user_data); /* make the corresponding slot (and the pane that contains it) active */ slot = nemo_view_get_nemo_window_slot (NEMO_VIEW (list_view)); nemo_window_slot_make_hosting_pane_active (slot); return FALSE; } static gint get_icon_scale_callback (NemoListModel *model, NemoListView *view) { return gtk_widget_get_scale_factor (GTK_WIDGET (view->details->tree_view)); } static void create_and_set_up_tree_view (NemoListView *view) { GtkCellRenderer *cell; GtkTreeViewColumn *column; GtkBindingSet *binding_set; AtkObject *atk_obj; GList *nemo_columns; GList *l; gchar **default_column_order, **default_visible_columns; view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (view->details->tree_view), TRUE); view->details->columns = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); gtk_tree_view_set_enable_search (view->details->tree_view, TRUE); /* Don't handle backspace key. It's used to open the parent folder. */ binding_set = gtk_binding_set_by_class (GTK_WIDGET_GET_CLASS (view->details->tree_view)); gtk_binding_entry_remove (binding_set, GDK_KEY_BackSpace, 0); view->details->drag_dest = nemo_tree_view_drag_dest_new (view->details->tree_view); g_signal_connect_object (view->details->drag_dest, "get_root_uri", G_CALLBACK (get_root_uri_callback), view, 0); g_signal_connect_object (view->details->drag_dest, "get_file_for_path", G_CALLBACK (get_file_for_path_callback), view, 0); g_signal_connect_object (view->details->drag_dest, "move_copy_items", G_CALLBACK (move_copy_items_callback), view, 0); g_signal_connect_object (view->details->drag_dest, "handle_netscape_url", G_CALLBACK (list_view_handle_netscape_url), view, 0); g_signal_connect_object (view->details->drag_dest, "handle_uri_list", G_CALLBACK (list_view_handle_uri_list), view, 0); g_signal_connect_object (view->details->drag_dest, "handle_text", G_CALLBACK (list_view_handle_text), view, 0); g_signal_connect_object (view->details->drag_dest, "handle_raw", G_CALLBACK (list_view_handle_raw), view, 0); g_signal_connect_object (gtk_tree_view_get_selection (view->details->tree_view), "changed", G_CALLBACK (list_selection_changed_callback), view, 0); g_signal_connect_object (GTK_WIDGET (view->details->tree_view), "query-tooltip", G_CALLBACK (query_tooltip_callback), view, 0); g_signal_connect_object (view->details->tree_view, "drag_begin", G_CALLBACK (drag_begin_callback), view, 0); g_signal_connect_object (view->details->tree_view, "drag_data_get", G_CALLBACK (drag_data_get_callback), view, 0); g_signal_connect_object (view->details->tree_view, "motion_notify_event", G_CALLBACK (motion_notify_callback), view, 0); g_signal_connect_object (view->details->tree_view, "enter_notify_event", G_CALLBACK (enter_notify_callback), view, 0); g_signal_connect_object (view->details->tree_view, "leave_notify_event", G_CALLBACK (leave_notify_callback), view, 0); g_signal_connect_object (view->details->tree_view, "button_press_event", G_CALLBACK (button_press_callback), view, 0); g_signal_connect_object (view->details->tree_view, "button_release_event", G_CALLBACK (button_release_callback), view, 0); g_signal_connect_object (view->details->tree_view, "key_press_event", G_CALLBACK (key_press_callback), view, 0); g_signal_connect_object (view->details->tree_view, "popup_menu", G_CALLBACK (popup_menu_callback), view, 0); g_signal_connect_object (view->details->tree_view, "row_expanded", G_CALLBACK (row_expanded_callback), view, 0); g_signal_connect_object (view->details->tree_view, "row_collapsed", G_CALLBACK (row_collapsed_callback), view, 0); g_signal_connect_object (view->details->tree_view, "row-activated", G_CALLBACK (row_activated_callback), view, 0); g_signal_connect_object (view->details->tree_view, "focus_in_event", G_CALLBACK(focus_in_event_callback), view, 0); view->details->model = g_object_new (NEMO_TYPE_LIST_MODEL, NULL); gtk_tree_view_set_model (view->details->tree_view, GTK_TREE_MODEL (view->details->model)); /* Need the model for the dnd drop icon "accept" change */ nemo_list_model_set_drag_view (NEMO_LIST_MODEL (view->details->model), view->details->tree_view, 0, 0); g_signal_connect_object (view->details->model, "sort_column_changed", G_CALLBACK (sort_column_changed_callback), view, 0); g_signal_connect_object (view->details->model, "subdirectory_unloaded", G_CALLBACK (subdirectory_unloaded_callback), view, 0); g_signal_connect_object (view->details->model, "get-icon-scale", G_CALLBACK (get_icon_scale_callback), view, 0); gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE); gtk_tree_view_set_rules_hint (view->details->tree_view, TRUE); nemo_columns = nemo_get_all_columns (); for (l = nemo_columns; l != NULL; l = l->next) { NemoColumn *nemo_column; int column_num; char *name; char *label; float xalign; nemo_column = NEMO_COLUMN (l->data); g_object_get (nemo_column, "name", &name, "label", &label, "xalign", &xalign, NULL); column_num = nemo_list_model_add_column (view->details->model, nemo_column); /* Created the name column specially, because it * has the icon in it.*/ if (!strcmp (name, "name")) { /* Create the file name column */ cell = gtk_cell_renderer_pixbuf_new (); view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell; view->details->file_name_column = gtk_tree_view_column_new (); gtk_tree_view_append_column (view->details->tree_view, view->details->file_name_column); g_object_set_data_full (G_OBJECT (view->details->file_name_column), "column-id", g_strdup (name), g_free); view->details->file_name_column_num = column_num; g_hash_table_insert (view->details->columns, g_strdup ("name"), view->details->file_name_column); g_signal_connect (gtk_tree_view_column_get_button (view->details->file_name_column), "button-press-event", G_CALLBACK (column_header_clicked), view); gtk_tree_view_set_search_column (view->details->tree_view, column_num); gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, column_num); gtk_tree_view_column_set_title (view->details->file_name_column, _("Name")); gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE); gtk_tree_view_column_set_min_width (view->details->file_name_column, 100); gtk_tree_view_column_set_reorderable (view->details->file_name_column, TRUE); gtk_tree_view_column_set_expand (view->details->file_name_column, TRUE); gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE); gtk_tree_view_column_set_attributes (view->details->file_name_column, cell, "surface", NEMO_LIST_MODEL_SMALLEST_ICON_COLUMN, NULL); cell = gtk_cell_renderer_text_new (); view->details->file_name_cell = (GtkCellRendererText *)cell; g_object_set (cell, "xpad", 5, "ellipsize", PANGO_ELLIPSIZE_END, "width-chars", 40, NULL); g_signal_connect (cell, "edited", G_CALLBACK (cell_renderer_edited), view); g_signal_connect (cell, "editing-canceled", G_CALLBACK (cell_renderer_editing_canceled), view); g_signal_connect (cell, "editing-started", G_CALLBACK (cell_renderer_editing_started_cb), view); gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE); gtk_tree_view_column_set_cell_data_func (view->details->file_name_column, cell, (GtkTreeCellDataFunc) filename_cell_data_func, view, NULL); } else { cell = gtk_cell_renderer_text_new (); g_object_set (cell, "xalign", xalign, "xpad", 5, NULL); view->details->cells = g_list_append (view->details->cells, cell); column = gtk_tree_view_column_new (); g_object_set_data_full (G_OBJECT (column), "column-id", g_strdup (name), g_free); gtk_tree_view_column_set_title (column, label); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_set_attributes (column, cell, "text", column_num, "weight", NEMO_LIST_MODEL_TEXT_WEIGHT_COLUMN, NULL); gtk_tree_view_append_column (view->details->tree_view, column); gtk_tree_view_column_set_min_width (column, 30); gtk_tree_view_column_set_sort_column_id (column, column_num); g_hash_table_insert (view->details->columns, g_strdup (name), column); g_signal_connect (gtk_tree_view_column_get_button (column), "button-press-event", G_CALLBACK (column_header_clicked), view); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_reorderable (column, TRUE); } g_free (name); g_free (label); } nemo_column_list_free (nemo_columns); default_visible_columns = g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); default_column_order = g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); /* Apply the default column order and visible columns, to get it * right most of the time. The metadata will be checked when a * folder is loaded */ apply_columns_settings (view, default_column_order, default_visible_columns); gtk_widget_show (GTK_WIDGET (view->details->tree_view)); gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_view)); atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view)); atk_object_set_name (atk_obj, _("List View")); gtk_widget_set_has_tooltip (GTK_WIDGET (view->details->tree_view), TRUE); g_strfreev (default_visible_columns); g_strfreev (default_column_order); } static void nemo_list_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoListModel *model; if (nemo_file_has_thumbnail_access_problem (file)) { nemo_application_set_cache_flag (nemo_application_get_singleton ()); nemo_window_slot_check_bad_cache_bar (nemo_view_get_nemo_window_slot (view)); } model = NEMO_LIST_VIEW (view)->details->model; nemo_list_model_add_file (model, file, directory); } static char ** get_default_visible_columns (NemoListView *list_view) { NemoFile *file; NemoDirectory *directory; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_file_is_in_trash (file)) { return g_strdupv ((gchar **) default_trash_visible_columns); } if (nemo_file_is_in_recent (file)) { return g_strdupv ((gchar **) default_recent_visible_columns); } directory = nemo_view_get_model (NEMO_VIEW (list_view)); if (NEMO_IS_SEARCH_DIRECTORY (directory)) { return g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS); } return g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); } static char ** get_visible_columns (NemoListView *list_view) { NemoFile *file; GList *visible_columns; char **ret; ret = NULL; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { visible_columns = nemo_window_get_ignore_meta_visible_columns (nemo_view_get_nemo_window (NEMO_VIEW (list_view))); } else { visible_columns = nemo_file_get_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS); } if (visible_columns) { ret = string_array_from_string_glist (visible_columns); g_list_free_full (visible_columns, g_free); } if (ret != NULL) { return ret; } return get_default_visible_columns (list_view); } static char ** get_default_column_order (NemoListView *list_view) { NemoFile *file; NemoDirectory *directory; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_file_is_in_trash (file)) { return g_strdupv ((gchar **) default_trash_columns_order); } if (nemo_file_is_in_recent (file)) { return g_strdupv ((gchar **) default_recent_columns_order); } directory = nemo_view_get_model (NEMO_VIEW (list_view)); if (NEMO_IS_SEARCH_DIRECTORY (directory)) { return g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS); } return g_settings_get_strv (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); } static char ** get_column_order (NemoListView *list_view) { NemoFile *file; GList *column_order; char **ret; ret = NULL; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { column_order = nemo_window_get_ignore_meta_column_order (nemo_view_get_nemo_window (NEMO_VIEW (list_view))); } else { column_order = nemo_file_get_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER); } if (column_order) { ret = string_array_from_string_glist (column_order); g_list_free_full (column_order, g_free); } if (ret != NULL) { return ret; } return get_default_column_order (list_view); } static void set_columns_settings_from_metadata_and_preferences (NemoListView *list_view) { char **column_order; char **visible_columns; column_order = get_column_order (list_view); visible_columns = get_visible_columns (list_view); apply_columns_settings (list_view, column_order, visible_columns); g_strfreev (column_order); g_strfreev (visible_columns); } static void set_sort_order_from_metadata_and_preferences (NemoListView *list_view) { char *sort_attribute; int sort_column_id; NemoFile *file; gboolean sort_reversed, default_sort_reversed; const gchar *default_sort_order; file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_global_preferences_get_ignore_view_metadata ()) sort_attribute = g_strdup (nemo_window_get_ignore_meta_sort_column (nemo_view_get_nemo_window (NEMO_VIEW (list_view)))); else sort_attribute = nemo_file_get_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL); sort_column_id = nemo_list_model_get_sort_column_id_from_attribute (list_view->details->model, g_quark_from_string (sort_attribute)); g_free (sort_attribute); default_sort_order = get_default_sort_order (file, &default_sort_reversed); if (sort_column_id == -1) { sort_column_id = nemo_list_model_get_sort_column_id_from_attribute (list_view->details->model, g_quark_from_string (default_sort_order)); } if (nemo_global_preferences_get_ignore_view_metadata ()) { gint dir = nemo_window_get_ignore_meta_sort_direction (nemo_view_get_nemo_window (NEMO_VIEW (list_view))); sort_reversed = dir > SORT_NULL ? dir == SORT_DESCENDING : default_sort_reversed; } else { sort_reversed = nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED, default_sort_reversed); } gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_view->details->model), sort_column_id, sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING); } static gboolean list_view_changed_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gtk_tree_model_row_changed (model, path, iter); return FALSE; } static NemoZoomLevel get_default_zoom_level (void) { NemoZoomLevel default_zoom_level; default_zoom_level = g_settings_get_enum (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL); if (default_zoom_level < NEMO_ZOOM_LEVEL_SMALLEST || NEMO_ZOOM_LEVEL_LARGEST < default_zoom_level) { default_zoom_level = NEMO_ZOOM_LEVEL_SMALL; } return default_zoom_level; } static void set_zoom_level_from_metadata_and_preferences (NemoListView *list_view) { NemoFile *file; int level; if (nemo_view_supports_zooming (NEMO_VIEW (list_view))) { file = nemo_view_get_directory_as_file (NEMO_VIEW (list_view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { gchar *uri; uri = nemo_file_get_uri (file); if (eel_uri_is_search (uri)) { level = get_default_zoom_level (); } else { gint ignore_level; ignore_level = nemo_window_get_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (list_view))); level = ignore_level > -1 ? ignore_level : get_default_zoom_level (); } g_free (uri); } else { level = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL, get_default_zoom_level ()); } nemo_list_view_set_zoom_level (list_view, level, TRUE); /* updated the rows after updating the font size */ gtk_tree_model_foreach (GTK_TREE_MODEL (list_view->details->model), list_view_changed_foreach, NULL); } } static void nemo_list_view_begin_loading (NemoView *view) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); set_sort_order_from_metadata_and_preferences (list_view); set_zoom_level_from_metadata_and_preferences (list_view); set_columns_settings_from_metadata_and_preferences (list_view); AtkObject *atk = gtk_widget_get_accessible (GTK_WIDGET (NEMO_LIST_VIEW (view)->details->tree_view)); g_signal_connect_object (atk, "column-reordered", G_CALLBACK (columns_reordered_callback), view, 0); } static void stop_cell_editing (NemoListView *list_view) { GtkTreeViewColumn *column; /* Stop an ongoing rename to commit the name changes when the user * changes directories without exiting cell edit mode. It also prevents * the edited handler from being called on the cleared list model. */ column = list_view->details->file_name_column; if (column != NULL && list_view->details->editable_widget != NULL && GTK_IS_CELL_EDITABLE (list_view->details->editable_widget)) { gtk_cell_editable_editing_done (list_view->details->editable_widget); } } static void nemo_list_view_clear (NemoView *view) { NemoListView *list_view; GtkTreeSelection *tree_selection; list_view = NEMO_LIST_VIEW (view); tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view); g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view); if (list_view->details->model != NULL) { stop_cell_editing (list_view); nemo_list_model_clear (list_view->details->model); } g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view); } static void nemo_list_view_rename_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { NemoListView *view; view = NEMO_LIST_VIEW (callback_data); if (view->details->renaming_file) { view->details->rename_done = TRUE; if (error != NULL) { /* If the rename failed (or was cancelled), kill renaming_file. * We won't get a change event for the rename, so otherwise * it would stay around forever. */ nemo_file_unref (view->details->renaming_file); view->details->renaming_file = NULL; } } g_object_unref (view); } static void nemo_list_view_file_changed (NemoView *view, NemoFile *file, NemoDirectory *directory) { NemoListView *listview; GtkTreeIter iter; GtkTreePath *file_path; listview = NEMO_LIST_VIEW (view); nemo_list_model_file_changed (listview->details->model, file, directory); if (listview->details->renaming_file != NULL && file == listview->details->renaming_file && listview->details->rename_done) { /* This is (probably) the result of the rename operation, and * the tree-view changes above could have resorted the list, so * scroll to the new position */ if (nemo_list_model_get_tree_iter_from_file (listview->details->model, file, directory, &iter)) { file_path = gtk_tree_model_get_path (GTK_TREE_MODEL (listview->details->model), &iter); gtk_tree_view_scroll_to_cell (listview->details->tree_view, file_path, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (file_path); } nemo_file_unref (listview->details->renaming_file); listview->details->renaming_file = NULL; } } typedef struct { GtkTreePath *path; gboolean is_common; gboolean is_root; } HasCommonParentData; static void tree_selection_has_common_parent_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { HasCommonParentData *data; GtkTreePath *parent_path; gboolean has_parent; data = (HasCommonParentData *) user_data; parent_path = gtk_tree_path_copy (path); gtk_tree_path_up (parent_path); has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE; if (!has_parent) { data->is_root = TRUE; } if (data->is_common && !data->is_root) { if (data->path == NULL) { data->path = gtk_tree_path_copy (parent_path); } else if (gtk_tree_path_compare (data->path, parent_path) != 0) { data->is_common = FALSE; } } gtk_tree_path_free (parent_path); } static void tree_selection_has_common_parent (GtkTreeSelection *selection, gboolean *is_common, gboolean *is_root) { HasCommonParentData data; g_assert (is_common != NULL); g_assert (is_root != NULL); data.path = NULL; data.is_common = *is_common = TRUE; data.is_root = *is_root = FALSE; gtk_tree_selection_selected_foreach (selection, tree_selection_has_common_parent_foreach_func, &data); *is_common = data.is_common; *is_root = data.is_root; if (data.path != NULL) { gtk_tree_path_free (data.path); } } static char * nemo_list_view_get_backing_uri (NemoView *view) { NemoListView *list_view; NemoListModel *list_model; NemoFile *file; GtkTreeView *tree_view; GtkTreeSelection *selection; GtkTreePath *path; GList *paths; guint length; char *uri; g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), NULL); list_view = NEMO_LIST_VIEW (view); list_model = list_view->details->model; tree_view = list_view->details->tree_view; g_assert (list_model); /* We currently handle three common cases here: * (a) if the selection contains non-filesystem items (i.e., the * "(Empty)" label), we return the uri of the parent. * (b) if the selection consists of exactly one _expanded_ directory, we * return its URI. * (c) if the selection consists of either exactly one item which is not * an expanded directory) or multiple items in the same directory, * we return the URI of the common parent. */ uri = NULL; selection = gtk_tree_view_get_selection (tree_view); length = gtk_tree_selection_count_selected_rows (selection); if (length == 1) { paths = gtk_tree_selection_get_selected_rows (selection, NULL); path = (GtkTreePath *) paths->data; file = nemo_list_model_file_for_path (list_model, path); if (file == NULL) { /* The selected item is a label, not a file */ gtk_tree_path_up (path); file = nemo_list_model_file_for_path (list_model, path); } if (file != NULL) { if (nemo_file_is_directory (file) && gtk_tree_view_row_expanded (tree_view, path)) { uri = nemo_file_get_uri (file); } nemo_file_unref (file); } gtk_tree_path_free (path); g_list_free (paths); } if (uri == NULL && length > 0) { gboolean is_common, is_root; /* Check that all the selected items belong to the same * directory and that directory is not the root directory (which * is handled by NemoView::get_backing_directory.) */ tree_selection_has_common_parent (selection, &is_common, &is_root); if (is_common && !is_root) { paths = gtk_tree_selection_get_selected_rows (selection, NULL); path = (GtkTreePath *) paths->data; file = nemo_list_model_file_for_path (list_model, path); g_assert (file != NULL); uri = nemo_file_get_parent_uri (file); nemo_file_unref (file); g_list_foreach (paths, (GFunc) gtk_tree_path_free, NULL); g_list_free (paths); } } if (uri != NULL) { return uri; } return NEMO_VIEW_CLASS (nemo_list_view_parent_class)->get_backing_uri (view); } static void nemo_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **list; NemoFile *file; list = data; gtk_tree_model_get (model, iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); if (file != NULL) { (* list) = g_list_prepend ((* list), file); } } static GList * nemo_list_view_get_selection (NemoView *view) { GList *list; list = NULL; gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (NEMO_LIST_VIEW (view)->details->tree_view), nemo_list_view_get_selection_foreach_func, &list); return g_list_reverse (list); } static GList * nemo_list_view_peek_selection (NemoView *view) { NemoListView *list_view = NEMO_LIST_VIEW (view); if (list_view->details->current_selection_count == -1) { nemo_list_view_update_selection (NEMO_VIEW (list_view)); } return list_view->details->current_selection; } static gint nemo_list_view_get_selection_count (NemoView *view) { NemoListView *list_view = NEMO_LIST_VIEW (view); if (list_view->details->current_selection_count == -1) { nemo_list_view_update_selection (NEMO_VIEW (list_view)); } return list_view->details->current_selection_count; } static void nemo_list_view_update_selection (NemoView *view) { NemoListView *list_view = NEMO_LIST_VIEW (view); if (list_view->details->current_selection != NULL) { g_list_free (list_view->details->current_selection); list_view->details->current_selection = NULL; list_view->details->current_selection_count = 0; } list_view->details->current_selection = nemo_list_view_get_selection (view); list_view->details->current_selection_count = g_list_length (list_view->details->current_selection); } static void nemo_list_view_get_selection_for_file_transfer_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { NemoFile *file; struct SelectionForeachData *selection_data; GtkTreeIter parent, child; selection_data = data; gtk_tree_model_get (model, iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); if (file != NULL) { /* If the parent folder is also selected, don't include this file in the * file operation, since that would copy it to the toplevel target instead * of keeping it as a child of the copied folder */ child = *iter; while (gtk_tree_model_iter_parent (model, &parent, &child)) { if (gtk_tree_selection_iter_is_selected (selection_data->selection, &parent)) { return; } child = parent; } nemo_file_ref (file); selection_data->list = g_list_prepend (selection_data->list, file); } } static GList * nemo_list_view_get_selection_for_file_transfer (NemoView *view) { struct SelectionForeachData selection_data; selection_data.list = NULL; selection_data.selection = gtk_tree_view_get_selection (NEMO_LIST_VIEW (view)->details->tree_view); gtk_tree_selection_selected_foreach (selection_data.selection, nemo_list_view_get_selection_for_file_transfer_foreach_func, &selection_data); return g_list_reverse (selection_data.list); } static guint nemo_list_view_get_item_count (NemoView *view) { g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), 0); return nemo_list_model_get_length (NEMO_LIST_VIEW (view)->details->model); } static gboolean nemo_list_view_is_empty (NemoView *view) { return nemo_list_model_is_empty (NEMO_LIST_VIEW (view)->details->model); } static void nemo_list_view_end_file_changes (NemoView *view) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); if (list_view->details->new_selection_path) { gtk_tree_view_set_cursor (list_view->details->tree_view, list_view->details->new_selection_path, NULL, FALSE); gtk_tree_path_free (list_view->details->new_selection_path); list_view->details->new_selection_path = NULL; } } static void nemo_list_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { GtkTreePath *path; GtkTreePath *file_path; GtkTreeIter iter; GtkTreeIter temp_iter; GtkTreeRowReference* row_reference; NemoListView *list_view; GtkTreeModel* tree_model; GtkTreeSelection *selection; path = NULL; row_reference = NULL; list_view = NEMO_LIST_VIEW (view); tree_model = GTK_TREE_MODEL(list_view->details->model); if (nemo_list_model_get_tree_iter_from_file (list_view->details->model, file, directory, &iter)) { selection = gtk_tree_view_get_selection (list_view->details->tree_view); file_path = gtk_tree_model_get_path (tree_model, &iter); if (gtk_tree_selection_path_is_selected (selection, file_path)) { /* get reference for next element in the list view. If the element to be deleted is the * last one, get reference to previous element. If there is only one element in view * no need to select anything. */ temp_iter = iter; if (gtk_tree_model_iter_next (tree_model, &iter)) { path = gtk_tree_model_get_path (tree_model, &iter); row_reference = gtk_tree_row_reference_new (tree_model, path); } else { path = gtk_tree_model_get_path (tree_model, &temp_iter); if (gtk_tree_path_prev (path)) { row_reference = gtk_tree_row_reference_new (tree_model, path); } } gtk_tree_path_free (path); } gtk_tree_path_free (file_path); nemo_list_model_remove_file (list_view->details->model, file, directory); if (gtk_tree_row_reference_valid (row_reference)) { if (list_view->details->new_selection_path) { gtk_tree_path_free (list_view->details->new_selection_path); } list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference); } if (row_reference) { gtk_tree_row_reference_free (row_reference); } } } static void nemo_list_view_set_selection (NemoView *view, GList *selection) { NemoListView *list_view; GtkTreeSelection *tree_selection; GList *node; GList *iters, *l; NemoFile *file; list_view = NEMO_LIST_VIEW (view); tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view); g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view); gtk_tree_selection_unselect_all (tree_selection); for (node = selection; node != NULL; node = node->next) { file = node->data; iters = nemo_list_model_get_all_iters_for_file (list_view->details->model, file); for (l = iters; l != NULL; l = l->next) { gtk_tree_selection_select_iter (tree_selection, (GtkTreeIter *)l->data); } g_list_free_full (iters, g_free); } g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view); list_selection_changed_callback (tree_selection, view); } static void nemo_list_view_invert_selection (NemoView *view) { NemoListView *list_view; GtkTreeSelection *tree_selection; GList *node; GList *iters, *l; NemoFile *file; GList *selection = NULL; list_view = NEMO_LIST_VIEW (view); tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view); g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view); gtk_tree_selection_selected_foreach (tree_selection, nemo_list_view_get_selection_foreach_func, &selection); gtk_tree_selection_select_all (tree_selection); for (node = selection; node != NULL; node = node->next) { file = node->data; iters = nemo_list_model_get_all_iters_for_file (list_view->details->model, file); for (l = iters; l != NULL; l = l->next) { gtk_tree_selection_unselect_iter (tree_selection, (GtkTreeIter *)l->data); } g_list_free_full (iters, g_free); } g_list_free (selection); g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view); list_selection_changed_callback (tree_selection, view); } static void nemo_list_view_select_all (NemoView *view) { gtk_tree_selection_select_all (gtk_tree_view_get_selection (NEMO_LIST_VIEW (view)->details->tree_view)); } static void nemo_list_view_merge_menus (NemoView *view) { NemoListView *list_view; GtkUIManager *ui_manager; GtkActionGroup *action_group; list_view = NEMO_LIST_VIEW (view); NEMO_VIEW_CLASS (nemo_list_view_parent_class)->merge_menus (view); ui_manager = nemo_view_get_ui_manager (view); action_group = gtk_action_group_new ("ListViewActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); list_view->details->list_action_group = action_group; gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui manager */ list_view->details->list_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-list-view-ui.xml", NULL); list_view->details->menus_ready = TRUE; } static void nemo_list_view_unmerge_menus (NemoView *view) { NemoListView *list_view; GtkUIManager *ui_manager; list_view = NEMO_LIST_VIEW (view); NEMO_VIEW_CLASS (nemo_list_view_parent_class)->unmerge_menus (view); ui_manager = nemo_view_get_ui_manager (view); if (ui_manager != NULL) { nemo_ui_unmerge_ui (ui_manager, &list_view->details->list_merge_id, &list_view->details->list_action_group); } } static void nemo_list_view_update_menus (NemoView *view) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); /* don't update if the menus aren't ready */ if (!list_view->details->menus_ready) { return; } NEMO_VIEW_CLASS (nemo_list_view_parent_class)->update_menus (view); } /* Reset sort criteria and zoom level to match defaults */ static void nemo_list_view_reset_to_defaults (NemoView *view) { NemoFile *file; NemoDirectory *directory; file = nemo_view_get_directory_as_file (view); g_signal_handlers_block_by_func (NEMO_LIST_VIEW (view)->details->tree_view, columns_reordered_callback, NEMO_LIST_VIEW (view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { NemoWindow *window = nemo_view_get_nemo_window (NEMO_VIEW (view)); nemo_window_set_ignore_meta_sort_column (window, NULL); nemo_window_set_ignore_meta_sort_direction (window, SORT_NULL); nemo_window_set_ignore_meta_zoom_level (window, NEMO_ZOOM_LEVEL_NULL); nemo_window_set_ignore_meta_column_order (window, NULL); nemo_window_set_ignore_meta_visible_columns (window, NULL); } else { nemo_file_set_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_SORT_REVERSED, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL, NULL, NULL); nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL); nemo_file_set_metadata_list (file, NEMO_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL); } directory = nemo_view_get_model (view); if (NEMO_IS_SEARCH_DIRECTORY (directory)) g_settings_reset (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_SEARCH_VISIBLE_COLUMNS); char **default_columns, **default_order; default_columns = get_default_visible_columns (NEMO_LIST_VIEW (view)); default_order = get_default_column_order (NEMO_LIST_VIEW (view)); apply_columns_settings (NEMO_LIST_VIEW (view), default_order, default_columns); g_signal_handlers_unblock_by_func (NEMO_LIST_VIEW (view)->details->tree_view, columns_reordered_callback, NEMO_LIST_VIEW (view)); } static void nemo_list_view_scale_font_size (NemoListView *view, NemoZoomLevel new_level) { GList *l; static gboolean first_time = TRUE; static double pango_scale[7]; int medium; int i; g_return_if_fail (new_level >= NEMO_ZOOM_LEVEL_SMALLEST && new_level <= NEMO_ZOOM_LEVEL_LARGEST); if (first_time) { first_time = FALSE; medium = NEMO_ZOOM_LEVEL_SMALLER; pango_scale[medium] = PANGO_SCALE_MEDIUM; for (i = medium; i > NEMO_ZOOM_LEVEL_SMALLEST; i--) { pango_scale[i - 1] = (1 / 1.2) * pango_scale[i]; } for (i = medium; i < NEMO_ZOOM_LEVEL_LARGEST; i++) { pango_scale[i + 1] = 1.2 * pango_scale[i]; } } g_object_set (G_OBJECT (view->details->file_name_cell), "scale", pango_scale[new_level], NULL); for (l = view->details->cells; l != NULL; l = l->next) { g_object_set (G_OBJECT (l->data), "scale", pango_scale[new_level], NULL); } } static void nemo_list_view_set_zoom_level (NemoListView *view, NemoZoomLevel new_level, gboolean always_emit) { NemoFile *file; int icon_size; int column; g_return_if_fail (NEMO_IS_LIST_VIEW (view)); g_return_if_fail (new_level >= NEMO_ZOOM_LEVEL_SMALLEST && new_level <= NEMO_ZOOM_LEVEL_LARGEST); if (view->details->zoom_level == new_level) { if (always_emit) { g_signal_emit_by_name (NEMO_VIEW(view), "zoom_level_changed"); } return; } view->details->zoom_level = new_level; g_signal_emit_by_name (NEMO_VIEW(view), "zoom_level_changed"); file = nemo_view_get_directory_as_file (NEMO_VIEW (view)); if (nemo_global_preferences_get_ignore_view_metadata ()) { gchar *uri; uri = nemo_file_get_uri (file); if (!eel_uri_is_search (uri)) { nemo_window_set_ignore_meta_zoom_level (nemo_view_get_nemo_window (NEMO_VIEW (view)), new_level); } g_free (uri); } else { nemo_file_set_integer_metadata (file, NEMO_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL, get_default_zoom_level (), new_level); } /* Select correctly scaled icons. */ column = nemo_list_model_get_column_id_from_zoom_level (new_level); gtk_tree_view_column_set_attributes (view->details->file_name_column, GTK_CELL_RENDERER (view->details->pixbuf_cell), "surface", column, NULL); /* Scale text. */ nemo_list_view_scale_font_size (view, new_level); /* Make all rows the same size. */ icon_size = nemo_get_list_icon_size_for_zoom_level (new_level); gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (view->details->pixbuf_cell), -1, icon_size); nemo_view_update_menus (NEMO_VIEW (view)); /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=641518 */ gtk_tree_view_columns_autosize (view->details->tree_view); } static void nemo_list_view_bump_zoom_level (NemoView *view, int zoom_increment) { NemoListView *list_view; gint new_level; g_return_if_fail (NEMO_IS_LIST_VIEW (view)); list_view = NEMO_LIST_VIEW (view); new_level = list_view->details->zoom_level + zoom_increment; if (new_level >= NEMO_ZOOM_LEVEL_SMALLEST && new_level <= NEMO_ZOOM_LEVEL_LARGEST) { nemo_list_view_set_zoom_level (list_view, new_level, FALSE); } } static NemoZoomLevel nemo_list_view_get_zoom_level (NemoView *view) { NemoListView *list_view; g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), NEMO_ZOOM_LEVEL_STANDARD); list_view = NEMO_LIST_VIEW (view); return list_view->details->zoom_level; } static void nemo_list_view_zoom_to_level (NemoView *view, NemoZoomLevel zoom_level) { NemoListView *list_view; g_return_if_fail (NEMO_IS_LIST_VIEW (view)); list_view = NEMO_LIST_VIEW (view); nemo_list_view_set_zoom_level (list_view, zoom_level, FALSE); } static void nemo_list_view_restore_default_zoom_level (NemoView *view) { NemoListView *list_view; g_return_if_fail (NEMO_IS_LIST_VIEW (view)); list_view = NEMO_LIST_VIEW (view); nemo_list_view_set_zoom_level (list_view, get_default_zoom_level (), FALSE); } static NemoZoomLevel nemo_list_view_get_default_zoom_level (NemoView *view) { g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), NEMO_ZOOM_LEVEL_NULL); return get_default_zoom_level(); } static gboolean nemo_list_view_can_zoom_in (NemoView *view) { g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), FALSE); return NEMO_LIST_VIEW (view)->details->zoom_level < NEMO_ZOOM_LEVEL_LARGEST; } static gboolean nemo_list_view_can_zoom_out (NemoView *view) { g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), FALSE); return NEMO_LIST_VIEW (view)->details->zoom_level > NEMO_ZOOM_LEVEL_SMALLEST; } static void nemo_list_view_start_renaming_file (NemoView *view, NemoFile *file, gboolean select_all) { NemoListView *list_view; GtkTreeIter iter; GtkTreePath *path; list_view = NEMO_LIST_VIEW (view); /* Select all if we are in renaming mode already */ if (list_view->details->file_name_column && list_view->details->editable_widget) { gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget), 0, -1); return; } if (!nemo_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) { return; } /* call parent class to make sure the right icon is selected */ NEMO_VIEW_CLASS (nemo_list_view_parent_class)->start_renaming_file (view, file, select_all); /* Freeze updates to the view to prevent losing rename focus when the tree view updates */ nemo_view_freeze_updates (NEMO_VIEW (view)); path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter); /* Make filename-cells editable. */ g_object_set (G_OBJECT (list_view->details->file_name_cell), "editable", TRUE, NULL); gtk_tree_view_scroll_to_cell (list_view->details->tree_view, NULL, list_view->details->file_name_column, TRUE, 0.0, 0.0); gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view, path, list_view->details->file_name_column, GTK_CELL_RENDERER (list_view->details->file_name_cell), TRUE); /* set cursor also triggers editing-started, where we save the editable widget */ if (list_view->details->editable_widget != NULL) { int start_offset = 0; int end_offset = -1; if (!select_all) { eel_filename_get_rename_region (list_view->details->original_name, &start_offset, &end_offset); } gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget), start_offset, end_offset); } gtk_tree_path_free (path); } static void nemo_list_view_click_to_rename_mode_changed (NemoView *directory_view) { NemoListView *view; g_assert (NEMO_IS_LIST_VIEW (directory_view)); view = NEMO_LIST_VIEW (directory_view); view->details->click_to_rename = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CLICK_TO_RENAME); } static void nemo_list_view_click_policy_changed (NemoView *directory_view) { GdkWindow *win; GdkDisplay *display; NemoListView *view; GtkTreeIter iter; GtkTreeView *tree; view = NEMO_LIST_VIEW (directory_view); /* ensure that we unset the hand cursor and refresh underlined rows */ if (get_click_policy () == NEMO_CLICK_POLICY_DOUBLE) { if (view->details->hover_path != NULL) { if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model), &iter, view->details->hover_path)) { gtk_tree_model_row_changed (GTK_TREE_MODEL (view->details->model), view->details->hover_path, &iter); } gtk_tree_path_free (view->details->hover_path); view->details->hover_path = NULL; } tree = view->details->tree_view; if (gtk_widget_get_realized (GTK_WIDGET (tree))) { win = gtk_widget_get_window (GTK_WIDGET (tree)); gdk_window_set_cursor (win, NULL); display = gtk_widget_get_display (GTK_WIDGET (view)); if (display != NULL) { gdk_display_flush (display); } } g_clear_object (&hand_cursor); } else if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE) { if (hand_cursor == NULL) { hand_cursor = gdk_cursor_new(GDK_HAND2); } } } static void default_sort_order_changed_callback (gpointer callback_data) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (callback_data); set_sort_order_from_metadata_and_preferences (list_view); } static void default_zoom_level_changed_callback (gpointer callback_data) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (callback_data); set_zoom_level_from_metadata_and_preferences (list_view); } static void default_visible_columns_changed_callback (gpointer callback_data) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (callback_data); set_columns_settings_from_metadata_and_preferences (list_view); } static void default_column_order_changed_callback (gpointer callback_data) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (callback_data); set_columns_settings_from_metadata_and_preferences (list_view); } static void nemo_list_view_sort_directories_first_changed (NemoView *view) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); nemo_list_model_set_should_sort_directories_first (list_view->details->model, nemo_view_should_sort_directories_first (view)); } static int nemo_list_view_compare_files (NemoView *view, NemoFile *file1, NemoFile *file2) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); return nemo_list_model_compare_func (list_view->details->model, file1, file2); } static gboolean nemo_list_view_using_manual_layout (NemoView *view) { g_return_val_if_fail (NEMO_IS_LIST_VIEW (view), FALSE); return FALSE; } static void nemo_list_view_dispose (GObject *object) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (object); if (list_view->details->model) { stop_cell_editing (list_view); g_object_unref (list_view->details->model); list_view->details->model = NULL; } if (list_view->details->drag_dest) { g_object_unref (list_view->details->drag_dest); list_view->details->drag_dest = NULL; } if (list_view->details->renaming_file_activate_timeout != 0) { g_source_remove (list_view->details->renaming_file_activate_timeout); list_view->details->renaming_file_activate_timeout = 0; } if (list_view->details->clipboard_handler_id != 0) { g_signal_handler_disconnect (nemo_clipboard_monitor_get (), list_view->details->clipboard_handler_id); list_view->details->clipboard_handler_id = 0; } G_OBJECT_CLASS (nemo_list_view_parent_class)->dispose (object); } static void nemo_list_view_finalize (GObject *object) { NemoListView *list_view; list_view = NEMO_LIST_VIEW (object); g_free (list_view->details->original_name); list_view->details->original_name = NULL; if (list_view->details->double_click_path[0]) { gtk_tree_path_free (list_view->details->double_click_path[0]); } if (list_view->details->double_click_path[1]) { gtk_tree_path_free (list_view->details->double_click_path[1]); } if (list_view->details->new_selection_path) { gtk_tree_path_free (list_view->details->new_selection_path); } g_list_free (list_view->details->cells); g_hash_table_destroy (list_view->details->columns); if (list_view->details->hover_path != NULL) { gtk_tree_path_free (list_view->details->hover_path); } if (list_view->details->column_editor != NULL) { gtk_widget_destroy (list_view->details->column_editor); } g_free (list_view->details); g_signal_handlers_disconnect_by_func (nemo_preferences, default_sort_order_changed_callback, list_view); g_signal_handlers_disconnect_by_func (nemo_list_view_preferences, default_zoom_level_changed_callback, list_view); g_signal_handlers_disconnect_by_func (nemo_list_view_preferences, default_visible_columns_changed_callback, list_view); g_signal_handlers_disconnect_by_func (nemo_list_view_preferences, default_column_order_changed_callback, list_view); g_signal_handlers_disconnect_by_func (nemo_preferences, tooltip_prefs_changed_callback, list_view); G_OBJECT_CLASS (nemo_list_view_parent_class)->finalize (object); } static char * nemo_list_view_get_first_visible_file (NemoView *view) { NemoFile *file; GtkTreePath *path; GtkTreeIter iter; NemoListView *list_view; list_view = NEMO_LIST_VIEW (view); if (gtk_tree_view_get_path_at_pos (list_view->details->tree_view, 0, 0, &path, NULL, NULL, NULL)) { gtk_tree_model_get_iter (GTK_TREE_MODEL (list_view->details->model), &iter, path); gtk_tree_path_free (path); gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model), &iter, NEMO_LIST_MODEL_FILE_COLUMN, &file, -1); if (file) { char *uri; uri = nemo_file_get_uri (file); nemo_file_unref (file); return uri; } } return NULL; } static void nemo_list_view_scroll_to_file (NemoListView *view, NemoFile *file) { GtkTreePath *path; GtkTreeIter iter; if (!nemo_list_model_get_first_iter_for_file (view->details->model, file, &iter)) { return; } path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter); gtk_tree_view_scroll_to_cell (view->details->tree_view, path, NULL, TRUE, 0.0, 0.0); gtk_tree_path_free (path); } static void list_view_scroll_to_file (NemoView *view, const char *uri) { NemoFile *file; if (uri != NULL) { /* Only if existing, since we don't want to add the file to the directory if it has been removed since then */ file = nemo_file_get_existing_by_uri (uri); if (file != NULL) { nemo_list_view_scroll_to_file (NEMO_LIST_VIEW (view), file); nemo_file_unref (file); } } } static void list_view_notify_clipboard_info (NemoClipboardMonitor *monitor, NemoClipboardInfo *info, NemoListView *view) { /* this could be called as a result of _end_loading() being * called after _dispose(), where the model is cleared. */ if (view->details->model == NULL) { return; } if (info != NULL && info->cut) { nemo_list_model_set_highlight_for_files (view->details->model, info->files); } else { nemo_list_model_set_highlight_for_files (view->details->model, NULL); } } static void nemo_list_view_end_loading (NemoView *view, gboolean all_files_seen) { NemoClipboardMonitor *monitor; NemoClipboardInfo *info; nemo_list_view_update_selection (view); monitor = nemo_clipboard_monitor_get (); info = nemo_clipboard_monitor_get_clipboard_info (monitor); list_view_notify_clipboard_info (monitor, info, NEMO_LIST_VIEW (view)); } static const char * nemo_list_view_get_id (NemoView *view) { return NEMO_LIST_VIEW_ID; } static void nemo_list_view_class_init (NemoListViewClass *class) { NemoViewClass *nemo_view_class; nemo_view_class = NEMO_VIEW_CLASS (class); G_OBJECT_CLASS (class)->dispose = nemo_list_view_dispose; G_OBJECT_CLASS (class)->finalize = nemo_list_view_finalize; nemo_view_class->add_file = nemo_list_view_add_file; nemo_view_class->begin_loading = nemo_list_view_begin_loading; nemo_view_class->end_loading = nemo_list_view_end_loading; nemo_view_class->bump_zoom_level = nemo_list_view_bump_zoom_level; nemo_view_class->can_zoom_in = nemo_list_view_can_zoom_in; nemo_view_class->can_zoom_out = nemo_list_view_can_zoom_out; nemo_view_class->click_policy_changed = nemo_list_view_click_policy_changed; nemo_view_class->clear = nemo_list_view_clear; nemo_view_class->file_changed = nemo_list_view_file_changed; nemo_view_class->get_backing_uri = nemo_list_view_get_backing_uri; nemo_view_class->get_selection = nemo_list_view_get_selection; nemo_view_class->peek_selection = nemo_list_view_peek_selection; nemo_view_class->get_selection_count = nemo_list_view_get_selection_count; nemo_view_class->get_selection_for_file_transfer = nemo_list_view_get_selection_for_file_transfer; nemo_view_class->get_item_count = nemo_list_view_get_item_count; nemo_view_class->is_empty = nemo_list_view_is_empty; nemo_view_class->remove_file = nemo_list_view_remove_file; nemo_view_class->merge_menus = nemo_list_view_merge_menus; nemo_view_class->unmerge_menus = nemo_list_view_unmerge_menus; nemo_view_class->update_menus = nemo_list_view_update_menus; nemo_view_class->reset_to_defaults = nemo_list_view_reset_to_defaults; nemo_view_class->restore_default_zoom_level = nemo_list_view_restore_default_zoom_level; nemo_view_class->get_default_zoom_level = nemo_list_view_get_default_zoom_level; nemo_view_class->reveal_selection = nemo_list_view_reveal_selection; nemo_view_class->select_all = nemo_list_view_select_all; nemo_view_class->set_selection = nemo_list_view_set_selection; nemo_view_class->invert_selection = nemo_list_view_invert_selection; nemo_view_class->compare_files = nemo_list_view_compare_files; nemo_view_class->sort_directories_first_changed = nemo_list_view_sort_directories_first_changed; nemo_view_class->start_renaming_file = nemo_list_view_start_renaming_file; nemo_view_class->get_zoom_level = nemo_list_view_get_zoom_level; nemo_view_class->zoom_to_level = nemo_list_view_zoom_to_level; nemo_view_class->end_file_changes = nemo_list_view_end_file_changes; nemo_view_class->using_manual_layout = nemo_list_view_using_manual_layout; nemo_view_class->get_view_id = nemo_list_view_get_id; nemo_view_class->get_first_visible_file = nemo_list_view_get_first_visible_file; nemo_view_class->scroll_to_file = list_view_scroll_to_file; nemo_view_class->click_to_rename_mode_changed = nemo_list_view_click_to_rename_mode_changed; } static void nemo_list_view_init (NemoListView *list_view) { list_view->details = g_new0 (NemoListViewDetails, 1); create_and_set_up_tree_view (list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DEFAULT_SORT_ORDER, G_CALLBACK (default_sort_order_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER, G_CALLBACK (default_sort_order_changed_callback), list_view); g_signal_connect_swapped (nemo_list_view_preferences, "changed::" NEMO_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL, G_CALLBACK (default_zoom_level_changed_callback), list_view); g_signal_connect_swapped (nemo_list_view_preferences, "changed::" NEMO_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, G_CALLBACK (default_visible_columns_changed_callback), list_view); g_signal_connect_swapped (nemo_list_view_preferences, "changed::" NEMO_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER, G_CALLBACK (default_column_order_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIPS_LIST_VIEW, G_CALLBACK (tooltip_prefs_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_FILE_TYPE, G_CALLBACK (tooltip_prefs_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_MOD_DATE, G_CALLBACK (tooltip_prefs_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_ACCESS_DATE, G_CALLBACK (tooltip_prefs_changed_callback), list_view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_TOOLTIP_FULL_PATH, G_CALLBACK (tooltip_prefs_changed_callback), list_view); tooltip_prefs_changed_callback (list_view); nemo_list_view_click_policy_changed (NEMO_VIEW (list_view)); nemo_list_view_click_to_rename_mode_changed (NEMO_VIEW (list_view)); nemo_list_view_sort_directories_first_changed (NEMO_VIEW (list_view)); list_view->details->current_selection_count = -1; /* ensure that the zoom level is always set in begin_loading */ list_view->details->zoom_level = NEMO_ZOOM_LEVEL_SMALLEST - 1; list_view->details->hover_path = NULL; list_view->details->clipboard_handler_id = g_signal_connect (nemo_clipboard_monitor_get (), "clipboard_info", G_CALLBACK (list_view_notify_clipboard_info), list_view); } static NemoView * nemo_list_view_create (NemoWindowSlot *slot) { NemoListView *view; view = g_object_new (NEMO_TYPE_LIST_VIEW, "window-slot", slot, NULL); return NEMO_VIEW (view); } static gboolean nemo_list_view_supports_uri (const char *uri, GFileType file_type, const char *mime_type) { if (file_type == G_FILE_TYPE_DIRECTORY) { return TRUE; } if (strcmp (mime_type, NEMO_SAVED_SEARCH_MIMETYPE) == 0){ return TRUE; } if (g_str_has_prefix (uri, "trash:")) { return TRUE; } if (g_str_has_prefix (uri, "recent:")) { return TRUE; } if (g_str_has_prefix (uri, EEL_SEARCH_URI)) { return TRUE; } return FALSE; } static NemoViewInfo nemo_list_view = { (char *)NEMO_LIST_VIEW_ID, /* translators: this is used in the view selection dropdown * of navigation windows and in the preferences dialog */ (char *)N_("List View"), /* translators: this is used in the view menu */ (char *)N_("_List"), (char *)N_("The list view encountered an error."), (char *)N_("The list view encountered an error while starting up."), (char *)N_("Display this location with the list view."), nemo_list_view_create, nemo_list_view_supports_uri }; void nemo_list_view_register (void) { nemo_list_view.view_combo_label = _(nemo_list_view.view_combo_label); nemo_list_view.view_menu_label_with_mnemonic = _(nemo_list_view.view_menu_label_with_mnemonic); nemo_list_view.error_label = _(nemo_list_view.error_label); nemo_list_view.startup_error_label = _(nemo_list_view.startup_error_label); nemo_list_view.display_location_label = _(nemo_list_view.display_location_label); nemo_view_factory_register (&nemo_list_view); } GtkTreeView* nemo_list_view_get_tree_view (NemoListView *list_view) { return list_view->details->tree_view; } nemo-4.4.2/src/nemo-list-view.h000066400000000000000000000042661357442400300163100ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-list-view.h - interface for list view of directory. Copyright (C) 2000 Eazel, Inc. Copyright (C) 2001 Anders Carlsson The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: John Sullivan Anders Carlsson */ #ifndef NEMO_LIST_VIEW_H #define NEMO_LIST_VIEW_H #include "nemo-view.h" #define NEMO_TYPE_LIST_VIEW nemo_list_view_get_type() #define NEMO_LIST_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_LIST_VIEW, NemoListView)) #define NEMO_LIST_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_LIST_VIEW, NemoListViewClass)) #define NEMO_IS_LIST_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_LIST_VIEW)) #define NEMO_IS_LIST_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_LIST_VIEW)) #define NEMO_LIST_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_LIST_VIEW, NemoListViewClass)) #define NEMO_LIST_VIEW_ID "OAFIID:Nemo_File_Manager_List_View" typedef struct NemoListViewDetails NemoListViewDetails; typedef struct { NemoView parent_instance; NemoListViewDetails *details; } NemoListView; typedef struct { NemoViewClass parent_class; } NemoListViewClass; GType nemo_list_view_get_type (void); void nemo_list_view_register (void); GtkTreeView* nemo_list_view_get_tree_view (NemoListView *list_view); #endif /* NEMO_LIST_VIEW_H */ nemo-4.4.2/src/nemo-location-bar.c000066400000000000000000000324601357442400300167270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Maciej Stachowiak * Ettore Perazzoli * Michael Meeks * Andy Hertzfeld * */ /* nemo-location-bar.c - Location bar for Nemo */ #include #include "nemo-location-bar.h" #include "nemo-application.h" #include "nemo-location-entry.h" #include "nemo-window.h" #include #include #include #include #include #include #include #include #include #include #include #define NEMO_DND_URI_LIST_TYPE (char *)"text/uri-list" #define NEMO_DND_TEXT_PLAIN_TYPE (char *)"text/plain" struct NemoLocationBarDetails { NemoEntry *entry; char *last_location; guint idle_id; }; enum { NEMO_DND_URI_LIST, NEMO_DND_TEXT_PLAIN, NEMO_DND_NTARGETS }; enum { CANCEL, LOCATION_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static const GtkTargetEntry drag_types [] = { { NEMO_DND_URI_LIST_TYPE, 0, NEMO_DND_URI_LIST }, { NEMO_DND_TEXT_PLAIN_TYPE, 0, NEMO_DND_TEXT_PLAIN }, }; static const GtkTargetEntry drop_types [] = { { NEMO_DND_URI_LIST_TYPE, 0, NEMO_DND_URI_LIST }, { NEMO_DND_TEXT_PLAIN_TYPE, 0, NEMO_DND_TEXT_PLAIN }, }; G_DEFINE_TYPE (NemoLocationBar, nemo_location_bar, GTK_TYPE_BOX); static NemoWindow * nemo_location_bar_get_window (GtkWidget *bar) { return NEMO_WINDOW (gtk_widget_get_ancestor (bar, NEMO_TYPE_WINDOW)); } /** * nemo_location_bar_get_location * * Get the GFile represented by the text in the location bar. **/ static GFile * nemo_location_bar_get_location (NemoLocationBar *bar) { char *user_location; GFile *location; user_location = gtk_editable_get_chars (GTK_EDITABLE (bar->details->entry), 0, -1); location = g_file_parse_name (user_location); g_free (user_location); return location; } static void emit_location_changed (NemoLocationBar *bar) { GFile *location; location = nemo_location_bar_get_location (bar); g_signal_emit (bar, signals[LOCATION_CHANGED], 0, location); g_object_unref (location); } static void drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *data, guint info, guint32 time, gpointer callback_data) { char **names; NemoApplication *application; int name_count; NemoWindow *new_window, *window; GdkScreen *screen; gboolean new_windows_for_extras; char *prompt; char *detail; GFile *location; NemoLocationBar *self = NEMO_LOCATION_BAR (widget); g_assert (data != NULL); g_assert (callback_data == NULL); names = g_uri_list_extract_uris ((const gchar *) gtk_selection_data_get_data (data)); if (names == NULL || *names == NULL) { g_warning ("No D&D URI's"); g_strfreev (names); gtk_drag_finish (context, FALSE, FALSE, time); return; } window = nemo_location_bar_get_window (widget); new_windows_for_extras = FALSE; /* Ask user if they really want to open multiple windows * for multiple dropped URIs. This is likely to have been * a mistake. */ name_count = g_strv_length (names); if (name_count > 1) { prompt = g_strdup_printf (ngettext("Do you want to view %d location?", "Do you want to view %d locations?", name_count), name_count); detail = g_strdup_printf (ngettext("This will open %d separate window.", "This will open %d separate windows.", name_count), name_count); /* eel_run_simple_dialog should really take in pairs * like gtk_dialog_new_with_buttons() does. */ new_windows_for_extras = eel_run_simple_dialog (GTK_WIDGET (window), TRUE, GTK_MESSAGE_QUESTION, prompt, detail, GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL) != 0 /* GNOME_OK */; g_free (prompt); g_free (detail); if (!new_windows_for_extras) { g_strfreev (names); gtk_drag_finish (context, FALSE, FALSE, time); return; } } nemo_location_bar_set_location (self, names[0]); emit_location_changed (self); if (new_windows_for_extras) { int i; application = nemo_application_get_singleton (); screen = gtk_window_get_screen (GTK_WINDOW (window)); for (i = 1; names[i] != NULL; ++i) { new_window = nemo_application_create_window (application, screen); location = g_file_new_for_uri (names[i]); nemo_window_go_to (new_window, location); g_object_unref (location); } } g_strfreev (names); gtk_drag_finish (context, TRUE, FALSE, time); } static void drag_data_get_callback (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, gpointer callback_data) { NemoLocationBar *self; GFile *location; gchar *uri; g_assert (selection_data != NULL); self = callback_data; location = nemo_location_bar_get_location (self); uri = g_file_get_uri (location); switch (info) { case NEMO_DND_URI_LIST: case NEMO_DND_TEXT_PLAIN: gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) uri, strlen (uri)); break; default: g_assert_not_reached (); } g_free (uri); g_object_unref (location); } static gboolean button_pressed_callback (GtkWidget *widget, GdkEventButton *event) { NemoWindow *window; NemoWindowSlot *slot; NemoView *view; NemoLocationEntry *entry; if (event->button != 3) { return FALSE; } window = nemo_location_bar_get_window (gtk_widget_get_parent (widget)); slot = nemo_window_get_active_slot (window); view = slot->content_view; entry = NEMO_LOCATION_ENTRY (gtk_bin_get_child (GTK_BIN (widget))); if (view == NULL || nemo_location_entry_get_secondary_action (entry) == NEMO_LOCATION_ENTRY_ACTION_GOTO) { return FALSE; } nemo_view_pop_up_location_context_menu (view, event, NULL); return FALSE; } /** * nemo_location_bar_update_icon * * if the text in the entry matches the uri, set the label to "location", otherwise use "goto" * **/ static void nemo_location_bar_update_icon (NemoLocationBar *bar) { const char *current_text; GFile *location; GFile *last_location; if (bar->details->last_location == NULL){ nemo_location_entry_set_secondary_action (NEMO_LOCATION_ENTRY (bar->details->entry), NEMO_LOCATION_ENTRY_ACTION_GOTO); return; } current_text = gtk_entry_get_text (GTK_ENTRY (bar->details->entry)); location = g_file_parse_name (current_text); last_location = g_file_parse_name (bar->details->last_location); if (g_file_equal (last_location, location)) { nemo_location_entry_set_secondary_action (NEMO_LOCATION_ENTRY (bar->details->entry), NEMO_LOCATION_ENTRY_ACTION_CLEAR); } else { nemo_location_entry_set_secondary_action (NEMO_LOCATION_ENTRY (bar->details->entry), NEMO_LOCATION_ENTRY_ACTION_GOTO); } g_object_unref (location); g_object_unref (last_location); } static void editable_changed_callback (GtkEntry *entry, gpointer user_data) { nemo_location_bar_update_icon (NEMO_LOCATION_BAR (user_data)); } static void editable_activate_callback (GtkEntry *entry, gpointer user_data) { nemo_location_bar_update_icon (NEMO_LOCATION_BAR (user_data)); NemoLocationBar *self = user_data; const char *entry_text; entry_text = gtk_entry_get_text (entry); if (entry_text != NULL && *entry_text != '\0') { emit_location_changed (self); } } void nemo_location_bar_activate (NemoLocationBar *bar) { /* Put the keyboard focus in the text field when switching to this mode, * and select all text for easy overtyping */ gtk_widget_grab_focus (GTK_WIDGET (bar->details->entry)); nemo_entry_select_all (bar->details->entry); } static void nemo_location_bar_cancel (NemoLocationBar *bar) { char *last_location; last_location = bar->details->last_location; nemo_location_bar_set_location (bar, last_location); } static void finalize (GObject *object) { NemoLocationBar *bar; bar = NEMO_LOCATION_BAR (object); /* cancel the pending idle call, if any */ if (bar->details->idle_id != 0) { g_source_remove (bar->details->idle_id); bar->details->idle_id = 0; } g_free (bar->details->last_location); bar->details->last_location = NULL; G_OBJECT_CLASS (nemo_location_bar_parent_class)->finalize (object); } static void nemo_location_bar_class_init (NemoLocationBarClass *klass) { GObjectClass *gobject_class; GtkBindingSet *binding_set; gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = finalize; klass->cancel = nemo_location_bar_cancel; signals[CANCEL] = g_signal_new ("cancel", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoLocationBarClass, cancel), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[LOCATION_CHANGED] = g_signal_new ("location-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_OBJECT); binding_set = gtk_binding_set_by_class (klass); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "cancel", 0); g_type_class_add_private (klass, sizeof (NemoLocationBarDetails)); } static void nemo_location_bar_init (NemoLocationBar *bar) { GtkWidget *entry; GtkWidget *event_box; bar->details = G_TYPE_INSTANCE_GET_PRIVATE (bar, NEMO_TYPE_LOCATION_BAR, NemoLocationBarDetails); gtk_orientable_set_orientation (GTK_ORIENTABLE (bar), GTK_ORIENTATION_HORIZONTAL); event_box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); gtk_container_set_border_width (GTK_CONTAINER (event_box), 2); entry = nemo_location_entry_new (); g_signal_connect_object (entry, "activate", G_CALLBACK (editable_activate_callback), bar, G_CONNECT_AFTER); g_signal_connect_object (entry, "changed", G_CALLBACK (editable_changed_callback), bar, 0); gtk_container_add (GTK_CONTAINER (event_box), entry); gtk_box_pack_start (GTK_BOX (bar), event_box, TRUE, TRUE, 4); /* Label context menu */ g_signal_connect (event_box, "button-press-event", G_CALLBACK (button_pressed_callback), NULL); /* Drag source */ gtk_drag_source_set (GTK_WIDGET (event_box), GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_COPY | GDK_ACTION_LINK); g_signal_connect_object (event_box, "drag_data_get", G_CALLBACK (drag_data_get_callback), bar, 0); /* Drag dest. */ gtk_drag_dest_set (GTK_WIDGET (bar), GTK_DEST_DEFAULT_ALL, drop_types, G_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); g_signal_connect (bar, "drag_data_received", G_CALLBACK (drag_data_received_callback), NULL); bar->details->entry = NEMO_ENTRY (entry); gtk_widget_show_all (GTK_WIDGET (bar)); } GtkWidget * nemo_location_bar_new (void) { GtkWidget *bar; bar = gtk_widget_new (NEMO_TYPE_LOCATION_BAR, NULL); return bar; } void nemo_location_bar_set_location (NemoLocationBar *bar, const char *location) { char *formatted_location; GFile *file; g_assert (location != NULL); /* Note: This is called in reaction to external changes, and * thus should not emit the LOCATION_CHANGED signal. */ if (eel_uri_is_search (location)) { nemo_location_entry_set_special_text (NEMO_LOCATION_ENTRY (bar->details->entry), ""); } else { file = g_file_new_for_uri (location); formatted_location = g_file_get_parse_name (file); g_object_unref (file); nemo_location_entry_update_current_location (NEMO_LOCATION_ENTRY (bar->details->entry), formatted_location); g_free (formatted_location); } /* remember the original location for later comparison */ if (bar->details->last_location != location) { g_free (bar->details->last_location); bar->details->last_location = g_strdup (location); } nemo_location_bar_update_icon (bar); } NemoEntry * nemo_location_bar_get_entry (NemoLocationBar *location_bar) { return location_bar->details->entry; } gboolean nemo_location_bar_has_focus (NemoLocationBar *location_bar) { return gtk_widget_has_focus (GTK_WIDGET (location_bar->details->entry)); } nemo-4.4.2/src/nemo-location-bar.h000066400000000000000000000047241357442400300167360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Maciej Stachowiak * Ettore Perazzoli */ /* nemo-location-bar.h - Location bar for Nemo */ #ifndef NEMO_LOCATION_BAR_H #define NEMO_LOCATION_BAR_H #include #include #define NEMO_TYPE_LOCATION_BAR nemo_location_bar_get_type() #define NEMO_LOCATION_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_LOCATION_BAR, NemoLocationBar)) #define NEMO_LOCATION_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_LOCATION_BAR, NemoLocationBarClass)) #define NEMO_IS_LOCATION_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_LOCATION_BAR)) #define NEMO_IS_LOCATION_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_LOCATION_BAR)) #define NEMO_LOCATION_BAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_LOCATION_BAR, NemoLocationBarClass)) typedef struct NemoLocationBarDetails NemoLocationBarDetails; typedef struct NemoLocationBar { GtkBox parent; NemoLocationBarDetails *details; } NemoLocationBar; typedef struct { GtkBoxClass parent_class; /* for GtkBindingSet */ void (* cancel) (NemoLocationBar *bar); } NemoLocationBarClass; GType nemo_location_bar_get_type (void); GtkWidget* nemo_location_bar_new (void); NemoEntry * nemo_location_bar_get_entry (NemoLocationBar *location_bar); void nemo_location_bar_activate (NemoLocationBar *bar); void nemo_location_bar_set_location (NemoLocationBar *bar, const char *location); gboolean nemo_location_bar_has_focus (NemoLocationBar *location_bar); #endif /* NEMO_LOCATION_BAR_H */ nemo-4.4.2/src/nemo-location-entry.c000066400000000000000000000305201357442400300173170ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Maciej Stachowiak * Ettore Perazzoli * Michael Meeks * Andy Hertzfeld * */ /* nemo-location-bar.c - Location bar for Nemo */ #include #include "nemo-location-entry.h" #include "nemo-window-private.h" #include "nemo-window.h" #include #include #include #include #include #include #include #include #include #include struct NemoLocationEntryDetails { GtkLabel *label; char *current_directory; GFilenameCompleter *completer; guint idle_id; gboolean has_special_text; gboolean setting_special_text; gchar *special_text; NemoLocationEntryAction secondary_action; }; G_DEFINE_TYPE (NemoLocationEntry, nemo_location_entry, NEMO_TYPE_ENTRY); /* routine that performs the tab expansion. Extract the directory name and incomplete basename, then iterate through the directory trying to complete it. If we find something, add it to the entry */ static gboolean try_to_expand_path (gpointer callback_data) { NemoLocationEntry *entry; GtkEditable *editable; char *suffix, *user_location, *absolute_location, *uri_scheme; int user_location_length, pos; entry = NEMO_LOCATION_ENTRY (callback_data); editable = GTK_EDITABLE (entry); user_location = gtk_editable_get_chars (editable, 0, -1); user_location_length = g_utf8_strlen (user_location, -1); entry->details->idle_id = 0; uri_scheme = g_uri_parse_scheme (user_location); if (!g_path_is_absolute (user_location) && uri_scheme == NULL && user_location[0] != '~') { absolute_location = g_build_filename (entry->details->current_directory, user_location, NULL); suffix = g_filename_completer_get_completion_suffix (entry->details->completer, absolute_location); g_free (absolute_location); } else { suffix = g_filename_completer_get_completion_suffix (entry->details->completer, user_location); } g_free (user_location); g_free (uri_scheme); /* if we've got something, add it to the entry */ if (suffix != NULL) { pos = user_location_length; gtk_editable_insert_text (editable, suffix, -1, &pos); pos = user_location_length; gtk_editable_select_region (editable, pos, -1); g_free (suffix); } return FALSE; } /* Until we have a more elegant solution, this is how we figure out if * the GtkEntry inserted characters, assuming that the return value is * TRUE indicating that the GtkEntry consumed the key event for some * reason. This is a clone of code from GtkEntry. */ static gboolean entry_would_have_inserted_characters (const GdkEventKey *event) { switch (event->keyval) { case GDK_KEY_BackSpace: case GDK_KEY_Clear: case GDK_KEY_Insert: case GDK_KEY_Delete: case GDK_KEY_Home: case GDK_KEY_End: case GDK_KEY_KP_Home: case GDK_KEY_KP_End: case GDK_KEY_Left: case GDK_KEY_Right: case GDK_KEY_KP_Left: case GDK_KEY_KP_Right: case GDK_KEY_Return: return FALSE; default: if (event->keyval >= 0x20 && event->keyval <= 0xFF) { if ((event->state & GDK_CONTROL_MASK) != 0) { return FALSE; } if ((event->state & GDK_MOD1_MASK) != 0) { return FALSE; } } return event->length > 0; } } static int get_editable_number_of_chars (GtkEditable *editable) { char *text; int length; text = gtk_editable_get_chars (editable, 0, -1); length = g_utf8_strlen (text, -1); g_free (text); return length; } static void set_position_and_selection_to_end (GtkEditable *editable) { int end; end = get_editable_number_of_chars (editable); gtk_editable_select_region (editable, end, end); gtk_editable_set_position (editable, end); } static gboolean position_and_selection_are_at_end (GtkEditable *editable) { int end; int start_sel, end_sel; end = get_editable_number_of_chars (editable); if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel)) { if (start_sel != end || end_sel != end) { return FALSE; } } return gtk_editable_get_position (editable) == end; } static void got_completion_data_callback (GFilenameCompleter *completer, NemoLocationEntry *entry) { if (entry->details->idle_id) { g_source_remove (entry->details->idle_id); entry->details->idle_id = 0; } try_to_expand_path (entry); } static void editable_event_after_callback (GtkEntry *entry, GdkEvent *event, NemoLocationEntry *location_entry) { GtkEditable *editable; GdkEventKey *keyevent; if (event->type != GDK_KEY_PRESS) { return; } editable = GTK_EDITABLE (entry); keyevent = (GdkEventKey *)event; /* After typing the right arrow key we move the selection to * the end, if we have a valid selection - since this is most * likely an auto-completion. We ignore shift / control since * they can validly be used to extend the selection. */ if ((keyevent->keyval == GDK_KEY_Right || keyevent->keyval == GDK_KEY_End) && !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) && gtk_editable_get_selection_bounds (editable, NULL, NULL)) { set_position_and_selection_to_end (editable); } /* Only do expanding when we are typing at the end of the * text. Do the expand at idle time to avoid slowing down * typing when the directory is large. Only trigger the expand * when we type a key that would have inserted characters. */ if (position_and_selection_are_at_end (editable)) { if (entry_would_have_inserted_characters (keyevent)) { if (location_entry->details->idle_id == 0) { location_entry->details->idle_id = g_idle_add (try_to_expand_path, location_entry); } } } else { /* FIXME: Also might be good to do this when you click * to change the position or selection. */ if (location_entry->details->idle_id != 0) { g_source_remove (location_entry->details->idle_id); location_entry->details->idle_id = 0; } } } static void finalize (GObject *object) { NemoLocationEntry *entry; entry = NEMO_LOCATION_ENTRY (object); g_object_unref (entry->details->completer); g_free (entry->details->special_text); G_OBJECT_CLASS (nemo_location_entry_parent_class)->finalize (object); } static void destroy (GtkWidget *object) { NemoLocationEntry *entry; entry = NEMO_LOCATION_ENTRY (object); /* cancel the pending idle call, if any */ if (entry->details->idle_id != 0) { g_source_remove (entry->details->idle_id); entry->details->idle_id = 0; } g_free (entry->details->current_directory); entry->details->current_directory = NULL; GTK_WIDGET_CLASS (nemo_location_entry_parent_class)->destroy (object); } static void nemo_location_entry_text_changed (NemoLocationEntry *entry, GParamSpec *pspec) { if (entry->details->setting_special_text) { return; } entry->details->has_special_text = FALSE; } static void nemo_location_entry_icon_release (GtkEntry *gentry, GtkEntryIconPosition position, GdkEvent *event, gpointer unused) { switch (NEMO_LOCATION_ENTRY (gentry)->details->secondary_action) { case NEMO_LOCATION_ENTRY_ACTION_GOTO: g_signal_emit_by_name (gentry, "activate", gentry); break; case NEMO_LOCATION_ENTRY_ACTION_CLEAR: gtk_entry_set_text (gentry, ""); break; default: g_assert_not_reached (); } } static gboolean nemo_location_entry_focus_in (GtkWidget *widget, GdkEventFocus *event) { NemoLocationEntry *entry = NEMO_LOCATION_ENTRY (widget); if (entry->details->has_special_text) { entry->details->setting_special_text = TRUE; gtk_entry_set_text (GTK_ENTRY (entry), ""); entry->details->setting_special_text = FALSE; } return GTK_WIDGET_CLASS (nemo_location_entry_parent_class)->focus_in_event (widget, event); } static void nemo_location_entry_activate (GtkEntry *entry) { NemoLocationEntry *loc_entry; const gchar *entry_text; gchar *full_path, *uri_scheme = NULL; loc_entry = NEMO_LOCATION_ENTRY (entry); entry_text = gtk_entry_get_text (entry); if (entry_text != NULL && *entry_text != '\0') { uri_scheme = g_uri_parse_scheme (entry_text); if (!g_path_is_absolute (entry_text) && uri_scheme == NULL && entry_text[0] != '~') { /* Fix non absolute paths */ full_path = g_build_filename (loc_entry->details->current_directory, entry_text, NULL); gtk_entry_set_text (entry, full_path); g_free (full_path); } g_free (uri_scheme); } GTK_ENTRY_CLASS (nemo_location_entry_parent_class)->activate (entry); } static void nemo_location_entry_class_init (NemoLocationEntryClass *class) { GtkWidgetClass *widget_class; GObjectClass *gobject_class; GtkEntryClass *entry_class; widget_class = GTK_WIDGET_CLASS (class); widget_class->focus_in_event = nemo_location_entry_focus_in; widget_class->destroy = destroy; gobject_class = G_OBJECT_CLASS (class); gobject_class->finalize = finalize; entry_class = GTK_ENTRY_CLASS (class); entry_class->activate = nemo_location_entry_activate; g_type_class_add_private (class, sizeof (NemoLocationEntryDetails)); } void nemo_location_entry_update_current_location (NemoLocationEntry *entry, const char *location) { g_free (entry->details->current_directory); entry->details->current_directory = g_strdup (location); nemo_entry_set_text (NEMO_ENTRY (entry), location); set_position_and_selection_to_end (GTK_EDITABLE (entry)); } void nemo_location_entry_set_secondary_action (NemoLocationEntry *entry, NemoLocationEntryAction secondary_action) { if (entry->details->secondary_action == secondary_action) { return; } switch (secondary_action) { case NEMO_LOCATION_ENTRY_ACTION_CLEAR: gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, "edit-clear-symbolic"); break; case NEMO_LOCATION_ENTRY_ACTION_GOTO: gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, "go-next-symbolic"); break; default: g_assert_not_reached (); } entry->details->secondary_action = secondary_action; } NemoLocationEntryAction nemo_location_entry_get_secondary_action (NemoLocationEntry *entry) { return entry->details->secondary_action; } static void nemo_location_entry_init (NemoLocationEntry *entry) { entry->details = G_TYPE_INSTANCE_GET_PRIVATE (entry, NEMO_TYPE_LOCATION_ENTRY, NemoLocationEntryDetails); entry->details->completer = g_filename_completer_new (); g_filename_completer_set_dirs_only (entry->details->completer, TRUE); nemo_location_entry_set_secondary_action (entry, NEMO_LOCATION_ENTRY_ACTION_CLEAR); nemo_entry_set_special_tab_handling (NEMO_ENTRY (entry), TRUE); g_signal_connect (entry, "event_after", G_CALLBACK (editable_event_after_callback), entry); g_signal_connect (entry, "notify::text", G_CALLBACK (nemo_location_entry_text_changed), NULL); g_signal_connect (entry, "icon-release", G_CALLBACK (nemo_location_entry_icon_release), NULL); g_signal_connect (entry->details->completer, "got_completion_data", G_CALLBACK (got_completion_data_callback), entry); } GtkWidget * nemo_location_entry_new (void) { GtkWidget *entry; entry = gtk_widget_new (NEMO_TYPE_LOCATION_ENTRY, NULL); return entry; } void nemo_location_entry_set_special_text (NemoLocationEntry *entry, const char *special_text) { entry->details->has_special_text = TRUE; g_free (entry->details->special_text); entry->details->special_text = g_strdup (special_text); entry->details->setting_special_text = TRUE; gtk_entry_set_text (GTK_ENTRY (entry), special_text); entry->details->setting_special_text = FALSE; } nemo-4.4.2/src/nemo-location-entry.h000066400000000000000000000051721357442400300173310ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Maciej Stachowiak * Ettore Perazzoli */ #ifndef NEMO_LOCATION_ENTRY_H #define NEMO_LOCATION_ENTRY_H #include #define NEMO_TYPE_LOCATION_ENTRY nemo_location_entry_get_type() #define NEMO_LOCATION_ENTRY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_LOCATION_ENTRY, NemoLocationEntry)) #define NEMO_LOCATION_ENTRY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_LOCATION_ENTRY, NemoLocationEntryClass)) #define NEMO_IS_LOCATION_ENTRY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_LOCATION_ENTRY)) #define NEMO_IS_LOCATION_ENTRY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_LOCATION_ENTRY)) #define NEMO_LOCATION_ENTRY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_LOCATION_ENTRY, NemoLocationEntryClass)) typedef struct NemoLocationEntryDetails NemoLocationEntryDetails; typedef struct NemoLocationEntry { NemoEntry parent; NemoLocationEntryDetails *details; } NemoLocationEntry; typedef struct { NemoEntryClass parent_class; } NemoLocationEntryClass; typedef enum { NEMO_LOCATION_ENTRY_ACTION_GOTO, NEMO_LOCATION_ENTRY_ACTION_CLEAR } NemoLocationEntryAction; GType nemo_location_entry_get_type (void); GtkWidget* nemo_location_entry_new (void); void nemo_location_entry_set_special_text (NemoLocationEntry *entry, const char *special_text); void nemo_location_entry_set_secondary_action (NemoLocationEntry *entry, NemoLocationEntryAction secondary_action); NemoLocationEntryAction nemo_location_entry_get_secondary_action (NemoLocationEntry *entry); void nemo_location_entry_update_current_location (NemoLocationEntry *entry, const char *path); #endif /* NEMO_LOCATION_ENTRY_H */ nemo-4.4.2/src/nemo-main-application.c000066400000000000000000000671241357442400300176070ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-main-application: Nemo application subclass for standard windows * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2010, Cosimo Cecchi * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * */ #include #include "nemo-main-application.h" #if ENABLE_EMPTY_VIEW #include "nemo-empty-view.h" #endif /* ENABLE_EMPTY_VIEW */ #include "nemo-freedesktop-dbus.h" #include "nemo-icon-view.h" #include "nemo-image-properties-page.h" #include "nemo-list-view.h" #include "nemo-previewer.h" #include "nemo-progress-ui-handler.h" #include "nemo-self-check-functions.h" #include "nemo-window.h" #include "nemo-window-bookmarks.h" #include "nemo-window-manage-views.h" #include "nemo-window-private.h" #include "nemo-window-slot.h" #include "nemo-statusbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_APPLICATION #include #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include /* Keep window from shrinking down ridiculously small; numbers are somewhat arbitrary */ #define APPLICATION_WINDOW_MIN_WIDTH 300 #define APPLICATION_WINDOW_MIN_HEIGHT 100 #define START_STATE_CONFIG "start-state" #define NEMO_ACCEL_MAP_SAVE_DELAY 30 static void mount_removed_callback (GVolumeMonitor *monitor, GMount *mount, NemoMainApplication *application); static void mount_added_callback (GVolumeMonitor *monitor, GMount *mount, NemoMainApplication *application); G_DEFINE_TYPE (NemoMainApplication, nemo_main_application, NEMO_TYPE_APPLICATION); struct _NemoMainApplicationPriv { GVolumeMonitor *volume_monitor; NemoDBusManager *dbus_manager; NemoFreedesktopDBus *fdb_manager; gchar *geometry; NotifyNotification *unmount_notify; }; static void nemo_main_application_notify_unmount_done (NemoApplication *application, const gchar *message) { NemoMainApplication *app = NEMO_MAIN_APPLICATION (application); if (app->priv->unmount_notify) { notify_notification_close (app->priv->unmount_notify, NULL); g_clear_object (&app->priv->unmount_notify); } if (message != NULL) { NotifyNotification *unplug; gchar **strings; strings = g_strsplit (message, "\n", 0); unplug = notify_notification_new (strings[0], strings[1], "media-removable"); notify_notification_show (unplug, NULL); g_object_unref (unplug); g_strfreev (strings); } } static void nemo_main_application_notify_unmount_show (NemoApplication *application, const gchar *message) { NemoMainApplication *app = NEMO_MAIN_APPLICATION (application); gchar **strings; strings = g_strsplit (message, "\n", 0); if (!app->priv->unmount_notify) { app->priv->unmount_notify = notify_notification_new (strings[0], strings[1], "media-removable"); notify_notification_set_hint (app->priv->unmount_notify, "transient", g_variant_new_boolean (TRUE)); notify_notification_set_urgency (app->priv->unmount_notify, NOTIFY_URGENCY_CRITICAL); } else { notify_notification_update (app->priv->unmount_notify, strings[0], strings[1], "media-removable"); } notify_notification_show (app->priv->unmount_notify, NULL); g_strfreev (strings); } static void nemo_main_application_close_all_windows (NemoApplication *self) { GList *list_copy; GList *l; list_copy = g_list_copy (gtk_application_get_windows (GTK_APPLICATION (self))); for (l = list_copy; l != NULL; l = l->next) { if (NEMO_IS_WINDOW (l->data)) { NemoWindow *window; window = NEMO_WINDOW (l->data); nemo_window_close (window); } } g_list_free (list_copy); } static NemoWindow * nemo_main_application_create_window (NemoApplication *application, GdkScreen *screen) { NemoWindow *window; char *geometry_string; gboolean maximized; g_return_val_if_fail (NEMO_IS_APPLICATION (application), NULL); window = nemo_window_new (GTK_APPLICATION (application), screen); maximized = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_MAXIMIZED); if (maximized) { gtk_window_maximize (GTK_WINDOW (window)); } else { gtk_window_unmaximize (GTK_WINDOW (window)); } geometry_string = g_settings_get_string (nemo_window_state, NEMO_WINDOW_STATE_GEOMETRY); if (NEMO_MAIN_APPLICATION (application)->priv->geometry == NULL && geometry_string != NULL && geometry_string[0] != 0) { /* Ignore saved window position if a window with the same * location is already showing. That way the two windows * wont appear at the exact same location on the screen. */ eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window), geometry_string, NEMO_WINDOW_MIN_WIDTH, NEMO_WINDOW_MIN_HEIGHT, TRUE); } g_free (geometry_string); nemo_undo_manager_attach (application->undo_manager, G_OBJECT (window)); DEBUG ("Creating a new navigation window"); return window; } static void mount_added_callback (GVolumeMonitor *monitor, GMount *mount, NemoMainApplication *application) { NemoDirectory *directory; GFile *root; gchar *uri; root = g_mount_get_root (mount); uri = g_file_get_uri (root); DEBUG ("Added mount at uri %s", uri); g_free (uri); directory = nemo_directory_get_existing (root); g_object_unref (root); if (directory != NULL) { nemo_directory_force_reload (directory); nemo_directory_unref (directory); } } /* Called whenever a mount is unmounted. Check and see if there are * any windows open displaying contents on the mount. If there are, * close them. It would also be cool to save open window and position * info. */ static void mount_removed_callback (GVolumeMonitor *monitor, GMount *mount, NemoMainApplication *application) { GList *window_list, *node, *close_list; NemoWindow *window; NemoWindowSlot *slot; NemoWindowSlot *force_no_close_slot; GFile *root, *computer; gchar *uri; guint n_slots; close_list = NULL; force_no_close_slot = NULL; n_slots = 0; /* Check and see if any of the open windows are displaying contents from the unmounted mount */ window_list = gtk_application_get_windows (GTK_APPLICATION (application)); root = g_mount_get_root (mount); uri = g_file_get_uri (root); DEBUG ("Removed mount at uri %s", uri); g_free (uri); /* Construct a list of windows to be closed. Do not add the non-closable windows to the list. */ for (node = window_list; node != NULL; node = node->next) { window = NEMO_WINDOW (node->data); if (window != NULL) { GList *l; GList *lp; for (lp = window->details->panes; lp != NULL; lp = lp->next) { NemoWindowPane *pane; pane = (NemoWindowPane*) lp->data; for (l = pane->slots; l != NULL; l = l->next) { slot = l->data; n_slots++; if (nemo_window_slot_should_close_with_mount (slot, mount)) { close_list = g_list_prepend (close_list, slot); } } /* for all slots */ } /* for all panes */ } } /* Handle the windows in the close list. */ for (node = close_list; node != NULL; node = node->next) { slot = node->data; if (slot != force_no_close_slot) { if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_CLOSE_DEVICE_VIEW_ON_EJECT)) nemo_window_pane_close_slot (slot->pane, slot); else nemo_window_slot_go_home (slot, FALSE); } else { computer = g_file_new_for_path (g_get_home_dir ()); nemo_window_slot_open_location (slot, computer, 0); g_object_unref(computer); } } g_list_free (close_list); } static void open_window (NemoMainApplication *application, GFile *location, GdkScreen *screen, const char *geometry) { NemoWindow *window; gchar *uri; gboolean have_geometry; uri = g_file_get_uri (location); DEBUG ("Opening new window at uri %s", uri); window = nemo_main_application_create_window (NEMO_APPLICATION (application), screen); nemo_window_go_to (window, location); have_geometry = geometry != NULL && strcmp(geometry, "") != 0; if (have_geometry && !gtk_widget_get_visible (GTK_WIDGET (window))) { /* never maximize windows opened from shell if a * custom geometry has been requested. */ gtk_window_unmaximize (GTK_WINDOW (window)); eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window), geometry, APPLICATION_WINDOW_MIN_WIDTH, APPLICATION_WINDOW_MIN_HEIGHT, FALSE); } g_free (uri); } static void open_tabs (NemoMainApplication *application, GFile **locations, guint n_files, GdkScreen *screen, const char *geometry) { NemoWindow *window; gchar *uri; gboolean have_geometry; window = nemo_main_application_create_window (NEMO_APPLICATION (application), screen); /* open all locations */ uri = g_file_get_uri (locations[0]); g_debug ("Opening new tab at uri %s\n", uri); nemo_window_go_to (window, locations[0]); g_free (uri); for (int i = 1; i < n_files; i++) { /* open tabs in reverse order because each * tab is opened before the previous one */ guint tab = n_files-i; uri = g_file_get_uri (locations[tab]); g_debug ("Opening new tab at uri %s\n", uri); nemo_window_go_to_tab (window, locations[tab]); g_free (uri); } have_geometry = geometry != NULL && strcmp(geometry, "") != 0; if (have_geometry && !gtk_widget_get_visible (GTK_WIDGET (window))) { /* never maximize windows opened from shell if a * custom geometry has been requested. */ gtk_window_unmaximize (GTK_WINDOW (window)); eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window), geometry, APPLICATION_WINDOW_MIN_WIDTH, APPLICATION_WINDOW_MIN_HEIGHT, FALSE); } } static void open_windows (NemoMainApplication *application, GFile **files, gint n_files, GdkScreen *screen, const char *geometry, gboolean open_in_tabs) { gint i; if (files == NULL || files[0] == NULL) { /* Open a window pointing at the default location. */ open_window (application, NULL, screen, geometry); } else { if (open_in_tabs) { /* Open one window with one tab at each requested location */ open_tabs (application, files, n_files, screen, geometry); } else { /* Open windows at each requested location. */ for (i = 0; i < n_files; i++) { open_window (application, files[i], screen, geometry); } } } } static void nemo_main_application_open_location (NemoApplication *application, GFile *location, GFile *selection, const char *startup_id, const gboolean open_in_tabs) { NemoWindow *window; GList *sel_list = NULL; window = nemo_main_application_create_window (application, gdk_screen_get_default ()); gtk_window_set_startup_id (GTK_WINDOW (window), startup_id); if (selection != NULL) { sel_list = g_list_prepend (sel_list, nemo_file_get (selection)); } if(open_in_tabs){ nemo_window_slot_open_location_full (nemo_window_get_active_slot (window), location, NEMO_WINDOW_OPEN_FLAG_NEW_TAB, sel_list, NULL, NULL); } else { nemo_window_slot_open_location_full (nemo_window_get_active_slot (window), location, 0, sel_list, NULL, NULL); } if (sel_list != NULL) { nemo_file_list_free (sel_list); } } static void nemo_main_application_open (GApplication *app, GFile **files, gint n_files, const gchar *options) { NemoMainApplication *self = NEMO_MAIN_APPLICATION (app); gboolean open_in_tabs = FALSE; gchar *geometry = NULL; const char splitter = '='; g_debug ("Open called on the GApplication instance; %d files", n_files); /* Check if local command line passed --geometry or --tabs */ if (strlen (options) > 0) { gchar** split_options = g_strsplit (options, &splitter, 2); if (strcmp (split_options[0], "NULL") != 0) { geometry = g_strdup (split_options[0]); } sscanf (split_options[1], "%d", &open_in_tabs); g_strfreev (split_options); } DEBUG ("Open called on the GApplication instance; %d files, open in tabs: %s, geometry: '%s'", n_files, open_in_tabs ? "yes" : "no", geometry ? geometry : "none"); open_windows (self, files, n_files, gdk_screen_get_default (), geometry, open_in_tabs); g_clear_pointer (&geometry, g_free); } static void nemo_main_application_init (NemoMainApplication *application) { application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application, NEMO_TYPE_MAIN_APPLICATION, NemoMainApplicationPriv); } static void nemo_main_application_finalize (GObject *object) { NemoMainApplication *application; application = NEMO_MAIN_APPLICATION (object); nemo_bookmarks_exiting (); g_clear_object (&application->priv->volume_monitor); g_free (application->priv->geometry); g_clear_object (&application->priv->dbus_manager); g_clear_object (&application->priv->fdb_manager); G_OBJECT_CLASS (nemo_main_application_parent_class)->finalize (object); } static gboolean do_cmdline_sanity_checks (NemoMainApplication *self, gboolean perform_self_check, gboolean version, gboolean kill_shell, gboolean open_in_tabs, gchar **remaining) { gboolean retval = FALSE; if (perform_self_check && (remaining != NULL || kill_shell)) { g_printerr ("%s\n", _("--check cannot be used with other options.")); goto out; } if (kill_shell && remaining != NULL) { g_printerr ("%s\n", _("--quit cannot be used with URIs.")); goto out; } if (self->priv->geometry != NULL && !open_in_tabs && remaining != NULL && remaining[0] != NULL && remaining[1] != NULL) { g_printerr ("%s\n", _("--geometry cannot be used with more than one URI.")); goto out; } retval = TRUE; out: return retval; } static void do_perform_self_checks (gint *exit_status) { #ifndef NEMO_OMIT_SELF_CHECK /* Run the checks (each twice) for nemo and libnemo-private. */ nemo_run_self_checks (); nemo_run_lib_self_checks (); eel_exit_if_self_checks_failed (); nemo_run_self_checks (); nemo_run_lib_self_checks (); eel_exit_if_self_checks_failed (); #endif *exit_status = EXIT_SUCCESS; } static gboolean nemo_main_application_local_command_line (GApplication *application, gchar ***arguments, gint *exit_status) { gboolean perform_self_check = FALSE; gboolean version = FALSE; gboolean browser = FALSE; gboolean open_in_tabs = FALSE; gboolean kill_shell = FALSE; gboolean no_default_window = FALSE; gboolean no_desktop_ignored = FALSE; gboolean fix_cache = FALSE; gboolean debug = FALSE; gchar **remaining = NULL; GApplicationFlags init_flags; NemoMainApplication *self = NEMO_MAIN_APPLICATION (application); const GOptionEntry options[] = { #ifndef NEMO_OMIT_SELF_CHECK { "check", 'c', 0, G_OPTION_ARG_NONE, &perform_self_check, N_("Perform a quick set of self-check tests."), NULL }, #endif /* dummy, only for compatibility reasons */ { "browser", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &browser, NULL, NULL }, { "version", '\0', 0, G_OPTION_ARG_NONE, &version, N_("Show the version of the program."), NULL }, { "geometry", 'g', 0, G_OPTION_ARG_STRING, &self->priv->geometry, N_("Create the initial window with the given geometry. " "Examples: nemo --geometry=+100+100, nemo --geometry=600x400, nemo --geometry=600x400+100+100."), N_("GEOMETRY") }, { "no-default-window", 'n', 0, G_OPTION_ARG_NONE, &no_default_window, N_("Only create windows for explicitly specified URIs."), NULL }, { "no-desktop", '\0', 0, G_OPTION_ARG_NONE, &no_desktop_ignored, N_("Ignored argument - left for compatibility only."), NULL }, { "tabs", 't', 0, G_OPTION_ARG_NONE, &open_in_tabs, N_("Open URIs in tabs."), NULL }, { "fix-cache", '\0', 0, G_OPTION_ARG_NONE, &fix_cache, N_("Repair the user thumbnail cache - this can be useful if you're having trouble with file thumbnails. Must be run as root"), NULL }, { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Enable debugging code. Example usage: 'NEMO_DEBUG=Actions,Window nemo --debug'. Use NEMO_DEBUG=all for more topics.", NULL }, { "quit", 'q', 0, G_OPTION_ARG_NONE, &kill_shell, N_("Quit Nemo."), NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, N_("[URI...]") }, { NULL } }; GOptionContext *context; GError *error = NULL; gint argc = 0; gchar **argv = NULL; *exit_status = EXIT_SUCCESS; context = g_option_context_new (_("\n\nBrowse the file system with the file manager")); g_option_context_add_main_entries (context, options, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); argv = *arguments; argc = g_strv_length (argv); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("Could not parse arguments: %s\n", error->message); g_error_free (error); *exit_status = EXIT_FAILURE; goto out; } if (version) { g_print ("nemo " VERSION "\n"); goto out; } if (debug) { g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); } if (!do_cmdline_sanity_checks (self, perform_self_check, version, kill_shell, open_in_tabs, remaining)) { *exit_status = EXIT_FAILURE; goto out; } if (perform_self_check) { do_perform_self_checks (exit_status); goto out; } if (fix_cache) { if (geteuid () != 0) { g_printerr ("The --fix-cache option must be run with sudo or as the root user.\n"); } else { gnome_desktop_thumbnail_cache_fix_permissions (); g_print ("User thumbnail cache successfully repaired.\n"); } goto out; } DEBUG ("Parsing local command line, no_default_window %d, quit %d, " "self checks %d", no_default_window, kill_shell, perform_self_check); /* Keep our original flags handy */ init_flags = g_application_get_flags (application); /* First try to register as a service (this allows our dbus activation to succeed * if we're not already running */ g_application_set_flags (application, init_flags | G_APPLICATION_IS_SERVICE); g_application_register (application, NULL, &error); if (error != NULL) { g_debug ("Could not register nemo as a service, trying as a remote: %s", error->message); g_clear_error (&error); } else { goto post_registration; } /* If service registration failed, try to connect to the existing instance */ g_application_set_flags (application, init_flags | G_APPLICATION_IS_LAUNCHER); g_application_register (application, NULL, &error); if (error != NULL) { g_printerr ("Could not register nemo as a remote: %s\n", error->message); g_clear_error (&error); *exit_status = EXIT_FAILURE; goto out; } post_registration: if (kill_shell) { DEBUG ("Killing application, as requested"); g_action_group_activate_action (G_ACTION_GROUP (application), "quit", NULL); goto out; } GFile **files; gint idx, len; len = 0; files = NULL; /* Convert args to GFiles */ if (remaining != NULL) { GFile *file; GPtrArray *file_array; file_array = g_ptr_array_new (); for (idx = 0; remaining[idx] != NULL; idx++) { file = g_file_new_for_commandline_arg (remaining[idx]); if (file != NULL) { g_ptr_array_add (file_array, file); } } len = file_array->len; files = (GFile **) g_ptr_array_free (file_array, FALSE); g_strfreev (remaining); } if (files == NULL && !no_default_window) { files = g_malloc0 (2 * sizeof (GFile *)); len = 1; files[0] = g_file_new_for_path (g_get_home_dir ()); files[1] = NULL; } /* Invoke "Open" to create new windows */ if (len > 0) { gchar* concatOptions = g_malloc0(64); if (self->priv->geometry == NULL) { g_snprintf (concatOptions, 64, "NULL=%d", open_in_tabs); } else { g_snprintf (concatOptions, 64, "%s=%d", self->priv->geometry, open_in_tabs); } g_application_open (application, files, len, concatOptions); g_free (concatOptions); } for (idx = 0; idx < len; idx++) { g_object_unref (files[idx]); } g_free (files); out: g_option_context_free (context); return TRUE; } static void menu_state_changed_callback (NemoMainApplication *self) { if (!g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR) && !g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DISABLE_MENU_WARNING)) { GtkWidget *dialog; GtkWidget *msg_area; GtkWidget *checkbox; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("Nemo's main menu is now hidden")); gchar *secondary; secondary = g_strdup_printf (_("You have chosen to hide the main menu. You can get it back temporarily by:\n\n" "- Tapping the key\n" "- Right-clicking an empty region of the main toolbar\n" "- Right-clicking an empty region of the status bar.\n\n" "You can restore it permanently by selecting this option again from the View menu.")); g_object_set (dialog, "secondary-text", secondary, NULL); g_free (secondary); msg_area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog)); checkbox = gtk_check_button_new_with_label (_("Don't show this message again.")); gtk_box_pack_start (GTK_BOX (msg_area), checkbox, TRUE, TRUE, 2); g_settings_bind (nemo_preferences, NEMO_PREFERENCES_DISABLE_MENU_WARNING, checkbox, "active", G_SETTINGS_BIND_DEFAULT); gtk_widget_show_all (dialog); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); } } static void nemo_main_application_continue_startup (NemoApplication *app) { NemoMainApplication *self = NEMO_MAIN_APPLICATION (app); /* create DBus manager */ self->priv->dbus_manager = nemo_dbus_manager_new (); self->priv->fdb_manager = nemo_freedesktop_dbus_new (); /* Check the user's ~/.config/nemo directory and post warnings * if there are problems. */ nemo_application_check_required_directory (app, nemo_get_user_directory ()); /* register views */ nemo_icon_view_register (); nemo_list_view_register (); nemo_icon_view_compact_register (); #if defined(ENABLE_EMPTY_VIEW) && ENABLE_EMPTY_VIEW nemo_empty_view_register (); #endif /* Watch for unmounts so we can close open windows */ /* TODO-gio: This should be using the UNMOUNTED feature of GFileMonitor instead */ self->priv->volume_monitor = g_volume_monitor_get (); g_signal_connect_object (self->priv->volume_monitor, "mount_removed", G_CALLBACK (mount_removed_callback), self, 0); g_signal_connect_object (self->priv->volume_monitor, "mount_added", G_CALLBACK (mount_added_callback), self, 0); g_signal_connect_swapped (nemo_window_state, "changed::" NEMO_WINDOW_STATE_START_WITH_MENU_BAR, G_CALLBACK (menu_state_changed_callback), self); } static void nemo_desktop_application_continue_quit (NemoApplication *app) { } static void nemo_main_application_quit_mainloop (GApplication *app) { nemo_main_application_notify_unmount_done (NEMO_APPLICATION (app), NULL); G_APPLICATION_CLASS (nemo_main_application_parent_class)->quit_mainloop (app); } static void nemo_main_application_class_init (NemoMainApplicationClass *class) { GObjectClass *object_class; GApplicationClass *application_class; NemoApplicationClass *nemo_app_class; object_class = G_OBJECT_CLASS (class); object_class->finalize = nemo_main_application_finalize; application_class = G_APPLICATION_CLASS (class); application_class->open = nemo_main_application_open; application_class->local_command_line = nemo_main_application_local_command_line; application_class->quit_mainloop = nemo_main_application_quit_mainloop; nemo_app_class = NEMO_APPLICATION_CLASS (class); nemo_app_class->open_location = nemo_main_application_open_location; nemo_app_class->create_window = nemo_main_application_create_window; nemo_app_class->notify_unmount_show = nemo_main_application_notify_unmount_show; nemo_app_class->notify_unmount_done = nemo_main_application_notify_unmount_done; nemo_app_class->close_all_windows = nemo_main_application_close_all_windows; nemo_app_class->continue_startup = nemo_main_application_continue_startup; nemo_app_class->continue_quit = nemo_desktop_application_continue_quit; g_type_class_add_private (class, sizeof (NemoMainApplicationPriv)); } NemoApplication * nemo_main_application_get_singleton (void) { return nemo_application_initialize_singleton (NEMO_TYPE_MAIN_APPLICATION, "application-id", "org.Nemo", "flags", G_APPLICATION_HANDLES_OPEN, "inactivity-timeout", 30 * 1000, // seconds "register-session", TRUE, NULL); } nemo-4.4.2/src/nemo-main-application.h000066400000000000000000000043301357442400300176020ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-application: main Nemo application class. * * Copyright (C) 2000 Red Hat, Inc. * Copyright (C) 2010 Cosimo Cecchi * * Nemo 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. * * Nemo 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __NEMO_MAIN_APPLICATION_H__ #define __NEMO_MAIN_APPLICATION_H__ #include #include #include #include #include "nemo-window.h" #include "nemo-application.h" #define NEMO_TYPE_MAIN_APPLICATION nemo_main_application_get_type() #define NEMO_MAIN_APPLICATION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_MAIN_APPLICATION, NemoMainApplication)) #define NEMO_MAIN_APPLICATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_MAIN_APPLICATION, NemoMainApplicationClass)) #define NEMO_IS_MAIN_APPLICATION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_MAIN_APPLICATION)) #define NEMO_IS_MAIN_APPLICATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_MAIN_APPLICATION)) #define NEMO_MAIN_APPLICATION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_MAIN_APPLICATION, NemoMainApplicationClass)) typedef struct _NemoMainApplicationPriv NemoMainApplicationPriv; typedef struct { NemoApplication parent; NemoMainApplicationPriv *priv; } NemoMainApplication; typedef struct { NemoApplicationClass parent_class; } NemoMainApplicationClass; GType nemo_main_application_get_type (void); NemoApplication *nemo_main_application_get_singleton (void); #endif /* __NEMO_MAIN_APPLICATION_H__ */ nemo-4.4.2/src/nemo-main.c000066400000000000000000000062111357442400300152740ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee , * Darin Adler , * John Sullivan * */ /* nemo-main.c: Implementation of the routines that drive program lifecycle and main window creation/destruction. */ #include #include "nemo-main-application.h" #include #include #include #include #include #include #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #include #include #include #ifdef HAVE_EXEMPI #include #endif int main (int argc, char *argv[]) { gint retval; NemoApplication *application; #if defined (HAVE_MALLOPT) && defined(M_MMAP_THRESHOLD) /* Nemo uses lots and lots of small and medium size allocations, * and then a few large ones for the desktop background. By default * glibc uses a dynamic treshold for how large allocations should * be mmaped. Unfortunately this triggers quickly for nemo when * it does the desktop background allocations, raising the limit * such that a lot of temporary large allocations end up on the * heap and are thus not returned to the OS. To fix this we set * a hardcoded limit. I don't know what a good value is, but 128K * was the old glibc static limit, lets use that. */ mallopt (M_MMAP_THRESHOLD, 128 *1024); #endif /* This will be done by gtk+ later, but for now, force it to GNOME */ g_desktop_app_info_set_desktop_env ("GNOME"); if (g_getenv ("NEMO_DEBUG") != NULL) { eel_make_warnings_and_criticals_stop_in_debugger (); } /* Initialize gettext support */ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); g_set_prgname ("nemo"); #ifdef HAVE_EXEMPI xmp_init(); #endif /* Run the nemo application. */ application = nemo_main_application_get_singleton (); /* hold indefinitely if we're asked to persist */ if (g_getenv ("NEMO_PERSIST") != NULL) { g_application_hold (G_APPLICATION (application)); } retval = g_application_run (G_APPLICATION (application), argc, argv); g_object_unref (application); eel_debug_shut_down (); return retval; } nemo-4.4.2/src/nemo-mime-actions.c000066400000000000000000001642261357442400300167500ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* nemo-mime-actions.c - uri-specific versions of mime action functions Copyright (C) 2000, 2001 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Maciej Stachowiak */ #include #include "nemo-mime-actions.h" #include "nemo-window-slot.h" #include "nemo-error-reporting.h" #include "nemo-desktop-window.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum { UNIX_PERM_USER_EXEC = S_IXUSR, UNIX_PERM_GROUP_EXEC = S_IXGRP, UNIX_PERM_OTHER_EXEC = S_IXOTH, }; #define DEBUG_FLAG NEMO_DEBUG_MIME #include typedef enum { ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE, ACTIVATION_ACTION_ASK, ACTIVATION_ACTION_LAUNCH, ACTIVATION_ACTION_LAUNCH_IN_TERMINAL, ACTIVATION_ACTION_OPEN_IN_VIEW, ACTIVATION_ACTION_OPEN_IN_APPLICATION, ACTIVATION_ACTION_DO_NOTHING, } ActivationAction; typedef struct { NemoFile *file; char *uri; } LaunchLocation; typedef struct { GAppInfo *application; GList *uris; } ApplicationLaunchParameters; typedef struct { NemoWindowSlot *slot; gpointer window; GtkWindow *parent_window; GCancellable *cancellable; GList *locations; GList *mountables; GList *start_mountables; GList *not_mounted; NemoWindowOpenFlags flags; char *timed_wait_prompt; gboolean timed_wait_active; NemoFileListHandle *files_handle; gboolean tried_mounting; char *activation_directory; gboolean user_confirmation; } ActivateParameters; /* Number of seconds until cancel dialog shows up */ #define DELAY_UNTIL_CANCEL_MSECS 5000 #define RESPONSE_RUN 1000 #define RESPONSE_DISPLAY 1001 #define RESPONSE_RUN_IN_TERMINAL 1002 #define RESPONSE_MARK_TRUSTED 1003 #define RESPONSE_OPEN_WITH 1004 #define SILENT_WINDOW_OPEN_LIMIT 5 #define SILENT_OPEN_LIMIT 5 /* This number controls a maximum character count for a URL that is * displayed as part of a dialog. It's fairly arbitrary -- big enough * to allow most "normal" URIs to display in full, but small enough to * prevent the dialog from getting insanely wide. */ #define MAX_URI_IN_DIALOG_LENGTH 60 static void cancel_activate_callback (gpointer callback_data); static void activate_activation_uris_ready_callback (GList *files, gpointer callback_data); static void activation_mount_mountables (ActivateParameters *parameters); static void activation_start_mountables (ActivateParameters *parameters); static void activate_callback (GList *files, gpointer callback_data); static void activation_mount_not_mounted (ActivateParameters *parameters); static void launch_location_free (LaunchLocation *location) { nemo_file_unref (location->file); g_free (location->uri); g_free (location); } static void launch_location_list_free (GList *list) { g_list_foreach (list, (GFunc)launch_location_free, NULL); g_list_free (list); } static GList * get_file_list_for_launch_locations (GList *locations) { GList *files, *l; LaunchLocation *location; files = NULL; for (l = locations; l != NULL; l = l->next) { location = l->data; files = g_list_prepend (files, nemo_file_ref (location->file)); } return g_list_reverse (files); } static LaunchLocation * launch_location_from_file (NemoFile *file) { LaunchLocation *location; location = g_new (LaunchLocation, 1); location->file = nemo_file_ref (file); location->uri = nemo_file_get_uri (file); return location; } static void launch_location_update_from_file (LaunchLocation *location, NemoFile *file) { nemo_file_unref (location->file); g_free (location->uri); location->file = nemo_file_ref (file); location->uri = nemo_file_get_uri (file); } static void launch_location_update_from_uri (LaunchLocation *location, const char *uri) { nemo_file_unref (location->file); g_free (location->uri); location->file = nemo_file_get_by_uri (uri); location->uri = g_strdup (uri); } static LaunchLocation * find_launch_location_for_file (GList *list, NemoFile *file) { LaunchLocation *location; GList *l; for (l = list; l != NULL; l = l->next) { location = l->data; if (location->file == file) { return location; } } return NULL; } static GList * launch_locations_from_file_list (GList *list) { GList *new; new = NULL; while (list) { new = g_list_prepend (new, launch_location_from_file (list->data)); list = list->next; } new = g_list_reverse (new); return new; } static ApplicationLaunchParameters * application_launch_parameters_new (GAppInfo *application, GList *uris) { ApplicationLaunchParameters *result; result = g_new0 (ApplicationLaunchParameters, 1); result->application = g_object_ref (application); result->uris = eel_g_str_list_copy (uris); return result; } static void application_launch_parameters_free (ApplicationLaunchParameters *parameters) { g_object_unref (parameters->application); g_list_free_full (parameters->uris, g_free); g_free (parameters); } static GList* filter_nemo_handler (GList *apps) { GList *l, *next; GAppInfo *application; const char *id; l = apps; while (l != NULL) { application = (GAppInfo *) l->data; next = l->next; id = g_app_info_get_id (application); if (id != NULL && strcmp (id, "nemo.desktop") == 0) { g_object_unref (application); apps = g_list_delete_link (apps, l); } l = next; } return apps; } static GList* filter_non_uri_apps (GList *apps) { GList *l, *next; GAppInfo *app; for (l = apps; l != NULL; l = next) { app = l->data; next = l->next; if (!g_app_info_supports_uris (app)) { apps = g_list_delete_link (apps, l); g_object_unref (app); } } return apps; } static gboolean nemo_mime_actions_check_if_required_attributes_ready (NemoFile *file) { NemoFileAttributes attributes; gboolean ready; attributes = nemo_mime_actions_get_required_file_attributes (); ready = nemo_file_check_if_ready (file, attributes); return ready; } NemoFileAttributes nemo_mime_actions_get_required_file_attributes (void) { return NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; } static gboolean file_has_local_path (NemoFile *file) { GFile *location; char *path; gboolean res; /* Don't only check _is_native, because we want to support using the fuse path */ location = nemo_file_get_activation_location (file); if (g_file_is_native (location)) { res = TRUE; } else { path = g_file_get_path (location); res = path != NULL; g_free (path); } g_object_unref (location); return res; } GAppInfo * nemo_mime_get_default_application_for_file (NemoFile *file) { GAppInfo *app; char *mime_type; char *uri_scheme; if (!nemo_mime_actions_check_if_required_attributes_ready (file)) { if (file_has_local_path (file)) { return NULL; } } mime_type = nemo_file_get_mime_type (file); app = g_app_info_get_default_for_type (mime_type, !file_has_local_path (file)); g_free (mime_type); if (app == NULL) { uri_scheme = nemo_file_get_uri_scheme (file); if (uri_scheme != NULL) { app = g_app_info_get_default_for_uri_scheme (uri_scheme); g_free (uri_scheme); } } return app; } static int file_compare_by_mime_type (NemoFile *file_a, NemoFile *file_b) { char *mime_type_a, *mime_type_b; int ret; mime_type_a = nemo_file_get_mime_type (file_a); mime_type_b = nemo_file_get_mime_type (file_b); ret = strcmp (mime_type_a, mime_type_b); g_free (mime_type_a); g_free (mime_type_b); return ret; } static int file_compare_by_parent_uri (NemoFile *file_a, NemoFile *file_b) { char *parent_uri_a, *parent_uri_b; int ret; parent_uri_a = nemo_file_get_parent_uri (file_a); parent_uri_b = nemo_file_get_parent_uri (file_b); ret = strcmp (parent_uri_a, parent_uri_b); g_free (parent_uri_a); g_free (parent_uri_b); return ret; } static int application_compare_by_name (const GAppInfo *app_a, const GAppInfo *app_b) { return g_utf8_collate (g_app_info_get_name ((GAppInfo *)app_a), g_app_info_get_name ((GAppInfo *)app_b)); } static int application_compare_by_id (const GAppInfo *app_a, const GAppInfo *app_b) { const char *id_a, *id_b; id_a = g_app_info_get_id ((GAppInfo *)app_a); id_b = g_app_info_get_id ((GAppInfo *)app_b); if (id_a == NULL && id_b == NULL) { if (g_app_info_equal ((GAppInfo *)app_a, (GAppInfo *)app_b)) { return 0; } if ((gsize)app_a < (gsize) app_b) { return -1; } return 1; } if (id_a == NULL) { return -1; } if (id_b == NULL) { return 1; } return strcmp (id_a, id_b); } GList * nemo_mime_get_applications_for_file (NemoFile *file) { char *mime_type; char *uri_scheme; GList *result; GAppInfo *uri_handler; if (!nemo_mime_actions_check_if_required_attributes_ready (file)) { return NULL; } mime_type = nemo_file_get_mime_type (file); result = g_app_info_get_all_for_type (mime_type); uri_scheme = nemo_file_get_uri_scheme (file); if (uri_scheme != NULL) { uri_handler = g_app_info_get_default_for_uri_scheme (uri_scheme); if (uri_handler) { result = g_list_prepend (result, uri_handler); } g_free (uri_scheme); } if (!file_has_local_path (file)) { /* Filter out non-uri supporting apps */ result = filter_non_uri_apps (result); } result = g_list_sort (result, (GCompareFunc) application_compare_by_name); g_free (mime_type); return filter_nemo_handler (result); } GAppInfo * nemo_mime_get_default_application_for_files (GList *files) { GList *l, *sorted_files; NemoFile *file; GAppInfo *app, *one_app; g_assert (files != NULL); sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type); app = NULL; for (l = sorted_files; l != NULL; l = l->next) { file = l->data; if (l->prev && file_compare_by_mime_type (file, l->prev->data) == 0 && file_compare_by_parent_uri (file, l->prev->data) == 0) { continue; } one_app = nemo_mime_get_default_application_for_file (file); if (one_app == NULL || (app != NULL && !g_app_info_equal (app, one_app))) { if (app) { g_object_unref (app); } if (one_app) { g_object_unref (one_app); } app = NULL; break; } if (app == NULL) { app = one_app; } else { g_object_unref (one_app); } } g_list_free (sorted_files); return app; } /* returns an intersection of two mime application lists, * and returns a new list, freeing a, b and all applications * that are not in the intersection set. * The lists are assumed to be pre-sorted by their IDs */ static GList * intersect_application_lists (GList *a, GList *b) { GList *l, *m; GList *ret; GAppInfo *a_app, *b_app; int cmp; ret = NULL; l = a; m = b; while (l != NULL && m != NULL) { a_app = (GAppInfo *) l->data; b_app = (GAppInfo *) m->data; cmp = application_compare_by_id (a_app, b_app); if (cmp > 0) { g_object_unref (b_app); m = m->next; } else if (cmp < 0) { g_object_unref (a_app); l = l->next; } else { g_object_unref (b_app); ret = g_list_prepend (ret, a_app); l = l->next; m = m->next; } } g_list_foreach (l, (GFunc) g_object_unref, NULL); g_list_foreach (m, (GFunc) g_object_unref, NULL); g_list_free (a); g_list_free (b); return g_list_reverse (ret); } GList * nemo_mime_get_applications_for_files (GList *files) { GList *l, *sorted_files; NemoFile *file; GList *one_ret, *ret; g_assert (files != NULL); sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type); ret = NULL; for (l = sorted_files; l != NULL; l = l->next) { file = l->data; if (l->prev && file_compare_by_mime_type (file, l->prev->data) == 0 && file_compare_by_parent_uri (file, l->prev->data) == 0) { continue; } one_ret = nemo_mime_get_applications_for_file (file); one_ret = g_list_sort (one_ret, (GCompareFunc) application_compare_by_id); if (ret != NULL) { ret = intersect_application_lists (ret, one_ret); } else { ret = one_ret; } if (ret == NULL) { break; } } g_list_free (sorted_files); ret = g_list_sort (ret, (GCompareFunc) application_compare_by_name); return ret; } static void trash_or_delete_files (GtkWindow *parent_window, const GList *files, gboolean delete_if_all_already_in_trash) { GList *locations; const GList *node; locations = NULL; for (node = files; node != NULL; node = node->next) { locations = g_list_prepend (locations, nemo_file_get_location ((NemoFile *) node->data)); } locations = g_list_reverse (locations); nemo_file_operations_trash_or_delete (locations, parent_window, NULL, NULL); g_list_free_full (locations, g_object_unref); } static void report_broken_symbolic_link (GtkWindow *parent_window, NemoFile *file) { char *target_path; char *display_name; char *prompt; char *detail; GtkDialog *dialog; GList file_as_list; int response; g_assert (nemo_file_is_broken_symbolic_link (file)); display_name = nemo_file_get_display_name (file); if (nemo_file_is_in_trash (file)) { prompt = g_strdup_printf (_("The Link \"%s\" is Broken."), display_name); } else { prompt = g_strdup_printf (_("The Link \"%s\" is Broken. Move it to Trash?"), display_name); } g_free (display_name); target_path = nemo_file_get_symbolic_link_target_path (file); if (target_path == NULL) { detail = g_strdup (_("This link cannot be used, because it has no target.")); } else { detail = g_strdup_printf (_("This link cannot be used, because its target " "\"%s\" doesn't exist."), target_path); } if (nemo_file_is_in_trash (file)) { eel_run_simple_dialog (GTK_WIDGET (parent_window), FALSE, GTK_MESSAGE_WARNING, prompt, detail, GTK_STOCK_CANCEL, NULL); goto out; } dialog = eel_show_yes_no_dialog (prompt, detail, _("Mo_ve to Trash"), GTK_STOCK_CANCEL, parent_window); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CANCEL); /* Make this modal to avoid problems with reffing the view & file * to keep them around in case the view changes, which would then * cause the old view not to be destroyed, which would cause its * merged Bonobo items not to be un-merged. Maybe we need to unmerge * explicitly when disconnecting views instead of relying on the * unmerge in Destroy. But since BonoboUIHandler is probably going * to change wildly, I don't want to mess with this now. */ response = gtk_dialog_run (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); if (response == GTK_RESPONSE_YES) { file_as_list.data = file; file_as_list.next = NULL; file_as_list.prev = NULL; trash_or_delete_files (parent_window, &file_as_list, TRUE); } out: g_free (prompt); g_free (target_path); g_free (detail); } static ActivationAction get_executable_text_file_action (GtkWindow *parent_window, NemoFile *file) { GtkDialog *dialog; char *file_name; char *prompt; char *detail; int preferences_value; int response; g_assert (nemo_file_contains_text (file)); preferences_value = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION); switch (preferences_value) { case NEMO_EXECUTABLE_TEXT_LAUNCH: return ACTIVATION_ACTION_LAUNCH; case NEMO_EXECUTABLE_TEXT_DISPLAY: return ACTIVATION_ACTION_OPEN_IN_APPLICATION; case NEMO_EXECUTABLE_TEXT_ASK: break; default: /* Complain non-fatally, since preference data can't be trusted */ g_warning ("Unknown value %d for NEMO_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION", preferences_value); } file_name = nemo_file_get_display_name (file); prompt = g_strdup_printf (_("Do you want to run \"%s\", or display its contents?"), file_name); detail = g_strdup_printf (_("\"%s\" is an executable text file."), file_name); g_free (file_name); dialog = eel_create_question_dialog (prompt, detail, _("Run in _Terminal"), RESPONSE_RUN_IN_TERMINAL, _("_Display"), RESPONSE_DISPLAY, parent_window); gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button (dialog, _("_Run"), RESPONSE_RUN); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CANCEL); gtk_widget_show (GTK_WIDGET (dialog)); g_free (prompt); g_free (detail); response = gtk_dialog_run (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); switch (response) { case RESPONSE_RUN: return ACTIVATION_ACTION_LAUNCH; case RESPONSE_RUN_IN_TERMINAL: return ACTIVATION_ACTION_LAUNCH_IN_TERMINAL; case RESPONSE_DISPLAY: return ACTIVATION_ACTION_OPEN_IN_APPLICATION; default: return ACTIVATION_ACTION_DO_NOTHING; } } static ActivationAction get_default_executable_text_file_action (void) { int preferences_value; preferences_value = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION); switch (preferences_value) { case NEMO_EXECUTABLE_TEXT_LAUNCH: return ACTIVATION_ACTION_LAUNCH; case NEMO_EXECUTABLE_TEXT_DISPLAY: return ACTIVATION_ACTION_OPEN_IN_APPLICATION; case NEMO_EXECUTABLE_TEXT_ASK: default: return ACTIVATION_ACTION_ASK; } } gboolean nemo_mime_file_opens_in_view (NemoFile *file) { return (nemo_file_is_directory (file) || NEMO_IS_DESKTOP_ICON_FILE (file)); } static ActivationAction get_activation_action (NemoFile *file, gboolean is_desktop) { ActivationAction action; char *activation_uri; if (nemo_file_is_nemo_link (file)) { return ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE; } activation_uri = nemo_file_get_activation_uri (file); if (activation_uri == NULL) { activation_uri = nemo_file_get_uri (file); } action = ACTIVATION_ACTION_DO_NOTHING; if (nemo_file_is_launchable (file)) { char *executable_path; action = ACTIVATION_ACTION_LAUNCH; executable_path = g_filename_from_uri (activation_uri, NULL, NULL); if (!executable_path) { action = ACTIVATION_ACTION_DO_NOTHING; } else if (nemo_file_contains_text (file)) { action = get_default_executable_text_file_action (); } g_free (executable_path); } if (action == ACTIVATION_ACTION_DO_NOTHING) { if (nemo_mime_file_opens_in_view (file) && !is_desktop) { action = ACTIVATION_ACTION_OPEN_IN_VIEW; } else { action = ACTIVATION_ACTION_OPEN_IN_APPLICATION; } } g_free (activation_uri); return action; } gboolean nemo_mime_file_opens_in_external_app (NemoFile *file) { ActivationAction activation_action; activation_action = get_activation_action (file, FALSE); return (activation_action == ACTIVATION_ACTION_OPEN_IN_APPLICATION); } static unsigned int mime_application_hash (GAppInfo *app) { const char *id; id = g_app_info_get_id (app); if (id == NULL) { return GPOINTER_TO_UINT(app); } return g_str_hash (id); } static void list_to_parameters_foreach (GAppInfo *application, GList *uris, GList **ret) { ApplicationLaunchParameters *parameters; uris = g_list_reverse (uris); parameters = application_launch_parameters_new (application, uris); *ret = g_list_prepend (*ret, parameters); } /** * make_activation_parameters * * Construct a list of ApplicationLaunchParameters from a list of NemoFiles, * where files that have the same default application are put into the same * launch parameter, and others are put into the unhandled_files list. * * @files: Files to use for construction. * @unhandled_files: Files without any default application will be put here. * * Return value: Newly allocated list of ApplicationLaunchParameters. **/ static GList * make_activation_parameters (GList *uris, GList **unhandled_uris) { GList *ret, *l, *app_uris; NemoFile *file; GAppInfo *app, *old_app; GHashTable *app_table; char *uri; ret = NULL; *unhandled_uris = NULL; app_table = g_hash_table_new_full ((GHashFunc) mime_application_hash, (GEqualFunc) g_app_info_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) g_list_free); for (l = uris; l != NULL; l = l->next) { uri = l->data; file = nemo_file_get_by_uri (uri); app = nemo_mime_get_default_application_for_file (file); if (app != NULL) { app_uris = NULL; if (g_hash_table_lookup_extended (app_table, app, (gpointer *) &old_app, (gpointer *) &app_uris)) { g_hash_table_steal (app_table, old_app); app_uris = g_list_prepend (app_uris, uri); g_object_unref (app); app = old_app; } else { app_uris = g_list_prepend (NULL, uri); } g_hash_table_insert (app_table, app, app_uris); } else { *unhandled_uris = g_list_prepend (*unhandled_uris, uri); } nemo_file_unref (file); } g_hash_table_foreach (app_table, (GHFunc) list_to_parameters_foreach, &ret); g_hash_table_destroy (app_table); *unhandled_uris = g_list_reverse (*unhandled_uris); return g_list_reverse (ret); } static gboolean file_was_cancelled (NemoFile *file) { GError *error; error = nemo_file_get_file_info_error (file); return error != NULL && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED; } static gboolean file_was_not_mounted (NemoFile *file) { GError *error; error = nemo_file_get_file_info_error (file); return error != NULL && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED; } static void activation_parameters_free (ActivateParameters *parameters) { if (parameters->timed_wait_active) { eel_timed_wait_stop (cancel_activate_callback, parameters); } if (parameters->slot) { g_object_remove_weak_pointer (G_OBJECT (parameters->slot), (gpointer *)¶meters->slot); } if (parameters->parent_window) { g_object_remove_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *)¶meters->parent_window); } g_object_unref (parameters->cancellable); launch_location_list_free (parameters->locations); nemo_file_list_free (parameters->mountables); nemo_file_list_free (parameters->start_mountables); nemo_file_list_free (parameters->not_mounted); g_free (parameters->activation_directory); g_free (parameters->timed_wait_prompt); g_assert (parameters->files_handle == NULL); g_free (parameters); } static void cancel_activate_callback (gpointer callback_data) { ActivateParameters *parameters = callback_data; parameters->timed_wait_active = FALSE; g_cancellable_cancel (parameters->cancellable); if (parameters->files_handle) { nemo_file_list_cancel_call_when_ready (parameters->files_handle); parameters->files_handle = NULL; activation_parameters_free (parameters); } } static void activation_start_timed_cancel (ActivateParameters *parameters) { parameters->timed_wait_active = TRUE; eel_timed_wait_start_with_duration (DELAY_UNTIL_CANCEL_MSECS, cancel_activate_callback, parameters, parameters->timed_wait_prompt, parameters->parent_window); } static void pause_activation_timed_cancel (ActivateParameters *parameters) { if (parameters->timed_wait_active) { eel_timed_wait_stop (cancel_activate_callback, parameters); parameters->timed_wait_active = FALSE; } } static void unpause_activation_timed_cancel (ActivateParameters *parameters) { if (!parameters->timed_wait_active) { activation_start_timed_cancel (parameters); } } static void activate_mount_op_active (GtkMountOperation *operation, GParamSpec *pspec, ActivateParameters *parameters) { gboolean is_active; g_object_get (operation, "is-showing", &is_active, NULL); if (is_active) { pause_activation_timed_cancel (parameters); } else { unpause_activation_timed_cancel (parameters); } } static gboolean confirm_multiple_windows (GtkWindow *parent_window, int count, gboolean use_tabs) { GtkDialog *dialog; char *prompt; char *detail; int response; if (count <= SILENT_WINDOW_OPEN_LIMIT) { return TRUE; } prompt = _("Are you sure you want to open all files?"); if (use_tabs) { detail = g_strdup_printf (ngettext("This will open %d separate tab.", "This will open %d separate tabs.", count), count); } else { detail = g_strdup_printf (ngettext("This will open %d separate window.", "This will open %d separate windows.", count), count); } dialog = eel_show_yes_no_dialog (prompt, detail, GTK_STOCK_OK, GTK_STOCK_CANCEL, parent_window); g_free (detail); response = gtk_dialog_run (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); return response == GTK_RESPONSE_YES; } typedef struct { GtkWindow *parent_window; NemoFile *file; } ActivateParametersSpecial; static void activate_parameters_special_free (ActivateParametersSpecial *parameters_special) { if (parameters_special->parent_window) { g_object_remove_weak_pointer (G_OBJECT (parameters_special->parent_window), (gpointer *)¶meters_special->parent_window); } nemo_file_unref (parameters_special->file); g_free (parameters_special); } static void make_exec_callback (NemoFile *file, GFile *res_loc, GError *error, gpointer callback_data) { ActivateParametersSpecial *params = (ActivateParametersSpecial *) callback_data; if (error == NULL) { gchar *path = nemo_file_get_path (params->file); nemo_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (params->parent_window)), path, FALSE, NULL); g_free (path); } nemo_report_error_setting_permissions (file, error, NULL); activate_parameters_special_free (params); } static void open_with_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { GtkWindow *parent_window; NemoFile *file; GAppInfo *info; GList files; if (response_id != GTK_RESPONSE_OK) { gtk_widget_destroy (GTK_WIDGET (dialog)); return; } parent_window = user_data; GtkWidget *content = gtk_dialog_get_content_area (dialog); GList *children = gtk_container_get_children (GTK_CONTAINER (content)); NemoMimeApplicationChooser *chooser = children->data; g_list_free (children); info = nemo_mime_application_chooser_get_info (chooser); file = nemo_file_get_by_uri (nemo_mime_application_chooser_get_uri (chooser)); g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); files.next = NULL; files.prev = NULL; files.data = file; nemo_launch_application (info, &files, parent_window); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (info); } static void run_open_with_dialog (ActivateParametersSpecial *params) { GtkWidget *dialog; GtkWidget *ok_button; char *mime_type; char *uri = NULL; GList *uris = NULL; mime_type = nemo_file_get_mime_type (params->file); uri = nemo_file_get_uri (params->file); dialog = gtk_dialog_new_with_buttons (_("Open with"), params->parent_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); GtkWidget *chooser = nemo_mime_application_chooser_new (uri, uris, mime_type, ok_button); GtkWidget *content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); gtk_box_pack_start (GTK_BOX (content), chooser, TRUE, TRUE, 0); gtk_widget_show_all (dialog); g_signal_connect_object (dialog, "response", G_CALLBACK (open_with_dialog_response_cb), params->parent_window, 0); activate_parameters_special_free (params); } static void unhandled_uri_response_callback (GtkDialog *dialog, int response_id, ActivateParametersSpecial *parameters) { switch (response_id) { case RESPONSE_RUN: ; guint32 existing = nemo_file_get_permissions (parameters->file); nemo_file_set_permissions (parameters->file, existing | (UNIX_PERM_USER_EXEC|UNIX_PERM_GROUP_EXEC|UNIX_PERM_OTHER_EXEC), (NemoFileOperationCallback) make_exec_callback, parameters); break; case RESPONSE_OPEN_WITH: run_open_with_dialog (parameters); break; default: /* Just destroy dialog */ break; } gtk_widget_destroy (GTK_WIDGET (dialog)); } static void application_unhandled_uri (ActivateParameters *parameters, char *uri) { NemoFile *file = nemo_file_get_existing_by_uri (uri); gboolean enable_exec_button; char *primary, *secondary, *display_name; GtkWidget *dialog; ActivateParametersSpecial *parameters_special; parameters_special = g_new0 (ActivateParametersSpecial, 1); if (parameters->parent_window) { parameters_special->parent_window = parameters->parent_window; g_object_add_weak_pointer (G_OBJECT (parameters_special->parent_window), (gpointer *)¶meters_special->parent_window); } parameters_special->file = nemo_file_ref (file); enable_exec_button = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_MIME_MAKE_EXECUTABLE); dialog = gtk_message_dialog_new (parameters->parent_window, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, NULL); primary = _("Unknown file type"); display_name = nemo_file_get_display_name (file); if (enable_exec_button) { secondary = g_strdup_printf (_("The file \"%s\" has no known programs associated with it. " "If you trust the source of this file, and have sufficient permissions, you can mark it executable and launch it. " "Or, you can use the Open With dialog to pick a program to associate it with." ), display_name); gtk_dialog_add_button (GTK_DIALOG (dialog), _("Make executable and run"), RESPONSE_RUN); } else { secondary = g_strdup_printf (_("The file \"%s\" has no known programs associated with it. " "Use the Open With dialog to pick a program to open it with."), display_name); } g_object_set (dialog, "text", primary, "secondary-text", secondary, NULL); gtk_dialog_add_button (GTK_DIALOG (dialog), _("Choose a program"), RESPONSE_OPEN_WITH); if (!nemo_file_can_set_permissions (file) && enable_exec_button) { GtkWidget *w = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), RESPONSE_RUN); gtk_widget_set_sensitive (w, FALSE); } gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); g_signal_connect (dialog, "response", G_CALLBACK (unhandled_uri_response_callback), parameters_special); gtk_widget_show (dialog); g_free (display_name); g_free (secondary); return; } static void untrusted_launcher_response_callback (GtkDialog *dialog, int response_id, ActivateParametersSpecial *parameters) { GdkScreen *screen; char *uri; GFile *file; switch (response_id) { case RESPONSE_RUN: screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window)); uri = nemo_file_get_uri (parameters->file); DEBUG ("Launching untrusted launcher %s", uri); nemo_launch_desktop_file (screen, uri, NULL, parameters->parent_window); g_free (uri); break; case RESPONSE_MARK_TRUSTED: file = nemo_file_get_location (parameters->file); nemo_file_mark_desktop_file_trusted (file, parameters->parent_window, TRUE, NULL, NULL); g_object_unref (file); break; default: /* Just destroy dialog */ break; } gtk_widget_destroy (GTK_WIDGET (dialog)); activate_parameters_special_free (parameters); } static void activate_desktop_file (ActivateParameters *parameters, NemoFile *file) { ActivateParametersSpecial *parameters_special; char *primary, *secondary, *display_name; GtkWidget *dialog; GdkScreen *screen; char *uri; screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window)); if (!nemo_file_is_trusted_link (file)) { /* copy the parts of parameters we are interested in as the orignal will be freed */ parameters_special = g_new0 (ActivateParametersSpecial, 1); if (parameters->parent_window) { parameters_special->parent_window = parameters->parent_window; g_object_add_weak_pointer (G_OBJECT (parameters_special->parent_window), (gpointer *)¶meters_special->parent_window); } parameters_special->file = nemo_file_ref (file); primary = _("Untrusted application launcher"); display_name = nemo_file_get_display_name (file); secondary = g_strdup_printf (_("The application launcher \"%s\" has not been marked as trusted (executable). " "If you do not know the source of this file, launching it may be unsafe." ), display_name); dialog = gtk_message_dialog_new (parameters->parent_window, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, NULL); g_object_set (dialog, "text", primary, "secondary-text", secondary, NULL); gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Launch Anyway"), RESPONSE_RUN); if (nemo_file_can_set_permissions (file)) { gtk_dialog_add_button (GTK_DIALOG (dialog), _("Mark as _Trusted"), RESPONSE_MARK_TRUSTED); } gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); g_signal_connect (dialog, "response", G_CALLBACK (untrusted_launcher_response_callback), parameters_special); gtk_widget_show (dialog); g_free (display_name); g_free (secondary); return; } uri = nemo_file_get_uri (file); DEBUG ("Launching trusted launcher %s", uri); nemo_launch_desktop_file (screen, uri, NULL, parameters->parent_window); g_free (uri); } static void activate_files (ActivateParameters *parameters) { NemoWindow *window; NemoWindowOpenFlags flags; NemoFile *file; GList *launch_desktop_files; GList *launch_files; GList *launch_in_terminal_files; GList *open_in_app_uris; GList *open_in_app_parameters; GList *unhandled_open_in_app_uris; ApplicationLaunchParameters *one_parameters; GList *open_in_view_files; GList *l; int count; char *uri; char *executable_path, *quoted_path; char *old_working_dir; ActivationAction action; GdkScreen *screen; LaunchLocation *location; gint num_apps; gint num_unhandled; gint num_files; gboolean open_files; gboolean launch_location_is_desktop; screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window)); launch_desktop_files = NULL; launch_files = NULL; launch_in_terminal_files = NULL; launch_location_is_desktop = FALSE; open_in_app_uris = NULL; open_in_view_files = NULL; window = NULL; if (parameters->slot != NULL) { window = nemo_window_slot_get_window (parameters->slot); launch_location_is_desktop = NEMO_IS_DESKTOP_WINDOW (window); } for (l = parameters->locations; l != NULL; l = l->next) { location = l->data; file = location->file; if (file_was_cancelled (file)) { continue; } action = get_activation_action (file, launch_location_is_desktop); if (action == ACTIVATION_ACTION_ASK) { /* Special case for executable text files, since it might be * dangerous & unexpected to launch these. */ pause_activation_timed_cancel (parameters); action = get_executable_text_file_action (parameters->parent_window, file); unpause_activation_timed_cancel (parameters); } switch (action) { case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE : launch_desktop_files = g_list_prepend (launch_desktop_files, file); break; case ACTIVATION_ACTION_LAUNCH : launch_files = g_list_prepend (launch_files, file); break; case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL : launch_in_terminal_files = g_list_prepend (launch_in_terminal_files, file); break; case ACTIVATION_ACTION_OPEN_IN_VIEW : open_in_view_files = g_list_prepend (open_in_view_files, file); break; case ACTIVATION_ACTION_OPEN_IN_APPLICATION : open_in_app_uris = g_list_prepend (open_in_app_uris, location->uri); break; case ACTIVATION_ACTION_DO_NOTHING : break; case ACTIVATION_ACTION_ASK : g_assert_not_reached (); break; default: break; } } launch_desktop_files = g_list_reverse (launch_desktop_files); for (l = launch_desktop_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); activate_desktop_file (parameters, file); } old_working_dir = NULL; if (parameters->activation_directory && (launch_files != NULL || launch_in_terminal_files != NULL)) { old_working_dir = g_get_current_dir (); g_chdir (parameters->activation_directory); } launch_files = g_list_reverse (launch_files); for (l = launch_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); uri = nemo_file_get_activation_uri (file); executable_path = g_filename_from_uri (uri, NULL, NULL); quoted_path = g_shell_quote (executable_path); DEBUG ("Launching file path %s", quoted_path); nemo_launch_application_from_command (screen, quoted_path, FALSE, NULL); g_free (quoted_path); g_free (executable_path); g_free (uri); } launch_in_terminal_files = g_list_reverse (launch_in_terminal_files); for (l = launch_in_terminal_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); uri = nemo_file_get_activation_uri (file); executable_path = g_filename_from_uri (uri, NULL, NULL); quoted_path = g_shell_quote (executable_path); DEBUG ("Launching in terminal file quoted path %s", quoted_path); nemo_launch_application_from_command (screen, quoted_path, TRUE, NULL); g_free (quoted_path); g_free (executable_path); g_free (uri); } if (old_working_dir != NULL) { g_chdir (old_working_dir); g_free (old_working_dir); } open_in_view_files = g_list_reverse (open_in_view_files); count = g_list_length (open_in_view_files); flags = parameters->flags; if (count > 1) { if ((parameters->flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0 && g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } } if (parameters->slot != NULL && (!parameters->user_confirmation || confirm_multiple_windows (parameters->parent_window, count, (flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0))) { if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0 && g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_NEW_TAB_POSITION) == NEMO_NEW_TAB_POSITION_AFTER_CURRENT_TAB) { /* When inserting N tabs after the current one, * we first open tab N, then tab N-1, ..., then tab 0. * Each of them is appended to the current tab, i.e. * prepended to the list of tabs to open. */ open_in_view_files = g_list_reverse (open_in_view_files); } for (l = open_in_view_files; l != NULL; l = l->next) { GFile *initial_location, *final_location; /* The ui should ask for navigation or object windows * depending on what the current one is */ file = NEMO_FILE (l->data); uri = nemo_file_get_activation_uri (file); initial_location = g_file_new_for_uri (uri); if (g_file_is_native (initial_location) && (nemo_file_is_in_admin (file) || !nemo_file_can_read (file) || !nemo_file_can_execute (file))) { gchar *file_path = NULL; g_free (uri); file_path = g_file_get_path (initial_location); uri = g_strconcat ("admin://", file_path, NULL); } final_location = g_file_new_for_uri (uri); nemo_window_slot_open_location (parameters->slot, final_location, flags); g_clear_object (&initial_location); g_clear_object (&final_location); g_free (uri); } } open_in_app_parameters = NULL; unhandled_open_in_app_uris = NULL; if (open_in_app_uris != NULL) { open_in_app_uris = g_list_reverse (open_in_app_uris); open_in_app_parameters = make_activation_parameters (open_in_app_uris, &unhandled_open_in_app_uris); } num_apps = g_list_length (open_in_app_parameters); num_unhandled = g_list_length (unhandled_open_in_app_uris); num_files = g_list_length (open_in_app_uris); open_files = TRUE; if (open_in_app_uris != NULL && (!parameters->user_confirmation || num_files + num_unhandled > SILENT_OPEN_LIMIT) && num_apps > 1) { GtkDialog *dialog; char *prompt; char *detail; int response; pause_activation_timed_cancel (parameters); prompt = _("Are you sure you want to open all files?"); detail = g_strdup_printf (ngettext ("This will open %d separate application.", "This will open %d separate applications.", num_apps), num_apps); dialog = eel_show_yes_no_dialog (prompt, detail, GTK_STOCK_OK, GTK_STOCK_CANCEL, parameters->parent_window); g_free (detail); response = gtk_dialog_run (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); unpause_activation_timed_cancel (parameters); if (response != GTK_RESPONSE_YES) { open_files = FALSE; } } if (open_files) { for (l = open_in_app_parameters; l != NULL; l = l->next) { one_parameters = l->data; nemo_launch_application_by_uri (one_parameters->application, one_parameters->uris, parameters->parent_window); application_launch_parameters_free (one_parameters); } for (l = unhandled_open_in_app_uris; l != NULL; l = l->next) { uri = l->data; /* this does not block */ application_unhandled_uri (parameters, uri); } } if (open_in_app_parameters != NULL || unhandled_open_in_app_uris != NULL) { if ((parameters->flags & NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0 && window != NULL) { nemo_window_close (window); } } g_list_free (launch_desktop_files); g_list_free (launch_files); g_list_free (launch_in_terminal_files); g_list_free (open_in_view_files); g_list_free (open_in_app_uris); g_list_free (open_in_app_parameters); g_list_free (unhandled_open_in_app_uris); activation_parameters_free (parameters); } static void activation_mount_not_mounted_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { ActivateParameters *parameters = user_data; GError *error; NemoFile *file; LaunchLocation *loc; file = parameters->not_mounted->data; error = NULL; if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) { if (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED)) { eel_show_error_dialog (_("Unable to mount location"), error->message, parameters->parent_window); } if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_ALREADY_MOUNTED) { loc = find_launch_location_for_file (parameters->locations, file); if (loc) { parameters->locations = g_list_remove (parameters->locations, loc); launch_location_free (loc); } } g_error_free (error); } parameters->not_mounted = g_list_delete_link (parameters->not_mounted, parameters->not_mounted); nemo_file_unref (file); activation_mount_not_mounted (parameters); } static void activation_mount_not_mounted (ActivateParameters *parameters) { NemoFile *file; GFile *location; LaunchLocation *loc; GMountOperation *mount_op; GList *l, *next, *files; if (parameters->not_mounted != NULL) { file = parameters->not_mounted->data; mount_op = gtk_mount_operation_new (parameters->parent_window); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); g_signal_connect (mount_op, "notify::is-showing", G_CALLBACK (activate_mount_op_active), parameters); location = nemo_file_get_location (file); g_file_mount_enclosing_volume (location, 0, mount_op, parameters->cancellable, activation_mount_not_mounted_callback, parameters); g_object_unref (location); /* unref mount_op here - g_file_mount_enclosing_volume() does ref for itself */ g_object_unref (mount_op); return; } parameters->tried_mounting = TRUE; if (parameters->locations == NULL) { activation_parameters_free (parameters); return; } /* once the mount is finished, refresh all attributes */ /* - fixes new windows not appearing after successful mount */ for (l = parameters->locations; l != NULL; l = next) { loc = l->data; next = l->next; nemo_file_invalidate_all_attributes (loc->file); } files = get_file_list_for_launch_locations (parameters->locations); nemo_file_list_call_when_ready (files, nemo_mime_actions_get_required_file_attributes () | NEMO_FILE_ATTRIBUTE_LINK_INFO, ¶meters->files_handle, activate_callback, parameters); nemo_file_list_free (files); } static void activate_callback (GList *files, gpointer callback_data) { ActivateParameters *parameters = callback_data; GList *l, *next; NemoFile *file; LaunchLocation *location; parameters->files_handle = NULL; for (l = parameters->locations; l != NULL; l = next) { location = l->data; file = location->file; next = l->next; if (file_was_cancelled (file)) { launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); continue; } if (file_was_not_mounted (file)) { if (parameters->tried_mounting) { launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); } else { parameters->not_mounted = g_list_prepend (parameters->not_mounted, nemo_file_ref (file)); } continue; } } if (parameters->not_mounted != NULL) { activation_mount_not_mounted (parameters); } else { activate_files (parameters); } } static void activate_activation_uris_ready_callback (GList *files_ignore, gpointer callback_data) { ActivateParameters *parameters = callback_data; GList *l, *next, *files; NemoFile *file; LaunchLocation *location; parameters->files_handle = NULL; for (l = parameters->locations; l != NULL; l = next) { location = l->data; file = location->file; next = l->next; if (file_was_cancelled (file)) { launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); continue; } if (nemo_file_is_broken_symbolic_link (file)) { launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); pause_activation_timed_cancel (parameters); report_broken_symbolic_link (parameters->parent_window, file); unpause_activation_timed_cancel (parameters); continue; } if (nemo_file_get_file_type (file) == G_FILE_TYPE_MOUNTABLE && !nemo_file_has_activation_uri (file)) { /* Don't launch these... There is nothing we can do */ launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); continue; } } if (parameters->locations == NULL) { activation_parameters_free (parameters); return; } /* Convert the files to the actual activation uri files */ for (l = parameters->locations; l != NULL; l = l->next) { char *uri; location = l->data; /* We want the file for the activation URI since we care * about the attributes for that, not for the original file. */ uri = nemo_file_get_activation_uri (location->file); if (uri != NULL) { launch_location_update_from_uri (location, uri); } g_free (uri); } /* get the parameters for the actual files */ files = get_file_list_for_launch_locations (parameters->locations); nemo_file_list_call_when_ready (files, nemo_mime_actions_get_required_file_attributes () | NEMO_FILE_ATTRIBUTE_LINK_INFO, ¶meters->files_handle, activate_callback, parameters); nemo_file_list_free (files); } static void activation_get_activation_uris (ActivateParameters *parameters) { GList *l, *files; NemoFile *file; LaunchLocation *location; /* link target info might be stale, re-read it */ for (l = parameters->locations; l != NULL; l = l->next) { location = l->data; file = location->file; if (file_was_cancelled (file)) { launch_location_free (location); parameters->locations = g_list_delete_link (parameters->locations, l); continue; } if (nemo_file_is_symbolic_link (file)) { nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO); } } if (parameters->locations == NULL) { activation_parameters_free (parameters); return; } files = get_file_list_for_launch_locations (parameters->locations); nemo_file_list_call_when_ready (files, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO, ¶meters->files_handle, activate_activation_uris_ready_callback, parameters); nemo_file_list_free (files); } static void activation_mountable_mounted (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { ActivateParameters *parameters = callback_data; NemoFile *target_file; LaunchLocation *location; /* Remove from list of files that have to be mounted */ parameters->mountables = g_list_remove (parameters->mountables, file); nemo_file_unref (file); if (error == NULL) { /* Replace file with the result of the mount */ target_file = nemo_file_get (result_location); location = find_launch_location_for_file (parameters->locations, file); if (location) { launch_location_update_from_file (location, target_file); } nemo_file_unref (target_file); } else { /* Remove failed file */ if (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED)) { location = find_launch_location_for_file (parameters->locations, file); if (location) { parameters->locations = g_list_remove (parameters->locations, location); launch_location_free (location); } } if (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED)) { eel_show_error_dialog (_("Unable to mount location"), error->message, parameters->parent_window); } if (error->code == G_IO_ERROR_CANCELLED) { activation_parameters_free (parameters); return; } } /* Mount more mountables */ activation_mount_mountables (parameters); } static void activation_mount_mountables (ActivateParameters *parameters) { NemoFile *file; GMountOperation *mount_op; if (parameters->mountables != NULL) { file = parameters->mountables->data; mount_op = gtk_mount_operation_new (parameters->parent_window); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); g_signal_connect (mount_op, "notify::is-showing", G_CALLBACK (activate_mount_op_active), parameters); nemo_file_mount (file, mount_op, parameters->cancellable, activation_mountable_mounted, parameters); g_object_unref (mount_op); return; } if (parameters->mountables == NULL && parameters->start_mountables == NULL) activation_get_activation_uris (parameters); } static void activation_mountable_started (NemoFile *file, GFile *gfile_of_file, GError *error, gpointer callback_data) { ActivateParameters *parameters = callback_data; LaunchLocation *location; /* Remove from list of files that have to be mounted */ parameters->start_mountables = g_list_remove (parameters->start_mountables, file); nemo_file_unref (file); if (error == NULL) { /* Remove file */ location = find_launch_location_for_file (parameters->locations, file); if (location != NULL) { parameters->locations = g_list_remove (parameters->locations, location); launch_location_free (location); } } else { /* Remove failed file */ if (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_FAILED_HANDLED)) { location = find_launch_location_for_file (parameters->locations, file); if (location) { parameters->locations = g_list_remove (parameters->locations, location); launch_location_free (location); } } if (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED)) { eel_show_error_dialog (_("Unable to start location"), error->message, NULL); } if (error->code == G_IO_ERROR_CANCELLED) { activation_parameters_free (parameters); return; } } /* Start more mountables */ activation_start_mountables (parameters); } static void activation_start_mountables (ActivateParameters *parameters) { NemoFile *file; GMountOperation *start_op; if (parameters->start_mountables != NULL) { file = parameters->start_mountables->data; start_op = gtk_mount_operation_new (parameters->parent_window); g_signal_connect (start_op, "notify::is-showing", G_CALLBACK (activate_mount_op_active), parameters); nemo_file_start (file, start_op, parameters->cancellable, activation_mountable_started, parameters); g_object_unref (start_op); return; } if (parameters->mountables == NULL && parameters->start_mountables == NULL) activation_get_activation_uris (parameters); } /** * nemo_mime_activate_files: * * Activate a list of files. Each one might launch with an application or * with a component. This is normally called only by subclasses. * @view: FMDirectoryView in question. * @files: A GList of NemoFiles to activate. * **/ void nemo_mime_activate_files (GtkWindow *parent_window, NemoWindowSlot *slot, GList *files, const char *launch_directory, NemoWindowOpenFlags flags, gboolean user_confirmation) { ActivateParameters *parameters; char *file_name; int file_count; GList *l, *next; NemoFile *file; LaunchLocation *location; if (files == NULL) { return; } DEBUG_FILES (files, "Calling activate_files() with files:"); parameters = g_new0 (ActivateParameters, 1); parameters->slot = slot; g_object_add_weak_pointer (G_OBJECT (parameters->slot), (gpointer *)¶meters->slot); if (parent_window) { parameters->parent_window = parent_window; g_object_add_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *)¶meters->parent_window); } parameters->cancellable = g_cancellable_new (); parameters->activation_directory = g_strdup (launch_directory); parameters->locations = launch_locations_from_file_list (files); parameters->flags = flags; parameters->user_confirmation = user_confirmation; file_count = g_list_length (files); if (file_count == 1) { file_name = nemo_file_get_display_name (files->data); parameters->timed_wait_prompt = g_strdup_printf (_("Opening \"%s\"."), file_name); g_free (file_name); } else { parameters->timed_wait_prompt = g_strdup_printf (ngettext ("Opening %d item.", "Opening %d items.", file_count), file_count); } for (l = parameters->locations; l != NULL; l = next) { location = l->data; file = location->file; next = l->next; if (nemo_file_can_mount (file)) { parameters->mountables = g_list_prepend (parameters->mountables, nemo_file_ref (file)); } if (nemo_file_can_start (file)) { parameters->start_mountables = g_list_prepend (parameters->start_mountables, nemo_file_ref (file)); } } activation_start_timed_cancel (parameters); if (parameters->mountables != NULL) activation_mount_mountables (parameters); if (parameters->start_mountables != NULL) activation_start_mountables (parameters); if (parameters->mountables == NULL && parameters->start_mountables == NULL) activation_get_activation_uris (parameters); } /** * nemo_mime_activate_file: * * Activate a file in this view. This might involve switching the displayed * location for the current window, or launching an application. * @view: FMDirectoryView in question. * @file: A NemoFile representing the file in this view to activate. * @use_new_window: Should this item be opened in a new window? * **/ void nemo_mime_activate_file (GtkWindow *parent_window, NemoWindowSlot *slot, NemoFile *file, const char *launch_directory, NemoWindowOpenFlags flags) { GList *files; g_return_if_fail (NEMO_IS_FILE (file)); files = g_list_prepend (NULL, file); nemo_mime_activate_files (parent_window, slot, files, launch_directory, flags, FALSE); g_list_free (files); } void nemo_mime_launch_fm_and_select_file (GFile *file) { GAppInfo *info; GList *list; info = g_app_info_get_default_for_type ("inode/directory", !g_file_is_native (file)); list = g_list_prepend (NULL, file); g_app_info_launch (info, list, NULL, NULL); g_list_free (list); } nemo-4.4.2/src/nemo-mime-actions.h000066400000000000000000000050461357442400300167470ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-mime-actions.h - uri-specific versions of mime action functions Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Maciej Stachowiak */ #ifndef NEMO_MIME_ACTIONS_H #define NEMO_MIME_ACTIONS_H #include #include #include "nemo-window.h" NemoFileAttributes nemo_mime_actions_get_required_file_attributes (void); GAppInfo * nemo_mime_get_default_application_for_file (NemoFile *file); GList * nemo_mime_get_applications_for_file (NemoFile *file); GAppInfo * nemo_mime_get_default_application_for_files (GList *files); GList * nemo_mime_get_applications_for_files (GList *file); gboolean nemo_mime_file_opens_in_view (NemoFile *file); gboolean nemo_mime_file_opens_in_external_app (NemoFile *file); void nemo_mime_activate_files (GtkWindow *parent_window, NemoWindowSlot *slot, GList *files, const char *launch_directory, NemoWindowOpenFlags flags, gboolean user_confirmation); void nemo_mime_activate_file (GtkWindow *parent_window, NemoWindowSlot *slot_info, NemoFile *file, const char *launch_directory, NemoWindowOpenFlags flags); void nemo_mime_launch_fm_and_select_file (GFile *file); #endif /* NEMO_MIME_ACTIONS_H */ nemo-4.4.2/src/nemo-navigation-action.c000066400000000000000000000273671357442400300200010ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 2004, 2011 Red Hat, Inc. * Copyright (C) 2003 Marco Pesenti Gritti * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Based on ephy-navigation-action.h from Epiphany * * Authors: Alexander Larsson * Marco Pesenti Gritti * Cosimo Cecchi * */ #include #include "nemo-navigation-action.h" #include "nemo-window.h" #include #include G_DEFINE_TYPE (NemoNavigationAction, nemo_navigation_action, GTK_TYPE_ACTION); #define NEMO_NAVIGATION_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), NEMO_TYPE_NAVIGATION_ACTION, NemoNavigationActionPrivate)) struct NemoNavigationActionPrivate { NemoWindow *window; NemoNavigationDirection direction; char *arrow_tooltip; guint popup_timeout_id; }; enum { PROP_0, PROP_ARROW_TOOLTIP, PROP_DIRECTION, PROP_WINDOW }; static void activate_back_or_forward_menu_item (GtkMenuItem *menu_item, NemoWindow *window, gboolean back) { int index; g_assert (GTK_IS_MENU_ITEM (menu_item)); index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "user_data")); nemo_window_back_or_forward (window, back, index, nemo_event_get_window_open_flags ()); } static void activate_back_menu_item_callback (GtkMenuItem *menu_item, NemoWindow *window) { activate_back_or_forward_menu_item (menu_item, window, TRUE); } static void activate_forward_menu_item_callback (GtkMenuItem *menu_item, NemoWindow *window) { activate_back_or_forward_menu_item (menu_item, window, FALSE); } static void fill_menu (NemoWindow *window, GtkWidget *menu, gboolean back) { NemoWindowSlot *slot; GtkWidget *menu_item; int index; GList *list; slot = nemo_window_get_active_slot (window); list = back ? slot->back_list : slot->forward_list; index = 0; while (list != NULL) { menu_item = nemo_bookmark_menu_item_new (NEMO_BOOKMARK (list->data)); g_object_set_data (G_OBJECT (menu_item), "user_data", GINT_TO_POINTER (index)); gtk_widget_show (GTK_WIDGET (menu_item)); g_signal_connect_object (menu_item, "activate", back ? G_CALLBACK (activate_back_menu_item_callback) : G_CALLBACK (activate_forward_menu_item_callback), window, 0); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); list = g_list_next (list); ++index; } } static void show_menu (NemoNavigationAction *self, guint button, guint32 event_time) { NemoWindow *window; GtkWidget *menu; window = self->priv->window; menu = gtk_menu_new (); switch (self->priv->direction) { case NEMO_NAVIGATION_DIRECTION_FORWARD: fill_menu (window, menu, FALSE); break; case NEMO_NAVIGATION_DIRECTION_BACK: fill_menu (window, menu, TRUE); break; case NEMO_NAVIGATION_DIRECTION_UP: return; case NEMO_NAVIGATION_DIRECTION_RELOAD: return; case NEMO_NAVIGATION_DIRECTION_HOME: return; case NEMO_NAVIGATION_DIRECTION_COMPUTER: return; case NEMO_NAVIGATION_DIRECTION_EDIT: return; default: g_assert_not_reached (); break; } gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, event_time); } #define MENU_POPUP_TIMEOUT 1200 static gboolean popup_menu_timeout_cb (gpointer data) { NemoNavigationAction *self = data; show_menu (self, 1, gtk_get_current_event_time ()); return FALSE; } static void unschedule_menu_popup_timeout (NemoNavigationAction *self) { if (self->priv->popup_timeout_id != 0) { g_source_remove (self->priv->popup_timeout_id); self->priv->popup_timeout_id = 0; } } static void schedule_menu_popup_timeout (NemoNavigationAction *self) { /* unschedule any previous timeouts */ unschedule_menu_popup_timeout (self); self->priv->popup_timeout_id = g_timeout_add (MENU_POPUP_TIMEOUT, popup_menu_timeout_cb, self); } /* Performs the given action using a new tab, if the selected action supports this. In this case TRUE is returned. */ static gboolean new_tab_action (NemoNavigationAction *self) { NemoWindow *window; window = self->priv->window; switch (self->priv->direction) { case NEMO_NAVIGATION_DIRECTION_FORWARD: nemo_window_back_or_forward (window, FALSE, 0, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); break; case NEMO_NAVIGATION_DIRECTION_BACK: nemo_window_back_or_forward (window, TRUE, 0, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); break; case NEMO_NAVIGATION_DIRECTION_UP: nemo_window_slot_go_up (nemo_window_get_active_slot (window), NEMO_WINDOW_OPEN_FLAG_NEW_TAB); break; /* remaining actions are not supported */ case NEMO_NAVIGATION_DIRECTION_RELOAD: case NEMO_NAVIGATION_DIRECTION_HOME: case NEMO_NAVIGATION_DIRECTION_COMPUTER: case NEMO_NAVIGATION_DIRECTION_EDIT: return FALSE; break; default: return FALSE; } return TRUE; } /* Checks if, given the event, the action should be performed in a new tab. */ static gboolean is_new_tab_event(GdkEventButton *event) { /* When double clicking with the middle bouse button, tool_button_press_cb is called three instead of two times. Handle the current event as new_tab_action only if it's an actual button press to prevent calling new_tab_action the third time. */ return (event->button == 2 || (event->button == 1 && event->state & GDK_CONTROL_MASK)) && event->type == GDK_BUTTON_PRESS; } static gboolean tool_button_press_cb (GtkButton *button, GdkEventButton *event, gpointer user_data) { NemoNavigationAction *self = user_data; if (event->button == 3) { /* right click */ show_menu (self, event->button, event->time); return TRUE; } if (is_new_tab_event (event) && new_tab_action (self)) { /* it was a valid new_tab_action -> event is handled */ return TRUE; } if (event->button == 1) { schedule_menu_popup_timeout (self); } return FALSE; } static gboolean tool_button_release_cb (GtkButton *button, GdkEventButton *event, gpointer user_data) { NemoNavigationAction *self = user_data; unschedule_menu_popup_timeout (self); return FALSE; } static void connect_proxy (GtkAction *action, GtkWidget *proxy) { if (GTK_IS_BUTTON (proxy)) { g_signal_connect (proxy, "button-press-event", G_CALLBACK (tool_button_press_cb), action); g_signal_connect (proxy, "button-release-event", G_CALLBACK (tool_button_release_cb), action); } (* GTK_ACTION_CLASS (nemo_navigation_action_parent_class)->connect_proxy) (action, proxy); } static void disconnect_proxy (GtkAction *action, GtkWidget *proxy) { if (GTK_IS_BUTTON (proxy)) { /* remove any possible timeout going on */ unschedule_menu_popup_timeout (NEMO_NAVIGATION_ACTION (action)); g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (tool_button_press_cb), action); g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (tool_button_release_cb), action); } (* GTK_ACTION_CLASS (nemo_navigation_action_parent_class)->disconnect_proxy) (action, proxy); } static void nemo_navigation_action_finalize (GObject *object) { NemoNavigationAction *action = NEMO_NAVIGATION_ACTION (object); /* remove any possible timeout going on */ unschedule_menu_popup_timeout (action); g_free (action->priv->arrow_tooltip); (* G_OBJECT_CLASS (nemo_navigation_action_parent_class)->finalize) (object); } static void nemo_navigation_action_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoNavigationAction *nav; nav = NEMO_NAVIGATION_ACTION (object); switch (prop_id) { case PROP_ARROW_TOOLTIP: g_free (nav->priv->arrow_tooltip); nav->priv->arrow_tooltip = g_value_dup_string (value); break; case PROP_DIRECTION: nav->priv->direction = g_value_get_int (value); break; case PROP_WINDOW: nav->priv->window = g_value_get_object (value); break; default: break; } } static void nemo_navigation_action_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NemoNavigationAction *nav; nav = NEMO_NAVIGATION_ACTION (object); switch (prop_id) { case PROP_ARROW_TOOLTIP: g_value_set_string (value, nav->priv->arrow_tooltip); break; case PROP_DIRECTION: g_value_set_int (value, nav->priv->direction); break; case PROP_WINDOW: g_value_set_object (value, nav->priv->window); break; default: break; } } static void nemo_navigation_action_class_init (NemoNavigationActionClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkActionClass *action_class = GTK_ACTION_CLASS (class); object_class->finalize = nemo_navigation_action_finalize; object_class->set_property = nemo_navigation_action_set_property; object_class->get_property = nemo_navigation_action_get_property; action_class->toolbar_item_type = GTK_TYPE_TOOL_BUTTON; action_class->connect_proxy = connect_proxy; action_class->disconnect_proxy = disconnect_proxy; g_object_class_install_property (object_class, PROP_ARROW_TOOLTIP, g_param_spec_string ("arrow-tooltip", "Arrow Tooltip", "Arrow Tooltip", NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_int ("direction", "Direction", "Direction", 0, G_MAXINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_WINDOW, g_param_spec_object ("window", "Window", "The navigation window", NEMO_TYPE_WINDOW, G_PARAM_READWRITE)); g_type_class_add_private (object_class, sizeof(NemoNavigationActionPrivate)); } static void nemo_navigation_action_init (NemoNavigationAction *action) { action->priv = NEMO_NAVIGATION_ACTION_GET_PRIVATE (action); } nemo-4.4.2/src/nemo-navigation-action.h000066400000000000000000000050401357442400300177660ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 2004 Red Hat, Inc. * Copyright (C) 2003 Marco Pesenti Gritti * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * * Based on ephy-navigation-action.h from Epiphany * * Authors: Alexander Larsson * Marco Pesenti Gritti * */ #ifndef NEMO_NAVIGATION_ACTION_H #define NEMO_NAVIGATION_ACTION_H #include #define NEMO_TYPE_NAVIGATION_ACTION (nemo_navigation_action_get_type ()) #define NEMO_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_NAVIGATION_ACTION, NemoNavigationAction)) #define NEMO_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_NAVIGATION_ACTION, NemoNavigationActionClass)) #define NEMO_IS_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_NAVIGATION_ACTION)) #define NEMO_IS_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NEMO_TYPE_NAVIGATION_ACTION)) #define NEMO_NAVIGATION_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NEMO_TYPE_NAVIGATION_ACTION, NemoNavigationActionClass)) typedef struct _NemoNavigationAction NemoNavigationAction; typedef struct _NemoNavigationActionClass NemoNavigationActionClass; typedef struct NemoNavigationActionPrivate NemoNavigationActionPrivate; typedef enum { NEMO_NAVIGATION_DIRECTION_BACK, NEMO_NAVIGATION_DIRECTION_FORWARD, NEMO_NAVIGATION_DIRECTION_UP, NEMO_NAVIGATION_DIRECTION_RELOAD, NEMO_NAVIGATION_DIRECTION_HOME, NEMO_NAVIGATION_DIRECTION_COMPUTER, NEMO_NAVIGATION_DIRECTION_EDIT, } NemoNavigationDirection; struct _NemoNavigationAction { GtkAction parent; /*< private >*/ NemoNavigationActionPrivate *priv; }; struct _NemoNavigationActionClass { GtkActionClass parent_class; }; GType nemo_navigation_action_get_type (void); #endif nemo-4.4.2/src/nemo-navigation-state.c000066400000000000000000000156661357442400300176430ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Nemo navigation state * * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi * */ #include #include "nemo-navigation-state.h" struct _NemoNavigationStateDetails { GtkActionGroup *slave; GtkActionGroup *master; GList *groups; gchar **action_names; GList *active_bindings; }; enum { PROP_SLAVE = 1, PROP_MASTER, PROP_ACTION_NAMES, NUM_PROPERTIES, }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoNavigationState, nemo_navigation_state, G_TYPE_OBJECT); static void clear_bindings (NemoNavigationState *self) { g_list_free_full (self->priv->active_bindings, g_object_unref); self->priv->active_bindings = NULL; } static void update_bindings (NemoNavigationState *self) { gint length, idx; GBinding *binding; GtkAction *master_action, *slave_action; length = g_strv_length (self->priv->action_names); for (idx = 0; idx < length; idx++) { master_action = gtk_action_group_get_action (self->priv->master, self->priv->action_names[idx]); slave_action = gtk_action_group_get_action (self->priv->slave, self->priv->action_names[idx]); if (!master_action || !slave_action) { continue; } binding = g_object_bind_property (master_action, "sensitive", slave_action, "sensitive", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); /* bind "active" too for toggle actions */ if (GTK_IS_TOGGLE_ACTION (master_action)) { binding = g_object_bind_property (master_action, "active", slave_action, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } self->priv->active_bindings = g_list_prepend (self->priv->active_bindings, binding); } } static void nemo_navigation_state_init (NemoNavigationState *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_NAVIGATION_STATE, NemoNavigationStateDetails); } static void nemo_navigation_state_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoNavigationState *self = NEMO_NAVIGATION_STATE (object); switch (property_id) { case PROP_SLAVE: self->priv->slave = g_value_dup_object (value); nemo_navigation_state_add_group (self, g_value_get_object (value)); break; case PROP_MASTER: self->priv->master = g_value_dup_object (value); break; case PROP_ACTION_NAMES: self->priv->action_names = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_navigation_state_finalize (GObject *obj) { NemoNavigationState *self = NEMO_NAVIGATION_STATE (obj); g_strfreev (self->priv->action_names); G_OBJECT_CLASS (nemo_navigation_state_parent_class)->finalize (obj); } static void nemo_navigation_state_dispose (GObject *obj) { NemoNavigationState *self = NEMO_NAVIGATION_STATE (obj); clear_bindings (self); g_clear_object (&self->priv->slave); g_clear_object (&self->priv->master); if (self->priv->groups != NULL) { g_list_free_full (self->priv->groups, g_object_unref); self->priv->groups = NULL; } G_OBJECT_CLASS (nemo_navigation_state_parent_class)->dispose (obj); } static void nemo_navigation_state_class_init (NemoNavigationStateClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->dispose = nemo_navigation_state_dispose; oclass->finalize = nemo_navigation_state_finalize; oclass->set_property = nemo_navigation_state_set_property; properties[PROP_SLAVE] = g_param_spec_object ("slave", "The slave GtkActionGroup", "The GtkActionGroup that will sync with the current master", GTK_TYPE_ACTION_GROUP, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); properties[PROP_MASTER] = g_param_spec_object ("master", "The master GtkActionGroup", "The GtkActionGroup that will be used to sync the slave", GTK_TYPE_ACTION_GROUP, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); properties[PROP_ACTION_NAMES] = g_param_spec_boxed ("action-names", "The action names to sync", "The action names to sync", G_TYPE_STRV, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); g_type_class_add_private (klass, sizeof (NemoNavigationStateDetails)); } NemoNavigationState * nemo_navigation_state_new (GtkActionGroup *slave, const gchar **action_names) { return g_object_new (NEMO_TYPE_NAVIGATION_STATE, "slave", slave, "action-names", action_names, NULL); } void nemo_navigation_state_set_master (NemoNavigationState *self, GtkActionGroup *master) { if (self->priv->master != master) { clear_bindings (self); g_clear_object (&self->priv->master); self->priv->master = g_object_ref (master); update_bindings (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MASTER]); } } void nemo_navigation_state_add_group (NemoNavigationState *self, GtkActionGroup *group) { self->priv->groups = g_list_prepend (self->priv->groups, g_object_ref (group)); } void nemo_navigation_state_sync_all (NemoNavigationState *self) { GList *l; gint length, idx; const gchar *action_name; GtkAction *action; gboolean master_value; GtkActionGroup *group; length = g_strv_length (self->priv->action_names); for (idx = 0; idx < length; idx++) { action_name = self->priv->action_names[idx]; action = gtk_action_group_get_action (self->priv->master, action_name); master_value = gtk_action_get_sensitive (action); for (l = self->priv->groups; l != NULL; l = l->next) { group = l->data; action = gtk_action_group_get_action (group, action_name); gtk_action_set_sensitive (action, master_value); } } } GtkActionGroup * nemo_navigation_state_get_master (NemoNavigationState *self) { return self->priv->master; } void nemo_navigation_state_set_boolean (NemoNavigationState *self, const gchar *action_name, gboolean value) { GtkAction *action; action = gtk_action_group_get_action (self->priv->master, action_name); if (action == NULL) { return; } gtk_action_set_sensitive (action, value); } nemo-4.4.2/src/nemo-navigation-state.h000066400000000000000000000055521357442400300176410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* Nemo - Nemo navigation state * * Copyright (C) 2011 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Cosimo Cecchi * */ #ifndef __NEMO_NAVIGATION_STATE_H__ #define __NEMO_NAVIGATION_STATE_H__ #include #include #define NEMO_TYPE_NAVIGATION_STATE nemo_navigation_state_get_type() #define NEMO_NAVIGATION_STATE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_NAVIGATION_STATE, NemoNavigationState)) #define NEMO_NAVIGATION_STATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_NAVIGATION_STATE, NemoNavigationStateClass)) #define NEMO_IS_NAVIGATION_STATE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_NAVIGATION_STATE)) #define NEMO_IS_NAVIGATION_STATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_NAVIGATION_STATE)) #define NEMO_NAVIGATION_STATE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_NAVIGATION_STATE, NemoNavigationStateClass)) typedef struct _NemoNavigationState NemoNavigationState; typedef struct _NemoNavigationStateClass NemoNavigationStateClass; typedef struct _NemoNavigationStateDetails NemoNavigationStateDetails; struct _NemoNavigationState { GObject parent; NemoNavigationStateDetails *priv; }; struct _NemoNavigationStateClass { GObjectClass parent_class; }; /* GObject */ GType nemo_navigation_state_get_type (void); NemoNavigationState * nemo_navigation_state_new (GtkActionGroup *slave, const gchar **action_names); void nemo_navigation_state_add_group (NemoNavigationState *state, GtkActionGroup *group); void nemo_navigation_state_set_master (NemoNavigationState *state, GtkActionGroup *master); GtkActionGroup * nemo_navigation_state_get_master (NemoNavigationState *self); void nemo_navigation_state_sync_all (NemoNavigationState *state); void nemo_navigation_state_set_boolean (NemoNavigationState *self, const gchar *action_name, gboolean value); #endif /* __NEMO_NAVIGATION_STATE_H__ */ nemo-4.4.2/src/nemo-notebook.c000066400000000000000000000354721357442400300162030ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright © 2002 Christophe Fergeau * Copyright © 2003, 2004 Marco Pesenti Gritti * Copyright © 2003, 2004, 2005 Christian Persch * (ephy-notebook.c) * * Copyright © 2008 Free Software Foundation, Inc. * (nemo-notebook.c) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include "nemo-notebook.h" #include "nemo-window.h" #include "nemo-window-manage-views.h" #include "nemo-window-private.h" #include "nemo-window-slot.h" #include "nemo-window-slot-dnd.h" #include #include #include #define AFTER_ALL_TABS -1 #define NOT_IN_APP_WINDOWS -2 static int nemo_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label, int position); static void nemo_notebook_remove (GtkContainer *container, GtkWidget *tab_widget); enum { TAB_CLOSE_REQUEST, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (NemoNotebook, nemo_notebook, GTK_TYPE_NOTEBOOK); static void nemo_notebook_class_init (NemoNotebookClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass); container_class->remove = nemo_notebook_remove; notebook_class->insert_page = nemo_notebook_insert_page; signals[TAB_CLOSE_REQUEST] = g_signal_new ("tab-close-request", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoNotebookClass, tab_close_request), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NEMO_TYPE_WINDOW_SLOT); } /* FIXME remove when gtknotebook's func for this becomes public, bug #.... */ static NemoNotebook * find_notebook_at_pointer (gint abs_x, gint abs_y) { GdkDeviceManager *manager; GdkDevice *pointer; GdkWindow *win_at_pointer, *toplevel_win; gpointer toplevel = NULL; gint x, y; /* FIXME multi-head */ manager = gdk_display_get_device_manager (gdk_display_get_default ()); pointer = gdk_device_manager_get_client_pointer (manager); win_at_pointer = gdk_device_get_window_at_position (pointer, &x, &y); if (win_at_pointer == NULL) { /* We are outside all windows containing a notebook */ return NULL; } toplevel_win = gdk_window_get_toplevel (win_at_pointer); /* get the GtkWidget which owns the toplevel GdkWindow */ gdk_window_get_user_data (toplevel_win, &toplevel); /* toplevel should be an NemoWindow */ if (toplevel != NULL && NEMO_IS_WINDOW (toplevel)) { return NEMO_NOTEBOOK (NEMO_WINDOW (toplevel)->details->active_pane->notebook); } return NULL; } static gboolean is_in_notebook_window (NemoNotebook *notebook, gint abs_x, gint abs_y) { NemoNotebook *nb_at_pointer; nb_at_pointer = find_notebook_at_pointer (abs_x, abs_y); return nb_at_pointer == notebook; } gint nemo_notebook_find_tab_num_at_pos (NemoNotebook *notebook, gint abs_x, gint abs_y) { GtkPositionType tab_pos; int page_num = 0; GtkNotebook *nb = GTK_NOTEBOOK (notebook); GtkWidget *page; GtkAllocation allocation; tab_pos = gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook)); if (gtk_notebook_get_n_pages (nb) == 0) { return AFTER_ALL_TABS; } /* For some reason unfullscreen + quick click can cause a wrong click event to be reported to the tab */ if (!is_in_notebook_window(notebook, abs_x, abs_y)) { return NOT_IN_APP_WINDOWS; } while ((page = gtk_notebook_get_nth_page (nb, page_num))) { GtkWidget *tab; gint max_x, max_y; gint x_root, y_root; tab = gtk_notebook_get_tab_label (nb, page); g_return_val_if_fail (tab != NULL, -1); if (!gtk_widget_get_mapped (GTK_WIDGET (tab))) { page_num++; continue; } gdk_window_get_origin (gtk_widget_get_window (tab), &x_root, &y_root); gtk_widget_get_allocation (tab, &allocation); max_x = x_root + allocation.x + allocation.width; max_y = y_root + allocation.y + allocation.height; if (((tab_pos == GTK_POS_TOP) || (tab_pos == GTK_POS_BOTTOM)) &&(abs_x<=max_x)) { return page_num; } else if (((tab_pos == GTK_POS_LEFT) || (tab_pos == GTK_POS_RIGHT)) && (abs_y<=max_y)) { return page_num; } page_num++; } return AFTER_ALL_TABS; } static gboolean ctrl_key_is_down = FALSE; /* user_data = if this is a callback for a keydown (else a keyup) */ static gboolean control_key_checker_cb(NemoNotebook *notebook, GdkEventKey *event, gpointer user_data) { if (event->keyval == GDK_KEY_Control_L || event->keyval == GDK_KEY_Control_R) ctrl_key_is_down = GPOINTER_TO_INT (user_data); return FALSE; } static gboolean notebook_tab_shortcut_cb(NemoNotebook *notebook, GtkDirectionType direction, gpointer user_data) { /* the "focus" event is fired if tab/shift+tab is pressed, so we only * need to check if ctrl is pressed down here. */ if (ctrl_key_is_down) { /* change the selected tab. work out if we need to do any wrap-around */ int last = gtk_notebook_get_n_pages (GTK_NOTEBOOK(user_data)) - 1; int current = gtk_notebook_get_current_page (GTK_NOTEBOOK(user_data)); int next; if (direction) next = (current == 0 ? last : current - 1); else next = (current == last ? 0 : current + 1); gtk_notebook_set_current_page (GTK_NOTEBOOK(user_data), next); } return TRUE; } static void nemo_notebook_init (NemoNotebook *notebook) { gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); /* Make it so that pressing ctrl+tab/ctrl+shift+tab switches the currently * focused tab. */ /* Gtk internally gobbles up tab/shift+tab keyboard events for widget * focus switching but we can override this with a little trickery. */ g_signal_connect (notebook, "focus", G_CALLBACK(notebook_tab_shortcut_cb), (gpointer)notebook); g_signal_connect (notebook, "key-press-event", G_CALLBACK(control_key_checker_cb), GINT_TO_POINTER (TRUE)); g_signal_connect (notebook, "key-release-event", G_CALLBACK(control_key_checker_cb), GINT_TO_POINTER (FALSE)); } void nemo_notebook_sync_loading (NemoNotebook *notebook, NemoWindowSlot *slot) { GtkWidget *tab_label, *spinner, *icon; gboolean active; g_return_if_fail (NEMO_IS_NOTEBOOK (notebook)); g_return_if_fail (NEMO_IS_WINDOW_SLOT (slot)); tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), GTK_WIDGET (slot)); g_return_if_fail (GTK_IS_WIDGET (tab_label)); spinner = GTK_WIDGET (g_object_get_data (G_OBJECT (tab_label), "spinner")); icon = GTK_WIDGET (g_object_get_data (G_OBJECT (tab_label), "icon")); g_return_if_fail (spinner != NULL && icon != NULL); active = FALSE; g_object_get (spinner, "active", &active, NULL); if (active == slot->allow_stop) { return; } if (slot->allow_stop) { gtk_widget_hide (icon); gtk_widget_show (spinner); gtk_spinner_start (GTK_SPINNER (spinner)); } else { gtk_spinner_stop (GTK_SPINNER (spinner)); gtk_widget_hide (spinner); gtk_widget_show (icon); } } void nemo_notebook_sync_tab_label (NemoNotebook *notebook, NemoWindowSlot *slot) { GtkWidget *hbox, *label; char *location_name; g_return_if_fail (NEMO_IS_NOTEBOOK (notebook)); g_return_if_fail (NEMO_IS_WINDOW_SLOT (slot)); hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), GTK_WIDGET (slot)); g_return_if_fail (GTK_IS_WIDGET (hbox)); label = GTK_WIDGET (g_object_get_data (G_OBJECT (hbox), "label")); g_return_if_fail (GTK_IS_WIDGET (label)); gtk_label_set_text (GTK_LABEL (label), slot->title); if (slot->location != NULL) { /* Set the tooltip on the label's parent (the tab label hbox), * so it covers all of the tab label. */ location_name = g_file_get_parse_name (slot->location); gtk_widget_set_tooltip_text (gtk_widget_get_parent (label), location_name); g_free (location_name); } else { gtk_widget_set_tooltip_text (gtk_widget_get_parent (label), NULL); } } static void close_button_clicked_cb (GtkWidget *widget, NemoWindowSlot *slot) { GtkWidget *notebook; notebook = gtk_widget_get_ancestor (GTK_WIDGET (slot), NEMO_TYPE_NOTEBOOK); if (notebook != NULL) { g_signal_emit (notebook, signals[TAB_CLOSE_REQUEST], 0, slot); } } static GtkWidget * build_tab_label (NemoNotebook *nb, NemoWindowSlot *slot) { GtkWidget *hbox, *label, *close_button, *image, *spinner, *icon; /* set hbox spacing and label padding (see below) so that there's an * equal amount of space around the label */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); gtk_widget_show (hbox); /* setup load feedback */ spinner = gtk_spinner_new (); gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0); /* setup site icon, empty by default */ icon = gtk_image_new (); gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0); /* don't show the icon */ /* setup label */ label = gtk_label_new (NULL); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_misc_set_padding (GTK_MISC (label), 0, 0); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_widget_show (label); /* setup close button */ close_button = gtk_button_new (); gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); /* don't allow focus on the close button */ gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE); gtk_widget_set_name (close_button, "nemo-tab-close-button"); image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_set_tooltip_text (close_button, _("Close tab")); g_signal_connect_object (close_button, "clicked", G_CALLBACK (close_button_clicked_cb), slot, 0); gtk_container_add (GTK_CONTAINER (close_button), image); gtk_widget_show (image); gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); gtk_widget_show (close_button); nemo_drag_slot_proxy_init (hbox, NULL, slot); g_object_set_data (G_OBJECT (hbox), "label", label); g_object_set_data (G_OBJECT (hbox), "spinner", spinner); g_object_set_data (G_OBJECT (hbox), "icon", icon); g_object_set_data (G_OBJECT (hbox), "close-button", close_button); return hbox; } static int nemo_notebook_insert_page (GtkNotebook *gnotebook, GtkWidget *tab_widget, GtkWidget *tab_label, GtkWidget *menu_label, int position) { g_assert (GTK_IS_WIDGET (tab_widget)); position = GTK_NOTEBOOK_CLASS (nemo_notebook_parent_class)->insert_page (gnotebook, tab_widget, tab_label, menu_label, position); gtk_notebook_set_show_tabs (gnotebook, gtk_notebook_get_n_pages (gnotebook) > 1); gtk_notebook_set_tab_reorderable (gnotebook, tab_widget, TRUE); gtk_notebook_set_tab_detachable (gnotebook, tab_widget, TRUE); return position; } int nemo_notebook_add_tab (NemoNotebook *notebook, NemoWindowSlot *slot, int position, gboolean jump_to) { GtkNotebook *gnotebook = GTK_NOTEBOOK (notebook); GtkWidget *tab_label; g_return_val_if_fail (NEMO_IS_NOTEBOOK (notebook), -1); g_return_val_if_fail (NEMO_IS_WINDOW_SLOT (slot), -1); tab_label = build_tab_label (notebook, slot); position = gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), GTK_WIDGET (slot), tab_label, position); gtk_container_child_set (GTK_CONTAINER (notebook), GTK_WIDGET (slot), "tab-expand", TRUE, NULL); nemo_notebook_sync_tab_label (notebook, slot); nemo_notebook_sync_loading (notebook, slot); /* FIXME gtk bug! */ /* FIXME: this should be fixed in gtk 2.12; check & remove this! */ /* The signal handler may have reordered the tabs */ position = gtk_notebook_page_num (gnotebook, GTK_WIDGET (slot)); if (jump_to) { gtk_notebook_set_current_page (gnotebook, position); } return position; } static void nemo_notebook_remove (GtkContainer *container, GtkWidget *tab_widget) { GtkNotebook *gnotebook = GTK_NOTEBOOK (container); GTK_CONTAINER_CLASS (nemo_notebook_parent_class)->remove (container, tab_widget); gtk_notebook_set_show_tabs (gnotebook, gtk_notebook_get_n_pages (gnotebook) > 1); } void nemo_notebook_reorder_child_relative (NemoNotebook *notebook, int page_num, int offset) { GtkNotebook *gnotebook; GtkWidget *page; g_return_if_fail (NEMO_IS_NOTEBOOK (notebook)); g_return_if_fail (page_num != -1); if (!nemo_notebook_can_reorder_child_relative ( notebook, page_num, offset)) { return; } gnotebook = GTK_NOTEBOOK (notebook); page = gtk_notebook_get_nth_page (gnotebook, page_num); g_return_if_fail (page != NULL); gtk_notebook_reorder_child (gnotebook, page, page_num + offset); } void nemo_notebook_set_current_page_relative (NemoNotebook *notebook, int offset) { GtkNotebook *gnotebook; int page; g_return_if_fail (NEMO_IS_NOTEBOOK (notebook)); if (!nemo_notebook_can_set_current_page_relative (notebook, offset)) { return; } gnotebook = GTK_NOTEBOOK (notebook); page = gtk_notebook_get_current_page (gnotebook); gtk_notebook_set_current_page (gnotebook, page + offset); } static gboolean nemo_notebook_is_valid_relative_position (NemoNotebook *notebook, int page_num, int offset) { GtkNotebook *gnotebook; int n_pages; gnotebook = GTK_NOTEBOOK (notebook); n_pages = gtk_notebook_get_n_pages (gnotebook) - 1; if (page_num < 0 || (offset < 0 && page_num < -offset) || (offset > 0 && page_num > n_pages - offset)) { return FALSE; } return TRUE; } gboolean nemo_notebook_can_reorder_child_relative (NemoNotebook *notebook, int page_num, int offset) { g_return_val_if_fail (NEMO_IS_NOTEBOOK (notebook), FALSE); return nemo_notebook_is_valid_relative_position ( notebook, page_num, offset); } gboolean nemo_notebook_can_set_current_page_relative (NemoNotebook *notebook, int offset) { int page_num; g_return_val_if_fail (NEMO_IS_NOTEBOOK (notebook), FALSE); page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); return nemo_notebook_is_valid_relative_position ( notebook, page_num, offset); } nemo-4.4.2/src/nemo-notebook.h000066400000000000000000000060621357442400300162010ustar00rootroot00000000000000/* * Copyright © 2002 Christophe Fergeau * Copyright © 2003 Marco Pesenti Gritti * Copyright © 2003, 2004 Christian Persch * (ephy-notebook.c) * * Copyright © 2008 Free Software Foundation, Inc. * (nemo-notebook.c) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id: nemo-notebook.h 8210 2008-04-11 20:05:25Z chpe $ */ #ifndef NEMO_NOTEBOOK_H #define NEMO_NOTEBOOK_H #include #include #include "nemo-window-slot.h" G_BEGIN_DECLS #define NEMO_TYPE_NOTEBOOK (nemo_notebook_get_type ()) #define NEMO_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_NOTEBOOK, NemoNotebook)) #define NEMO_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_NOTEBOOK, NemoNotebookClass)) #define NEMO_IS_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_NOTEBOOK)) #define NEMO_IS_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_NOTEBOOK)) #define NEMO_NOTEBOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_NOTEBOOK, NemoNotebookClass)) typedef struct _NemoNotebookClass NemoNotebookClass; typedef struct _NemoNotebook NemoNotebook; struct _NemoNotebook { GtkNotebook parent; }; struct _NemoNotebookClass { GtkNotebookClass parent_class; /* Signals */ void (* tab_close_request) (NemoNotebook *notebook, NemoWindowSlot *slot); }; GType nemo_notebook_get_type (void); int nemo_notebook_add_tab (NemoNotebook *nb, NemoWindowSlot *slot, int position, gboolean jump_to); gint nemo_notebook_find_tab_num_at_pos (NemoNotebook *nb, gint abs_x, gint abs_y); void nemo_notebook_set_show_tabs (NemoNotebook *nb, gboolean show_tabs); void nemo_notebook_set_dnd_enabled (NemoNotebook *nb, gboolean enabled); void nemo_notebook_sync_tab_label (NemoNotebook *nb, NemoWindowSlot *slot); void nemo_notebook_sync_loading (NemoNotebook *nb, NemoWindowSlot *slot); void nemo_notebook_reorder_child_relative (NemoNotebook *notebook, int page_num, int offset); void nemo_notebook_set_current_page_relative (NemoNotebook *notebook, int offset); gboolean nemo_notebook_can_reorder_child_relative (NemoNotebook *notebook, int page_num, int offset); gboolean nemo_notebook_can_set_current_page_relative (NemoNotebook *notebook, int offset); G_END_DECLS #endif /* NEMO_NOTEBOOK_H */ nemo-4.4.2/src/nemo-open-with-main.c000066400000000000000000000127471357442400300172170ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-open-with-main.c - Start the "Open with" dialog. * Nemo * * Copyright (C) 2005 Vincent Untz * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: * Vincent Untz * Cosimo Cecchi */ #include #include #include #include #include #include #include #include #include #include #include #include static void main_dialog_destroyed (GtkWidget *widget, gpointer user_data) { /* this only happens when user clicks "cancel" * on the main dialog or when we are all done. */ gtk_main_quit (); } static void app_chooser_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { NemoFile *file; GAppInfo *info; GList files; if (response_id != GTK_RESPONSE_OK) { gtk_widget_destroy (GTK_WIDGET (dialog)); return; } NemoMimeApplicationChooser *chooser = NEMO_MIME_APPLICATION_CHOOSER (user_data); info = nemo_mime_application_chooser_get_info (chooser); file = nemo_file_get_by_uri (nemo_mime_application_chooser_get_uri (chooser)); files.next = NULL; files.prev = NULL; files.data = file; nemo_launch_application (info, &files, NULL); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (info); } int main (int argc, char *argv[]) { GtkWidget *dialog; GtkWidget *ok_button; GOptionContext *context; GError *error; const GOptionEntry options[] = { { NULL } }; bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); error = NULL; /* Translators: This is the --help description for the open-with app, the initial newlines are between the command line arg and the description */ context = g_option_context_new (N_("\n\nShow an open-with dialog given a uri, " "to allow the user to change the default mimetype handler.")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_critical ("Failed to parse arguments: %s", error->message); g_error_free (error); g_option_context_free (context); exit (1); } g_option_context_free (context); if (argc != 2) { g_critical ("uri required"); exit(1); } nemo_global_preferences_init (); const gchar *uri, *basename; gchar *mime_type; uri = argv[1]; GFile *file = g_file_new_for_uri (uri); GFileInfo *info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (info == NULL) { g_critical ("Unable to query mimetype from given uri"); g_object_unref (info); g_object_unref (file); exit(1); } basename = g_file_get_basename (file); mime_type = nemo_get_best_guess_file_mimetype (basename, info, g_file_info_get_size (info)); g_clear_pointer (&basename, g_free); dialog = gtk_dialog_new_with_buttons (_("Open with"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); GtkWidget *chooser = nemo_mime_application_chooser_new (uri, NULL, mime_type, ok_button); eel_ref_str_unref (mime_type); GtkWidget *content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); gtk_box_pack_start (GTK_BOX (content), chooser, TRUE, TRUE, 0); gtk_widget_show_all (dialog); g_signal_connect_object (dialog, "response", G_CALLBACK (app_chooser_dialog_response_cb), chooser, 0); g_signal_connect (dialog, "destroy", G_CALLBACK (main_dialog_destroyed), NULL); gtk_widget_show (dialog); gtk_main (); return 0; } nemo-4.4.2/src/nemo-pathbar.c000066400000000000000000002103701357442400300157740ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-pathbar.c * Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include #include #include #include #include #include #include "nemo-pathbar.h" #include #include #include #include #include #include #include "nemo-window.h" #include "nemo-window-private.h" #include "nemo-window-slot.h" #include "nemo-window-slot-dnd.h" enum { PATH_CLICKED, PATH_SET, LAST_SIGNAL }; typedef enum { NORMAL_BUTTON, ROOT_BUTTON, HOME_BUTTON, DESKTOP_BUTTON, MOUNT_BUTTON, XDG_BUTTON, DEFAULT_LOCATION_BUTTON, } ButtonType; #define BUTTON_DATA(x) ((ButtonData *)(x)) #define SCROLL_TIMEOUT 150 #define INITIAL_SCROLL_TIMEOUT 300 static guint path_bar_signals [LAST_SIGNAL] = { 0 }; static gboolean desktop_is_home; #define NEMO_PATH_BAR_ICON_SIZE 16 #define NEMO_PATH_BAR_BUTTON_MAX_WIDTH 250 /* * Content of pathbar->button_list: * <- next previous -> * --------------------------------------------------------------------- * | / | home | user | downloads | folder | sub folder * --------------------------------------------------------------------- * last fake_root button_list * scrolled_root_button */ typedef struct { GtkWidget *button; ButtonType type; char *dir_name; GFile *path; NemoFile *file; unsigned int file_changed_signal_id; gchar *mount_icon_name; /* flag to indicate its the base folder in the URI */ gboolean is_base_dir; GtkWidget *image; GtkWidget *label; GtkWidget *alignment; guint ignore_changes : 1; guint fake_root : 1; } ButtonData; struct _NemoPathBarDetails { GtkContainer parent; GdkWindow *event_window; GFile *root_path; GFile *home_path; GFile *desktop_path; /** XDG Dirs */ GFile *xdg_documents_path; GFile *xdg_download_path; GFile *xdg_music_path; GFile *xdg_pictures_path; GFile *xdg_public_path; GFile *xdg_templates_path; GFile *xdg_videos_path; GFile *current_path; gpointer current_button_data; GList *button_list; GList *scrolled_root_button; GList *fake_root; GtkWidget *up_slider_button; GtkWidget *down_slider_button; guint settings_signal_id; gint slider_width; gint16 spacing; gint16 button_offset; guint timer; guint slider_visible : 1; guint need_timer : 1; guint ignore_click : 1; unsigned int drag_slider_timeout; gboolean drag_slider_timeout_for_up_button; }; G_DEFINE_TYPE (NemoPathBar, nemo_path_bar, GTK_TYPE_CONTAINER); static GFile* get_xdg_dir (GUserDirectory dir); static void nemo_path_bar_scroll_up (NemoPathBar *path_bar); static void nemo_path_bar_scroll_down (NemoPathBar *path_bar); static void nemo_path_bar_stop_scrolling (NemoPathBar *path_bar); static gboolean nemo_path_bar_slider_button_press (GtkWidget *widget, GdkEventButton *event, NemoPathBar *path_bar); static gboolean nemo_path_bar_slider_button_release (GtkWidget *widget, GdkEventButton *event, NemoPathBar *path_bar); static void nemo_path_bar_check_icon_theme (NemoPathBar *path_bar); static void nemo_path_bar_update_button_appearance (ButtonData *button_data); static void nemo_path_bar_update_button_state (ButtonData *button_data, gboolean current_dir); static gboolean nemo_path_bar_update_path (NemoPathBar *path_bar, GFile *file_path, gboolean emit_signal); static GtkWidget * get_slider_button (NemoPathBar *path_bar, GtkPositionType position) { GtkWidget *button; GtkWidget *image; gtk_widget_push_composite_child (); button = gtk_button_new (); gtk_style_context_add_class (gtk_widget_get_style_context (button), "slider-button"); gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE); gtk_widget_add_events (button, GDK_SCROLL_MASK); if (position == GTK_POS_LEFT) { image = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_MENU); } else { image = gtk_image_new_from_icon_name ("pan-end-symbolic", GTK_ICON_SIZE_MENU); } gtk_container_add (GTK_CONTAINER (button), image); gtk_container_add (GTK_CONTAINER (path_bar), button); gtk_widget_show_all (button); gtk_widget_pop_composite_child (); return button; } static void update_button_types (NemoPathBar *path_bar) { GList *list; GFile *path = NULL; for (list = path_bar->priv->button_list; list; list = list->next) { ButtonData *button_data; button_data = BUTTON_DATA (list->data); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button))) { path = g_object_ref (button_data->path); break; } } if (path != NULL) { nemo_path_bar_update_path (path_bar, path, TRUE); g_object_unref (path); } } static void desktop_location_changed_callback (gpointer user_data) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (user_data); g_object_unref (path_bar->priv->desktop_path); g_object_unref (path_bar->priv->home_path); path_bar->priv->desktop_path = nemo_get_desktop_location (); path_bar->priv->home_path = g_file_new_for_path (g_get_home_dir ()); desktop_is_home = g_file_equal (path_bar->priv->home_path, path_bar->priv->desktop_path); update_button_types (path_bar); } static gboolean slider_timeout (gpointer user_data) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (user_data); path_bar->priv->drag_slider_timeout = 0; if (gtk_widget_get_visible (GTK_WIDGET (path_bar))) { if (path_bar->priv->drag_slider_timeout_for_up_button) { nemo_path_bar_scroll_up (path_bar); } else { nemo_path_bar_scroll_down (path_bar); } } return FALSE; } static void nemo_path_bar_slider_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, unsigned int time, gpointer user_data) { NemoPathBar *path_bar; GtkSettings *settings; unsigned int timeout; path_bar = NEMO_PATH_BAR (user_data); if (path_bar->priv->drag_slider_timeout == 0) { settings = gtk_widget_get_settings (widget); g_object_get (settings, "gtk-timeout-expand", &timeout, NULL); path_bar->priv->drag_slider_timeout = g_timeout_add (timeout, slider_timeout, path_bar); path_bar->priv->drag_slider_timeout_for_up_button = widget == path_bar->priv->up_slider_button; } } static void nemo_path_bar_slider_drag_leave (GtkWidget *widget, GdkDragContext *context, unsigned int time, gpointer user_data) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (user_data); if (path_bar->priv->drag_slider_timeout != 0) { g_source_remove (path_bar->priv->drag_slider_timeout); path_bar->priv->drag_slider_timeout = 0; } } /** * Utility function. Return a GFile for the "special directory" if it exists, or NULL * Ripped from nemo-file.c (nemo_file_is_user_special_directory) and slightly modified */ static GFile* get_xdg_dir (GUserDirectory dir) { const gchar *special_dir; special_dir = g_get_user_special_dir (dir); if (special_dir) { return g_file_new_for_path (special_dir); } else { return NULL; } } static void nemo_path_bar_init (NemoPathBar *path_bar) { char *p; path_bar->priv = G_TYPE_INSTANCE_GET_PRIVATE (path_bar, NEMO_TYPE_PATH_BAR, NemoPathBarDetails); gtk_widget_set_has_window (GTK_WIDGET (path_bar), FALSE); gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE); path_bar->priv->up_slider_button = get_slider_button (path_bar, GTK_POS_LEFT); path_bar->priv->down_slider_button = get_slider_button (path_bar, GTK_POS_RIGHT); p = nemo_get_desktop_directory (); path_bar->priv->desktop_path = g_file_new_for_path (p); g_free (p); path_bar->priv->home_path = g_file_new_for_path (g_get_home_dir ()); path_bar->priv->root_path = g_file_new_for_path ("/"); path_bar->priv->xdg_documents_path = get_xdg_dir (G_USER_DIRECTORY_DOCUMENTS); path_bar->priv->xdg_download_path = get_xdg_dir (G_USER_DIRECTORY_DOWNLOAD); path_bar->priv->xdg_music_path = get_xdg_dir (G_USER_DIRECTORY_MUSIC); path_bar->priv->xdg_pictures_path = get_xdg_dir (G_USER_DIRECTORY_PICTURES); path_bar->priv->xdg_public_path = get_xdg_dir (G_USER_DIRECTORY_PUBLIC_SHARE); path_bar->priv->xdg_templates_path = get_xdg_dir (G_USER_DIRECTORY_TEMPLATES); path_bar->priv->xdg_videos_path = get_xdg_dir (G_USER_DIRECTORY_VIDEOS); desktop_is_home = g_file_equal (path_bar->priv->home_path, path_bar->priv->desktop_path); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_location_changed_callback), path_bar); g_signal_connect_swapped (path_bar->priv->up_slider_button, "clicked", G_CALLBACK (nemo_path_bar_scroll_up), path_bar); g_signal_connect_swapped (path_bar->priv->down_slider_button, "clicked", G_CALLBACK (nemo_path_bar_scroll_down), path_bar); g_signal_connect (path_bar->priv->up_slider_button, "button_press_event", G_CALLBACK (nemo_path_bar_slider_button_press), path_bar); g_signal_connect (path_bar->priv->up_slider_button, "button_release_event", G_CALLBACK (nemo_path_bar_slider_button_release), path_bar); g_signal_connect (path_bar->priv->down_slider_button, "button_press_event", G_CALLBACK (nemo_path_bar_slider_button_press), path_bar); g_signal_connect (path_bar->priv->down_slider_button, "button_release_event", G_CALLBACK (nemo_path_bar_slider_button_release), path_bar); gtk_drag_dest_set (GTK_WIDGET (path_bar->priv->up_slider_button), 0, NULL, 0, 0); gtk_drag_dest_set_track_motion (GTK_WIDGET (path_bar->priv->up_slider_button), TRUE); g_signal_connect (path_bar->priv->up_slider_button, "drag-motion", G_CALLBACK (nemo_path_bar_slider_drag_motion), path_bar); g_signal_connect (path_bar->priv->up_slider_button, "drag-leave", G_CALLBACK (nemo_path_bar_slider_drag_leave), path_bar); gtk_drag_dest_set (GTK_WIDGET (path_bar->priv->down_slider_button), 0, NULL, 0, 0); gtk_drag_dest_set_track_motion (GTK_WIDGET (path_bar->priv->up_slider_button), TRUE); g_signal_connect (path_bar->priv->down_slider_button, "drag-motion", G_CALLBACK (nemo_path_bar_slider_drag_motion), path_bar); g_signal_connect (path_bar->priv->down_slider_button, "drag-leave", G_CALLBACK (nemo_path_bar_slider_drag_leave), path_bar); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (path_bar)), GTK_STYLE_CLASS_LINKED); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (path_bar)), "path-bar"); } static void nemo_path_bar_finalize (GObject *object) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (object); nemo_path_bar_stop_scrolling (path_bar); if (path_bar->priv->drag_slider_timeout != 0) { g_source_remove (path_bar->priv->drag_slider_timeout); path_bar->priv->drag_slider_timeout = 0; } g_list_free (path_bar->priv->button_list); g_clear_object (&path_bar->priv->xdg_documents_path); g_clear_object (&path_bar->priv->xdg_download_path); g_clear_object (&path_bar->priv->xdg_music_path); g_clear_object (&path_bar->priv->xdg_pictures_path); g_clear_object (&path_bar->priv->xdg_public_path); g_clear_object (&path_bar->priv->xdg_templates_path); g_clear_object (&path_bar->priv->xdg_videos_path); g_signal_handlers_disconnect_by_func (nemo_preferences, desktop_location_changed_callback, path_bar); G_OBJECT_CLASS (nemo_path_bar_parent_class)->finalize (object); } /* Removes the settings signal handler. It's safe to call multiple times */ static void remove_settings_signal (NemoPathBar *path_bar, GdkScreen *screen) { if (path_bar->priv->settings_signal_id) { GtkSettings *settings; settings = gtk_settings_get_for_screen (screen); g_signal_handler_disconnect (settings, path_bar->priv->settings_signal_id); path_bar->priv->settings_signal_id = 0; } } static void nemo_path_bar_dispose (GObject *object) { remove_settings_signal (NEMO_PATH_BAR (object), gtk_widget_get_screen (GTK_WIDGET (object))); G_OBJECT_CLASS (nemo_path_bar_parent_class)->dispose (object); } /* Size requisition: * * Ideally, our size is determined by another widget, and we are just filling * available space. */ static void nemo_path_bar_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { ButtonData *button_data; NemoPathBar *path_bar; GList *list; gint child_height; gint height; gint child_min, child_nat; path_bar = NEMO_PATH_BAR (widget); *minimum = *natural = 0; height = 0; for (list = path_bar->priv->button_list; list; list = list->next) { button_data = BUTTON_DATA (list->data); gtk_widget_get_preferred_width (button_data->button, &child_min, &child_nat); gtk_widget_get_preferred_height (button_data->button, &child_height, NULL); height = MAX (height, child_height); *minimum = MAX (*minimum, child_min); *natural = MAX (*natural, child_nat); } gtk_widget_get_preferred_width (path_bar->priv->down_slider_button, &path_bar->priv->slider_width, NULL); *minimum += path_bar->priv->slider_width * 2; *natural += path_bar->priv->slider_width * 2; } static void nemo_path_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { ButtonData *button_data; NemoPathBar *path_bar; GList *list; gint child_min, child_nat; path_bar = NEMO_PATH_BAR (widget); *minimum = *natural = 0; for (list = path_bar->priv->button_list; list; list = list->next) { button_data = BUTTON_DATA (list->data); gtk_widget_get_preferred_height (button_data->button, &child_min, &child_nat); *minimum = MAX (*minimum, child_min); *natural = MAX (*natural, child_nat); } } static void nemo_path_bar_update_slider_buttons (NemoPathBar *path_bar) { if (path_bar->priv->button_list) { GtkWidget *button; button = BUTTON_DATA (path_bar->priv->button_list->data)->button; if (gtk_widget_get_child_visible (button)) { gtk_widget_set_sensitive (path_bar->priv->down_slider_button, FALSE); nemo_path_bar_stop_scrolling (path_bar); } else { gtk_widget_set_sensitive (path_bar->priv->down_slider_button, TRUE); } button = BUTTON_DATA (g_list_last (path_bar->priv->button_list)->data)->button; if (gtk_widget_get_child_visible (button)) { gtk_widget_set_sensitive (path_bar->priv->up_slider_button, FALSE); nemo_path_bar_stop_scrolling (path_bar); } else { gtk_widget_set_sensitive (path_bar->priv->up_slider_button, TRUE); } } } static void nemo_path_bar_unmap (GtkWidget *widget) { nemo_path_bar_stop_scrolling (NEMO_PATH_BAR (widget)); gdk_window_hide (NEMO_PATH_BAR (widget)->priv->event_window); GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->unmap (widget); } static void nemo_path_bar_map (GtkWidget *widget) { gdk_window_show (NEMO_PATH_BAR (widget)->priv->event_window); GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->map (widget); } static void child_ordering_changed (NemoPathBar *path_bar) { GList *l; if (path_bar->priv->up_slider_button) { gtk_style_context_invalidate (gtk_widget_get_style_context (path_bar->priv->up_slider_button)); } if (path_bar->priv->down_slider_button) { gtk_style_context_invalidate (gtk_widget_get_style_context (path_bar->priv->down_slider_button)); } for (l = path_bar->priv->button_list; l; l = l->next) { ButtonData *data = l->data; gtk_style_context_invalidate (gtk_widget_get_style_context (data->button)); } } /* This is a tad complicated */ static void nemo_path_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkWidget *child; NemoPathBar *path_bar; GtkTextDirection direction; GtkAllocation child_allocation; GList *list, *pathbar_root_button; gint width; gint width_min; gint largest_width; gboolean need_sliders; gint up_slider_offset; gint down_slider_offset; GtkRequisition child_requisition; GtkRequisition child_requisition_min; gboolean needs_reorder = FALSE; gint button_count = 0; need_sliders = TRUE; up_slider_offset = 0; down_slider_offset = 0; path_bar = NEMO_PATH_BAR (widget); gtk_widget_set_allocation (widget, allocation); if (gtk_widget_get_realized (widget)) { gdk_window_move_resize (path_bar->priv->event_window, allocation->x, allocation->y, allocation->width, allocation->height); } /* No path is set so we don't have to allocate anything. */ if (path_bar->priv->button_list == NULL) { return; } direction = gtk_widget_get_direction (widget); gtk_widget_get_preferred_width (path_bar->priv->up_slider_button, &path_bar->priv->slider_width, NULL); gtk_widget_get_preferred_size (BUTTON_DATA (path_bar->priv->button_list->data)->button, NULL, &child_requisition); width = child_requisition.width; for (list = path_bar->priv->button_list->next; list; list = list->next) { child = BUTTON_DATA (list->data)->button; gtk_widget_get_preferred_size (child, NULL, &child_requisition); width += child_requisition.width; if (list == path_bar->priv->fake_root) { width += path_bar->priv->slider_width; break; } } largest_width = allocation->width; if (width <= allocation->width && !need_sliders) { if (path_bar->priv->fake_root) { pathbar_root_button = path_bar->priv->fake_root; } else { pathbar_root_button = g_list_last (path_bar->priv->button_list); } } else { gboolean reached_end; gint slider_space; reached_end = FALSE; need_sliders = TRUE; slider_space = 2 * path_bar->priv->slider_width; largest_width -= slider_space; /* To see how much space we have, and how many buttons we can display. * We start at the first button, count forward until hit the new * button, then count backwards. */ /* First assume, we can only display one button */ if (path_bar->priv->scrolled_root_button) { pathbar_root_button = path_bar->priv->scrolled_root_button; } else { pathbar_root_button = path_bar->priv->button_list; } /* Count down the path chain towards the end. */ gtk_widget_get_preferred_size (BUTTON_DATA (pathbar_root_button->data)->button, NULL, &child_requisition); button_count = 1; width = child_requisition.width; /* Count down the path chain towards the end. */ list = pathbar_root_button->prev; while (list && !reached_end) { if (list == path_bar->priv->fake_root) { break; } child = BUTTON_DATA (list->data)->button; gtk_widget_get_preferred_size (child, NULL, &child_requisition); if (width + child_requisition.width + slider_space > allocation->width) { reached_end = TRUE; if (button_count == 1) { /* Display two Buttons if they fit shrinked */ gtk_widget_get_preferred_size (child, &child_requisition_min, NULL); width_min = child_requisition_min.width; gtk_widget_get_preferred_size (BUTTON_DATA (pathbar_root_button->data)->button, &child_requisition_min, NULL); width_min += child_requisition_min.width; if (width_min <= largest_width) { button_count++; largest_width /= 2; if (width < largest_width) { /* unused space for second button */ largest_width += largest_width - width; } else if (child_requisition.width < largest_width) { /* unused space for first button */ largest_width += largest_width - child_requisition.width; } } } } else { width += child_requisition.width; } list = list->prev; } /* Finally, we walk up, seeing how many of the previous buttons we can add*/ while (pathbar_root_button->next && ! reached_end) { if (pathbar_root_button == path_bar->priv->fake_root) { break; } child = BUTTON_DATA (pathbar_root_button->next->data)->button; gtk_widget_get_preferred_size (child, NULL, &child_requisition); if (width + child_requisition.width + slider_space > allocation->width) { reached_end = TRUE; if (button_count == 1) { gtk_widget_get_preferred_size (child, &child_requisition_min, NULL); width_min = child_requisition_min.width; gtk_widget_get_preferred_size (BUTTON_DATA (pathbar_root_button->data)->button, &child_requisition_min, NULL); width_min += child_requisition_min.width; if (width_min <= largest_width) { // Two shinked buttons fit pathbar_root_button = pathbar_root_button->next; button_count++; largest_width /= 2; if (width < largest_width) { /* unused space for second button */ largest_width += largest_width - width; } else if (child_requisition.width < largest_width) { /* unused space for first button */ largest_width += largest_width - child_requisition.width; } } } } else { width += child_requisition.width; pathbar_root_button = pathbar_root_button->next; button_count++; } } } /* Now, we allocate space to the buttons */ child_allocation.y = allocation->y; child_allocation.height = allocation->height; if (direction == GTK_TEXT_DIR_RTL) { child_allocation.x = allocation->x + allocation->width; if (need_sliders || path_bar->priv->fake_root) { child_allocation.x -= (path_bar->priv->slider_width); up_slider_offset = allocation->width - path_bar->priv->slider_width; } } else { child_allocation.x = allocation->x; if (need_sliders || path_bar->priv->fake_root) { up_slider_offset = 0; child_allocation.x += path_bar->priv->slider_width; } } for (list = pathbar_root_button; list; list = list->prev) { child = BUTTON_DATA (list->data)->button; gtk_widget_get_preferred_size (child, NULL, &child_requisition); child_allocation.width = MIN (child_requisition.width, largest_width); if (direction == GTK_TEXT_DIR_RTL) { child_allocation.x -= child_allocation.width; } /* Check to see if we've don't have any more space to allocate buttons */ if (need_sliders && direction == GTK_TEXT_DIR_RTL) { if (child_allocation.x - path_bar->priv->slider_width < allocation->x) { break; } } else { if (need_sliders && direction == GTK_TEXT_DIR_LTR) { if (child_allocation.x + child_allocation.width + path_bar->priv->slider_width > allocation->x + allocation->width) { break; } } } needs_reorder |= gtk_widget_get_child_visible (child) == FALSE; gtk_widget_set_child_visible (child, TRUE); gtk_widget_size_allocate (child, &child_allocation); if (direction == GTK_TEXT_DIR_RTL) { down_slider_offset = child_allocation.x - allocation->x - path_bar->priv->slider_width; } else { down_slider_offset += child_allocation.width; child_allocation.x += child_allocation.width; } } /* Now we go hide all the widgets that don't fit */ while (list) { child = BUTTON_DATA (list->data)->button; needs_reorder |= gtk_widget_get_child_visible (child) == TRUE; gtk_widget_set_child_visible (child, FALSE); list = list->prev; } if (BUTTON_DATA (pathbar_root_button->data)->fake_root) { path_bar->priv->fake_root = pathbar_root_button; } for (list = pathbar_root_button->next; list; list = list->next) { child = BUTTON_DATA (list->data)->button; needs_reorder |= gtk_widget_get_child_visible (child) == TRUE; gtk_widget_set_child_visible (child, FALSE); if (BUTTON_DATA (list->data)->fake_root) { path_bar->priv->fake_root = list; } } if (need_sliders || path_bar->priv->fake_root) { child_allocation.width = path_bar->priv->slider_width; child_allocation.x = up_slider_offset + allocation->x; gtk_widget_size_allocate (path_bar->priv->up_slider_button, &child_allocation); needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == FALSE; gtk_widget_set_child_visible (path_bar->priv->up_slider_button, TRUE); gtk_widget_show_all (path_bar->priv->up_slider_button); if (direction == GTK_TEXT_DIR_LTR) { down_slider_offset += path_bar->priv->slider_width; } } else { needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == TRUE; gtk_widget_set_child_visible (path_bar->priv->up_slider_button, FALSE); } if (need_sliders) { child_allocation.width = path_bar->priv->slider_width; child_allocation.x = down_slider_offset + allocation->x; gtk_widget_size_allocate (path_bar->priv->down_slider_button, &child_allocation); needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == FALSE; gtk_widget_set_child_visible (path_bar->priv->down_slider_button, TRUE); gtk_widget_show_all (path_bar->priv->down_slider_button); nemo_path_bar_update_slider_buttons (path_bar); } else { needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == TRUE; gtk_widget_set_child_visible (path_bar->priv->down_slider_button, FALSE); /* Reset Scrolling to have the left most folder in focus when resizing again */ path_bar->priv->scrolled_root_button = NULL; } if (needs_reorder) { child_ordering_changed (path_bar); } } static void nemo_path_bar_style_updated (GtkWidget *widget) { GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->style_updated (widget); nemo_path_bar_check_icon_theme (NEMO_PATH_BAR (widget)); } static void nemo_path_bar_screen_changed (GtkWidget *widget, GdkScreen *previous_screen) { if (GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->screen_changed) { GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->screen_changed (widget, previous_screen); } /* We might nave a new settings, so we remove the old one */ if (previous_screen) { remove_settings_signal (NEMO_PATH_BAR (widget), previous_screen); } nemo_path_bar_check_icon_theme (NEMO_PATH_BAR (widget)); } static gboolean nemo_path_bar_scroll (GtkWidget *widget, GdkEventScroll *event) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (widget); switch (event->direction) { case GDK_SCROLL_RIGHT: case GDK_SCROLL_DOWN: nemo_path_bar_scroll_down (path_bar); return TRUE; case GDK_SCROLL_LEFT: case GDK_SCROLL_UP: nemo_path_bar_scroll_up (path_bar); return TRUE; case GDK_SCROLL_SMOOTH: break; default: break; } return FALSE; } static void nemo_path_bar_realize (GtkWidget *widget) { NemoPathBar *path_bar; GtkAllocation allocation; GdkWindow *window; GdkWindowAttr attributes; gint attributes_mask; gtk_widget_set_realized (widget, TRUE); path_bar = NEMO_PATH_BAR (widget); window = gtk_widget_get_parent_window (widget); gtk_widget_set_window (widget, window); g_object_ref (window); gtk_widget_get_allocation (widget, &allocation); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y; path_bar->priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (path_bar->priv->event_window, widget); } static void nemo_path_bar_unrealize (GtkWidget *widget) { NemoPathBar *path_bar; path_bar = NEMO_PATH_BAR (widget); gdk_window_set_user_data (path_bar->priv->event_window, NULL); gdk_window_destroy (path_bar->priv->event_window); path_bar->priv->event_window = NULL; GTK_WIDGET_CLASS (nemo_path_bar_parent_class)->unrealize (widget); } static void nemo_path_bar_add (GtkContainer *container, GtkWidget *widget) { gtk_widget_set_parent (widget, GTK_WIDGET (container)); } static void nemo_path_bar_remove_1 (GtkContainer *container, GtkWidget *widget) { gboolean was_visible = gtk_widget_get_visible (widget); gtk_widget_unparent (widget); if (was_visible) { gtk_widget_queue_resize (GTK_WIDGET (container)); } } static void nemo_path_bar_remove (GtkContainer *container, GtkWidget *widget) { NemoPathBar *path_bar; GList *children; path_bar = NEMO_PATH_BAR (container); if (widget == path_bar->priv->up_slider_button) { nemo_path_bar_remove_1 (container, widget); path_bar->priv->up_slider_button = NULL; return; } if (widget == path_bar->priv->down_slider_button) { nemo_path_bar_remove_1 (container, widget); path_bar->priv->down_slider_button = NULL; return; } children = path_bar->priv->button_list; while (children) { if (widget == BUTTON_DATA (children->data)->button) { nemo_path_bar_remove_1 (container, widget); path_bar->priv->button_list = g_list_remove_link (path_bar->priv->button_list, children); g_list_free_1 (children); return; } children = children->next; } } static void nemo_path_bar_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { NemoPathBar *path_bar; GList *children; g_return_if_fail (callback != NULL); path_bar = NEMO_PATH_BAR (container); children = path_bar->priv->button_list; while (children) { GtkWidget *child; child = BUTTON_DATA (children->data)->button; children = children->next; (* callback) (child, callback_data); } if (path_bar->priv->up_slider_button) { (* callback) (path_bar->priv->up_slider_button, callback_data); } if (path_bar->priv->down_slider_button) { (* callback) (path_bar->priv->down_slider_button, callback_data); } } static void nemo_path_bar_grab_notify (GtkWidget *widget, gboolean was_grabbed) { if (!was_grabbed) { nemo_path_bar_stop_scrolling (NEMO_PATH_BAR (widget)); } } static void nemo_path_bar_state_changed (GtkWidget *widget, GtkStateType previous_state) { if (!gtk_widget_get_sensitive (widget)) { nemo_path_bar_stop_scrolling (NEMO_PATH_BAR (widget)); } } static GtkWidgetPath * nemo_path_bar_get_path_for_child (GtkContainer *container, GtkWidget *child) { NemoPathBar *path_bar = NEMO_PATH_BAR (container); GtkWidgetPath *path; path = gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (path_bar))); if (gtk_widget_get_visible (child) && gtk_widget_get_child_visible (child)) { GtkWidgetPath *sibling_path; GList *visible_children; GList *l; int pos; /* 1. Build the list of visible children, in visually left-to-right order * (i.e. independently of the widget's direction). Note that our * button_list is stored in innermost-to-outermost path order! */ visible_children = NULL; if (gtk_widget_get_visible (path_bar->priv->down_slider_button) && gtk_widget_get_child_visible (path_bar->priv->down_slider_button)) { visible_children = g_list_prepend (visible_children, path_bar->priv->down_slider_button); } for (l = path_bar->priv->button_list; l; l = l->next) { ButtonData *data = l->data; if (gtk_widget_get_visible (data->button) && gtk_widget_get_child_visible (data->button)) visible_children = g_list_prepend (visible_children, data->button); } if (gtk_widget_get_visible (path_bar->priv->up_slider_button) && gtk_widget_get_child_visible (path_bar->priv->up_slider_button)) { visible_children = g_list_prepend (visible_children, path_bar->priv->up_slider_button); } if (gtk_widget_get_direction (GTK_WIDGET (path_bar)) == GTK_TEXT_DIR_RTL) { visible_children = g_list_reverse (visible_children); } /* 2. Find the index of the child within that list */ pos = 0; for (l = visible_children; l; l = l->next) { GtkWidget *button = l->data; if (button == child) { break; } pos++; } /* 3. Build the path */ sibling_path = gtk_widget_path_new (); for (l = visible_children; l; l = l->next) { gtk_widget_path_append_for_widget (sibling_path, l->data); } gtk_widget_path_append_with_siblings (path, sibling_path, pos); g_list_free (visible_children); gtk_widget_path_unref (sibling_path); } else { gtk_widget_path_append_for_widget (path, child); } return path; } static void nemo_path_bar_class_init (NemoPathBarClass *path_bar_class) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; gobject_class = (GObjectClass *) path_bar_class; widget_class = (GtkWidgetClass *) path_bar_class; container_class = (GtkContainerClass *) path_bar_class; gobject_class->finalize = nemo_path_bar_finalize; gobject_class->dispose = nemo_path_bar_dispose; widget_class->get_preferred_height = nemo_path_bar_get_preferred_height; widget_class->get_preferred_width = nemo_path_bar_get_preferred_width; widget_class->realize = nemo_path_bar_realize; widget_class->unrealize = nemo_path_bar_unrealize; widget_class->unmap = nemo_path_bar_unmap; widget_class->map = nemo_path_bar_map; widget_class->size_allocate = nemo_path_bar_size_allocate; widget_class->style_updated = nemo_path_bar_style_updated; widget_class->screen_changed = nemo_path_bar_screen_changed; widget_class->grab_notify = nemo_path_bar_grab_notify; widget_class->state_changed = nemo_path_bar_state_changed; widget_class->scroll_event = nemo_path_bar_scroll; container_class->add = nemo_path_bar_add; container_class->forall = nemo_path_bar_forall; container_class->remove = nemo_path_bar_remove; container_class->get_path_for_child = nemo_path_bar_get_path_for_child; path_bar_signals [PATH_CLICKED] = g_signal_new ("path-clicked", G_OBJECT_CLASS_TYPE (path_bar_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NemoPathBarClass, path_clicked), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_FILE); path_bar_signals [PATH_SET] = g_signal_new ("path-set", G_OBJECT_CLASS_TYPE (path_bar_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NemoPathBarClass, path_set), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_FILE); gtk_container_class_handle_border_width (container_class); g_type_class_add_private (path_bar_class, sizeof (NemoPathBarDetails)); } static void nemo_path_bar_scroll_down (NemoPathBar *path_bar) { GList *list; GList *down_button; GList *up_button; gint space_available; gint space_needed; GtkTextDirection direction; GtkAllocation allocation, down_button_allocation, up_button_allocation, slider_allocation; down_button = NULL; up_button = NULL; if (path_bar->priv->ignore_click) { path_bar->priv->ignore_click = FALSE; return; } gtk_widget_queue_resize (GTK_WIDGET (path_bar)); direction = gtk_widget_get_direction (GTK_WIDGET (path_bar)); /* We find the button at the 'down' end, the non visible subfolder of * a visible folder, that we have to make visible */ for (list = path_bar->priv->button_list; list; list = list->next) { if (list->next && gtk_widget_get_child_visible (BUTTON_DATA (list->next->data)->button)) { down_button = list; break; } } if (down_button == NULL || down_button == path_bar->priv->button_list) { /* No Button visible or we scroll back to curren folder reset scrolling */ path_bar->priv->scrolled_root_button = NULL; return; } /* Find the last visible button on the 'up' end */ for (list = g_list_last (path_bar->priv->button_list); list; list = list->prev) { if (gtk_widget_get_child_visible (BUTTON_DATA (list->data)->button)) { up_button = list; break; } } gtk_widget_get_allocation (BUTTON_DATA (down_button->data)->button, &down_button_allocation); gtk_widget_get_allocation (GTK_WIDGET (path_bar), &allocation); gtk_widget_get_allocation (path_bar->priv->down_slider_button, &slider_allocation); space_needed = down_button_allocation.width; if (direction == GTK_TEXT_DIR_RTL) { space_available = slider_allocation.x - allocation.x; } else { space_available = (allocation.x + allocation.width) - (slider_allocation.x + slider_allocation.width); } /* We have space_available extra space that's not being used. We * need space_needed space to make the button fit. So we walk down * from the end, removing buttons until we get all the space we * need */ while ((space_available < space_needed) && (up_button != down_button)) { gtk_widget_get_allocation (BUTTON_DATA (up_button->data)->button, &up_button_allocation); space_available += up_button_allocation.width; up_button = up_button->prev; path_bar->priv->scrolled_root_button = up_button; } } static void nemo_path_bar_scroll_up (NemoPathBar *path_bar) { GList *list; if (path_bar->priv->ignore_click) { path_bar->priv->ignore_click = FALSE; return; } gtk_widget_queue_resize (GTK_WIDGET (path_bar)); /* scroll in parent folder direction */ for (list = g_list_last (path_bar->priv->button_list); list; list = list->prev) { if (list->prev && gtk_widget_get_child_visible (BUTTON_DATA (list->prev->data)->button)) { if (list->prev == path_bar->priv->fake_root) { path_bar->priv->fake_root = NULL; } path_bar->priv->scrolled_root_button = list; return; } } } static gboolean nemo_path_bar_scroll_timeout (NemoPathBar *path_bar) { gboolean retval = FALSE; if (path_bar->priv->timer) { if (gtk_widget_has_focus (path_bar->priv->up_slider_button)) { nemo_path_bar_scroll_up (path_bar); } else if (gtk_widget_has_focus (path_bar->priv->down_slider_button)) { nemo_path_bar_scroll_down (path_bar); } if (path_bar->priv->need_timer) { path_bar->priv->need_timer = FALSE; g_source_remove (path_bar->priv->timer); path_bar->priv->timer = g_timeout_add (SCROLL_TIMEOUT, (GSourceFunc)nemo_path_bar_scroll_timeout, path_bar); } else { retval = TRUE; } } return retval; } static void nemo_path_bar_stop_scrolling (NemoPathBar *path_bar) { if (path_bar->priv->timer) { g_source_remove (path_bar->priv->timer); path_bar->priv->timer = 0; path_bar->priv->need_timer = FALSE; } } static gboolean nemo_path_bar_slider_button_press (GtkWidget *widget, GdkEventButton *event, NemoPathBar *path_bar) { if (!gtk_widget_has_focus (widget)) { gtk_widget_grab_focus (widget); } if (event->type != GDK_BUTTON_PRESS || event->button != 1) { return FALSE; } path_bar->priv->ignore_click = FALSE; if (widget == path_bar->priv->up_slider_button) { nemo_path_bar_scroll_up (path_bar); } else if (widget == path_bar->priv->down_slider_button) { nemo_path_bar_scroll_down (path_bar); } if (!path_bar->priv->timer) { path_bar->priv->need_timer = TRUE; path_bar->priv->timer = g_timeout_add (INITIAL_SCROLL_TIMEOUT, (GSourceFunc)nemo_path_bar_scroll_timeout, path_bar); } return FALSE; } static gboolean nemo_path_bar_slider_button_release (GtkWidget *widget, GdkEventButton *event, NemoPathBar *path_bar) { if (event->type != GDK_BUTTON_RELEASE) { return FALSE; } path_bar->priv->ignore_click = TRUE; nemo_path_bar_stop_scrolling (path_bar); return FALSE; } /* Changes the icons wherever it is needed */ static void reload_icons (NemoPathBar *path_bar) { GList *list; for (list = path_bar->priv->button_list; list; list = list->next) { ButtonData *button_data; button_data = BUTTON_DATA (list->data); if (button_data->type != NORMAL_BUTTON || button_data->is_base_dir) { nemo_path_bar_update_button_appearance (button_data); } } } /* Callback used when a GtkSettings value changes */ static void settings_notify_cb (GObject *object, GParamSpec *pspec, NemoPathBar *path_bar) { const char *name; name = g_param_spec_get_name (pspec); if (! strcmp (name, "gtk-icon-theme-name") || ! strcmp (name, "gtk-icon-sizes")) { reload_icons (path_bar); } } static void nemo_path_bar_check_icon_theme (NemoPathBar *path_bar) { GtkSettings *settings; if (path_bar->priv->settings_signal_id) { return; } settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (path_bar))); path_bar->priv->settings_signal_id = g_signal_connect (settings, "notify", G_CALLBACK (settings_notify_cb), path_bar); reload_icons (path_bar); } /* Public functions and their helpers */ void nemo_path_bar_clear_buttons (NemoPathBar *path_bar) { while (path_bar->priv->button_list != NULL) { gtk_container_remove (GTK_CONTAINER (path_bar), BUTTON_DATA (path_bar->priv->button_list->data)->button); } path_bar->priv->scrolled_root_button = NULL; path_bar->priv->fake_root = NULL; } static void button_clicked_cb (GtkWidget *button, gpointer data) { ButtonData *button_data; NemoPathBar *path_bar; GList *button_list; button_data = BUTTON_DATA (data); if (button_data->ignore_changes) { return; } path_bar = NEMO_PATH_BAR (gtk_widget_get_parent (button)); button_list = g_list_find (path_bar->priv->button_list, button_data); g_assert (button_list != NULL); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0, button_data->path); } static void button_data_free (ButtonData *button_data) { g_object_unref (button_data->path); g_free (button_data->dir_name); g_clear_pointer (&button_data->mount_icon_name, g_free); if (button_data->file != NULL) { g_signal_handler_disconnect (button_data->file, button_data->file_changed_signal_id); nemo_file_monitor_remove (button_data->file, button_data); nemo_file_unref (button_data->file); } g_free (button_data); } static const char * get_dir_name (ButtonData *button_data) { if (button_data->type == DESKTOP_BUTTON) { return _("Desktop"); /* } * originally this would look like /home/Home/Desktop in the pathbar. * I can see the logic, when you're only staying in $HOME, i.e. Home/Desktop * but when you've come from a directory further up it just looks wrong. * } else if (button_data->type == HOME_BUTTON) { return _("Home");*/ } else { return button_data->dir_name; } } static void set_label_padding_size (ButtonData *button_data) { const gchar *dir_name = get_dir_name (button_data); PangoLayout *layout; gint width, height, bold_width, bold_height; gint pad_left, pad_right; gchar *markup; layout = gtk_widget_create_pango_layout (button_data->label, dir_name); pango_layout_get_pixel_size (layout, &width, &height); markup = g_markup_printf_escaped ("%s", dir_name); pango_layout_set_markup (layout, markup, -1); g_free (markup); pango_layout_get_pixel_size (layout, &bold_width, &bold_height); pad_left = (bold_width - width) / 2; pad_right = (bold_width - width) / 2; gtk_widget_set_margin_left (GTK_WIDGET (button_data->label), pad_left); gtk_widget_set_margin_right (GTK_WIDGET (button_data->label), pad_right); g_object_unref (layout); } static void nemo_path_bar_update_button_appearance (ButtonData *button_data) { gchar *icon_name; const gchar *dir_name = get_dir_name (button_data); if (button_data->label != NULL) { if (gtk_label_get_use_markup (GTK_LABEL (button_data->label))) { char *markup; markup = g_markup_printf_escaped ("%s", dir_name); gtk_label_set_markup (GTK_LABEL (button_data->label), markup); gtk_widget_set_margin_right (GTK_WIDGET (button_data->label), 0); gtk_widget_set_margin_left (GTK_WIDGET (button_data->label), 0); g_free(markup); } else { gtk_label_set_text (GTK_LABEL (button_data->label), dir_name); set_label_padding_size (button_data); } } icon_name = NULL; if (button_data->image != NULL) { switch (button_data->type) { case ROOT_BUTTON: icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FILESYSTEM); break; case HOME_BUTTON: case DESKTOP_BUTTON: case XDG_BUTTON: icon_name = nemo_file_get_control_icon_name (button_data->file); break; case NORMAL_BUTTON: if (button_data->is_base_dir) { icon_name = nemo_file_get_control_icon_name (button_data->file); break; } case DEFAULT_LOCATION_BUTTON: case MOUNT_BUTTON: if (button_data->mount_icon_name) { icon_name = g_strdup (button_data->mount_icon_name); break; } default: icon_name = NULL; } gtk_image_set_from_icon_name (GTK_IMAGE (button_data->image), icon_name, GTK_ICON_SIZE_MENU); g_free (icon_name); } } static void nemo_path_bar_update_button_state (ButtonData *button_data, gboolean current_dir) { if (button_data->label != NULL) { gtk_label_set_label (GTK_LABEL (button_data->label), NULL); gtk_label_set_use_markup (GTK_LABEL (button_data->label), current_dir); } nemo_path_bar_update_button_appearance (button_data); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir) { button_data->ignore_changes = TRUE; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir); button_data->ignore_changes = FALSE; } } static gboolean setup_file_path_mounted_mount (GFile *location, ButtonData *button_data) { GVolumeMonitor *volume_monitor; GList *mounts, *l; GMount *mount; gboolean result; GFile *root, *default_location; result = FALSE; volume_monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (volume_monitor); for (l = mounts; l != NULL; l = l->next) { mount = l->data; if (g_mount_is_shadowed (mount)) { continue; } if (result) { continue; } root = g_mount_get_root (mount); if (g_file_equal (location, root)) { result = TRUE; /* set mount specific details in button_data */ if (button_data) { button_data->mount_icon_name = nemo_get_mount_icon_name (mount); button_data->dir_name = g_mount_get_name (mount); button_data->type = MOUNT_BUTTON; button_data->fake_root = TRUE; } g_object_unref (root); break; } default_location = g_mount_get_default_location (mount); if (!g_file_equal (default_location, root) && g_file_equal (location, default_location)) { result = TRUE; /* set mount specific details in button_data */ if (button_data) { button_data->mount_icon_name = nemo_get_mount_icon_name (mount); button_data->type = DEFAULT_LOCATION_BUTTON; button_data->fake_root = TRUE; } g_object_unref (default_location); g_object_unref (root); break; } g_object_unref (default_location); g_object_unref (root); } g_list_free_full (mounts, g_object_unref); return result; } static void setup_button_type (ButtonData *button_data, NemoPathBar *path_bar, GFile *location) { if (nemo_is_root_directory (location)) { button_data->type = ROOT_BUTTON; } else if (nemo_is_home_directory (location)) { button_data->type = HOME_BUTTON; button_data->fake_root = TRUE; } else if (nemo_is_desktop_directory (location)) { if (!desktop_is_home) { button_data->type = DESKTOP_BUTTON; } else { button_data->type = NORMAL_BUTTON; } } else if (path_bar->priv->xdg_documents_path != NULL && g_file_equal (location, path_bar->priv->xdg_documents_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_download_path != NULL && g_file_equal (location, path_bar->priv->xdg_download_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_music_path != NULL && g_file_equal (location, path_bar->priv->xdg_music_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_pictures_path != NULL && g_file_equal (location, path_bar->priv->xdg_pictures_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_templates_path != NULL && g_file_equal (location, path_bar->priv->xdg_templates_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_videos_path != NULL && g_file_equal (location, path_bar->priv->xdg_videos_path)) { button_data->type = XDG_BUTTON; } else if (path_bar->priv->xdg_public_path != NULL && g_file_equal (location, path_bar->priv->xdg_public_path)) { button_data->type = XDG_BUTTON; } else if (setup_file_path_mounted_mount (location, button_data)) { /* already setup */ } else { button_data->type = NORMAL_BUTTON; } } static void button_drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time_, gpointer user_data) { ButtonData *button_data; char *uri_list[2]; char *tmp; button_data = user_data; uri_list[0] = g_file_get_uri (button_data->path); uri_list[1] = NULL; if (info == NEMO_ICON_DND_GNOME_ICON_LIST) { tmp = g_strdup_printf ("%s\r\n", uri_list[0]); gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (const guchar *) tmp, strlen (tmp)); g_free (tmp); } else if (info == NEMO_ICON_DND_URI_LIST) { gtk_selection_data_set_uris (selection_data, uri_list); } g_free (uri_list[0]); } static void setup_button_drag_source (ButtonData *button_data) { GtkTargetList *target_list; const GtkTargetEntry targets[] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST } }; gtk_drag_source_set (button_data->button, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, NULL, 0, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK); target_list = gtk_target_list_new (targets, G_N_ELEMENTS (targets)); gtk_target_list_add_uri_targets (target_list, NEMO_ICON_DND_URI_LIST); gtk_drag_source_set_target_list (button_data->button, target_list); gtk_target_list_unref (target_list); g_signal_connect (button_data->button, "drag-data-get", G_CALLBACK (button_drag_data_get_cb), button_data); } static void button_data_file_changed (NemoFile *file, ButtonData *button_data) { GFile *location, *current_location, *parent, *button_parent; ButtonData *current_button_data; char *display_name; NemoPathBar *path_bar; gboolean renamed, child; path_bar = (NemoPathBar *) gtk_widget_get_ancestor (button_data->button, NEMO_TYPE_PATH_BAR); if (path_bar == NULL) { return; } g_assert (path_bar->priv->current_path != NULL); g_assert (path_bar->priv->current_button_data != NULL); current_button_data = path_bar->priv->current_button_data; location = nemo_file_get_location (file); if (!g_file_equal (button_data->path, location)) { parent = g_file_get_parent (location); button_parent = g_file_get_parent (button_data->path); renamed = (parent != NULL && button_parent != NULL) && g_file_equal (parent, button_parent); if (parent != NULL) { g_object_unref (parent); } if (button_parent != NULL) { g_object_unref (button_parent); } if (renamed) { button_data->path = g_object_ref (location); } else { /* the file has been moved. * If it was below the currently displayed location, remove it. * If it was not below the currently displayed location, update the path bar */ child = g_file_has_prefix (button_data->path, path_bar->priv->current_path); if (child) { /* moved file inside current path hierarchy */ g_object_unref (location); location = g_file_get_parent (button_data->path); current_location = g_object_ref (path_bar->priv->current_path); } else { /* moved current path, or file outside current path hierarchy. * Update path bar to new locations. */ current_location = nemo_file_get_location (current_button_data->file); } nemo_path_bar_update_path (path_bar, location, FALSE); nemo_path_bar_set_path (path_bar, current_location); g_object_unref (location); g_object_unref (current_location); return; } } else if (nemo_file_is_gone (file)) { gint idx, position; /* if the current or a parent location are gone, don't do anything, as the view * will get the event too and call us back. */ current_location = nemo_file_get_location (current_button_data->file); if (g_file_has_prefix (location, current_location)) { /* remove this and the following buttons */ position = g_list_position (path_bar->priv->button_list, g_list_find (path_bar->priv->button_list, button_data)); if (position != -1) { for (idx = 0; idx <= position; idx++) { gtk_container_remove (GTK_CONTAINER (path_bar), BUTTON_DATA (path_bar->priv->button_list->data)->button); } } } g_object_unref (current_location); g_object_unref (location); return; } g_object_unref (location); /* MOUNTs use the GMount as the name, so don't update for those */ if (button_data->type != MOUNT_BUTTON) { display_name = nemo_file_get_display_name (file); if (g_strcmp0 (display_name, button_data->dir_name) != 0) { g_free (button_data->dir_name); button_data->dir_name = g_strdup (display_name); } g_free (display_name); } nemo_path_bar_update_button_appearance (button_data); } static ButtonData * make_directory_button (NemoPathBar *path_bar, NemoFile *file, gboolean current_dir, gboolean base_dir) { GFile *path; GtkWidget *child; ButtonData *button_data; gchar *uri; path = nemo_file_get_location (file); child = NULL; /* Is it a special button? */ button_data = g_new0 (ButtonData, 1); setup_button_type (button_data, path_bar, path); button_data->button = gtk_toggle_button_new (); gtk_style_context_add_class (gtk_widget_get_style_context (button_data->button), "text-button"); gtk_button_set_focus_on_click (GTK_BUTTON (button_data->button), FALSE); gtk_widget_add_events (button_data->button, GDK_SCROLL_MASK); /* TODO update button type when xdg directories change */ button_data->image = gtk_image_new (); switch (button_data->type) { case ROOT_BUTTON: child = button_data->image; button_data->label = NULL; break; case HOME_BUTTON: case DESKTOP_BUTTON: case MOUNT_BUTTON: case DEFAULT_LOCATION_BUTTON: button_data->label = gtk_label_new (NULL); child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); gtk_box_pack_start (GTK_BOX (child), button_data->image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (child), button_data->label, FALSE, FALSE, 0); break; case XDG_BUTTON: case NORMAL_BUTTON: default: button_data->label = gtk_label_new (NULL); child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); gtk_box_pack_start (GTK_BOX (child), button_data->image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (child), button_data->label, FALSE, FALSE, 0); button_data->is_base_dir = base_dir; } if (button_data->label != NULL) { gtk_label_set_ellipsize (GTK_LABEL (button_data->label), PANGO_ELLIPSIZE_MIDDLE); } if (button_data->path == NULL) { button_data->path = g_object_ref (path); } if (button_data->dir_name == NULL) { button_data->dir_name = nemo_file_get_display_name (file); } if (button_data->file == NULL) { button_data->file = nemo_file_ref (file); nemo_file_monitor_add (button_data->file, button_data, NEMO_FILE_ATTRIBUTES_FOR_ICON); button_data->file_changed_signal_id = g_signal_connect (button_data->file, "changed", G_CALLBACK (button_data_file_changed), button_data); } gtk_container_add (GTK_CONTAINER (button_data->button), child); gtk_widget_show_all (button_data->button); nemo_path_bar_update_button_state (button_data, current_dir); g_signal_connect (button_data->button, "clicked", G_CALLBACK (button_clicked_cb), button_data); g_object_weak_ref (G_OBJECT (button_data->button), (GWeakNotify) button_data_free, button_data); uri = g_file_get_uri (path); if (!eel_uri_is_search (uri)) { setup_button_drag_source (button_data); } g_clear_pointer (&uri, g_free); nemo_drag_slot_proxy_init (button_data->button, button_data->file, NULL); g_object_unref (path); return button_data; } static gboolean nemo_path_bar_check_parent_path (NemoPathBar *path_bar, GFile *location, ButtonData **current_button_data) { GList *list; GList *current_path; gboolean need_new_fake_root; current_path = NULL; need_new_fake_root = FALSE; if (current_button_data) { *current_button_data = NULL; } for (list = path_bar->priv->button_list; list; list = list->next) { ButtonData *button_data; button_data = list->data; if (g_file_equal (location, button_data->path)) { current_path = list; if (current_button_data) { *current_button_data = button_data; } break; } if (list == path_bar->priv->fake_root) { need_new_fake_root = TRUE; } } if (current_path) { if (need_new_fake_root) { path_bar->priv->fake_root = NULL; for (list = current_path; list; list = list->next) { ButtonData *button_data; button_data = list->data; if (list->prev != NULL && button_data->fake_root) { path_bar->priv->fake_root = list; break; } } } for (list = path_bar->priv->button_list; list; list = list->next) { nemo_path_bar_update_button_state (BUTTON_DATA (list->data), (list == current_path) ? TRUE : FALSE); } if (!gtk_widget_get_child_visible (BUTTON_DATA (current_path->data)->button)) { path_bar->priv->scrolled_root_button = current_path; gtk_widget_queue_resize (GTK_WIDGET (path_bar)); } return TRUE; } return FALSE; } static gboolean nemo_path_bar_update_path (NemoPathBar *path_bar, GFile *file_path, gboolean emit_signal) { NemoFile *file, *parent_file; gboolean first_directory, last_directory; gboolean result; GList *new_buttons, *l, *fake_root; ButtonData *button_data, *current_button_data; g_return_val_if_fail (NEMO_IS_PATH_BAR (path_bar), FALSE); g_return_val_if_fail (file_path != NULL, FALSE); fake_root = NULL; result = TRUE; first_directory = TRUE; new_buttons = NULL; current_button_data = NULL; file = nemo_file_get (file_path); gtk_widget_push_composite_child (); while (file != NULL) { parent_file = nemo_file_get_parent (file); last_directory = !parent_file; button_data = make_directory_button (path_bar, file, first_directory, last_directory); nemo_file_unref (file); if (first_directory) { current_button_data = button_data; } new_buttons = g_list_prepend (new_buttons, button_data); if (parent_file != NULL && button_data->fake_root) { fake_root = new_buttons; } file = parent_file; first_directory = FALSE; } nemo_path_bar_clear_buttons (path_bar); path_bar->priv->button_list = g_list_reverse (new_buttons); path_bar->priv->fake_root = fake_root; for (l = path_bar->priv->button_list; l; l = l->next) { GtkWidget *button; button = BUTTON_DATA (l->data)->button; gtk_container_add (GTK_CONTAINER (path_bar), button); } gtk_widget_pop_composite_child (); child_ordering_changed (path_bar); if (path_bar->priv->current_path != NULL) { g_object_unref (path_bar->priv->current_path); } path_bar->priv->current_path = g_object_ref (file_path); path_bar->priv->current_button_data = current_button_data; g_signal_emit (path_bar, path_bar_signals [PATH_SET], 0, file_path); return result; } gboolean nemo_path_bar_set_path (NemoPathBar *path_bar, GFile *file_path) { ButtonData *button_data; g_return_val_if_fail (NEMO_IS_PATH_BAR (path_bar), FALSE); g_return_val_if_fail (file_path != NULL, FALSE); /* Check whether the new path is already present in the pathbar as buttons. * This could be a parent directory or a previous selected subdirectory. */ if (nemo_path_bar_check_parent_path (path_bar, file_path, &button_data)) { if (path_bar->priv->current_path != NULL) { g_object_unref (path_bar->priv->current_path); } path_bar->priv->current_path = g_object_ref (file_path); path_bar->priv->current_button_data = button_data; return TRUE; } return nemo_path_bar_update_path (path_bar, file_path, TRUE); } GFile * nemo_path_bar_get_path_for_button (NemoPathBar *path_bar, GtkWidget *button) { GList *list; g_return_val_if_fail (NEMO_IS_PATH_BAR (path_bar), NULL); g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); for (list = path_bar->priv->button_list; list; list = list->next) { ButtonData *button_data; button_data = BUTTON_DATA (list->data); if (button_data->button == button) { return g_object_ref (button_data->path); } } return NULL; } nemo-4.4.2/src/nemo-pathbar.h000066400000000000000000000043371357442400300160050ustar00rootroot00000000000000/* nemo-pathbar.h * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * */ #ifndef NEMO_PATHBAR_H #define NEMO_PATHBAR_H #include #include typedef struct _NemoPathBar NemoPathBar; typedef struct _NemoPathBarClass NemoPathBarClass; typedef struct _NemoPathBarDetails NemoPathBarDetails; #define NEMO_TYPE_PATH_BAR (nemo_path_bar_get_type ()) #define NEMO_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PATH_BAR, NemoPathBar)) #define NEMO_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PATH_BAR, NemoPathBarClass)) #define NEMO_IS_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PATH_BAR)) #define NEMO_IS_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PATH_BAR)) #define NEMO_PATH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PATH_BAR, NemoPathBarClass)) struct _NemoPathBar { GtkContainer parent; NemoPathBarDetails *priv; }; struct _NemoPathBarClass { GtkContainerClass parent_class; void (* path_clicked) (NemoPathBar *path_bar, GFile *location); void (* path_set) (NemoPathBar *path_bar, GFile *location); }; GType nemo_path_bar_get_type (void) G_GNUC_CONST; gboolean nemo_path_bar_set_path (NemoPathBar *path_bar, GFile *file); GFile * nemo_path_bar_get_path_for_button (NemoPathBar *path_bar, GtkWidget *button); void nemo_path_bar_clear_buttons (NemoPathBar *path_bar); #endif /* NEMO_PATHBAR_H */ nemo-4.4.2/src/nemo-places-sidebar.c000066400000000000000000004131361357442400300172360ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* * Nemo * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Authors : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk) * Cosimo Cecchi * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nemo-application.h" #include "nemo-bookmark-list.h" #include "nemo-places-sidebar.h" #include "nemo-properties-window.h" #include "nemo-window.h" #include "nemo-window-slot.h" #include #define DEBUG_FLAG NEMO_DEBUG_PLACES #include #define EXPANDER_COLUMN_WIDTH 14 #define EXPANDER_PAD_COLUMN_WIDTH 4 #define EJECT_COLUMN_WIDTH 22 #define DRAG_EXPAND_CATEGORY_DELAY 500 #define EJECT_PAD_COLUMN_WIDTH 14 #if (!GLIB_CHECK_VERSION(2,50,0)) #define g_drive_is_removable g_drive_is_media_removable #endif typedef struct { GtkScrolledWindow parent; GtkTreeView *tree_view; GtkCellRenderer *eject_icon_cell_renderer; char *uri; GtkTreeStore *store; GtkTreeModel *store_filter; NemoWindow *window; NemoBookmarkList *bookmarks; GVolumeMonitor *volume_monitor; NemoActionManager *action_manager; guint action_manager_changed_id; GList *action_items; gboolean devices_header_added; gboolean bookmarks_header_added; /* DnD */ GList *drag_list; gboolean drag_data_received; int drag_data_info; gboolean drop_occured; gboolean in_drag; gchar *desktop_dnd_source_fs; gboolean desktop_dnd_can_delete_source; GtkWidget *popup_menu; GtkWidget *popup_menu_open_in_new_tab_item; GtkWidget *popup_menu_add_shortcut_item; GtkWidget *popup_menu_remove_item; GtkWidget *popup_menu_rename_item; GtkWidget *popup_menu_separator_item; GtkWidget *popup_menu_mount_item; GtkWidget *popup_menu_unmount_item; GtkWidget *popup_menu_eject_item; GtkWidget *popup_menu_rescan_item; GtkWidget *popup_menu_empty_trash_item; GtkWidget *popup_menu_start_item; GtkWidget *popup_menu_stop_item; GtkWidget *popup_menu_properties_separator_item; GtkWidget *popup_menu_properties_item; GtkWidget *popup_menu_action_separator_item; GtkWidget *popup_menu_remove_rename_separator_item; NemoFile *popup_file; guint popup_file_idle_handler; /* volume mounting - delayed open process */ gboolean mounting; NemoWindowSlot *go_to_after_mount_slot; NemoWindowOpenFlags go_to_after_mount_flags; NotifyNotification *unmount_notify; guint bookmarks_changed_id; gboolean my_computer_expanded; gboolean bookmarks_expanded; gboolean devices_expanded; gboolean network_expanded; gboolean updating_sidebar; /* Store the positions of the last * entry prior to bookmarks, and * the first entry after bookmarks * to allow drag and drop creation * of new bookmarks */ gchar *top_bookend_uri; gchar *bottom_bookend_uri; gint bookmark_breakpoint; guint expand_timeout_source; guint popup_menu_action_index; guint update_places_on_idle_id; } NemoPlacesSidebar; typedef struct { GtkScrolledWindowClass parent; } NemoPlacesSidebarClass; typedef struct { GObject parent; } NemoPlacesSidebarProvider; typedef struct { GObjectClass parent; } NemoPlacesSidebarProviderClass; typedef struct { NemoAction *action; NemoPlacesSidebar *sidebar; GtkWidget *item; } ActionPayload; enum { PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_SIDEBAR_COLUMN_URI, PLACES_SIDEBAR_COLUMN_DRIVE, PLACES_SIDEBAR_COLUMN_VOLUME, PLACES_SIDEBAR_COLUMN_MOUNT, PLACES_SIDEBAR_COLUMN_NAME, PLACES_SIDEBAR_COLUMN_ICON, PLACES_SIDEBAR_COLUMN_INDEX, PLACES_SIDEBAR_COLUMN_EJECT, PLACES_SIDEBAR_COLUMN_NO_EJECT, PLACES_SIDEBAR_COLUMN_BOOKMARK, PLACES_SIDEBAR_COLUMN_TOOLTIP, PLACES_SIDEBAR_COLUMN_EJECT_ICON, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, PLACES_SIDEBAR_COLUMN_HEADING_TEXT, PLACES_SIDEBAR_COLUMN_DF_PERCENT, PLACES_SIDEBAR_COLUMN_SHOW_DF, PLACES_SIDEBAR_COLUMN_COUNT }; typedef enum { PLACES_BUILT_IN, PLACES_XDG_DIR, PLACES_MOUNTED_VOLUME, PLACES_BOOKMARK, PLACES_HEADING, } PlaceType; typedef enum { SECTION_COMPUTER, SECTION_XDG_BOOKMARKS, SECTION_BOOKMARKS, SECTION_DEVICES, SECTION_NETWORK, } SectionType; enum { POSITION_UPPER, POSITION_MIDDLE, POSITION_LOWER }; static void open_selected_bookmark (NemoPlacesSidebar *sidebar, GtkTreeModel *model, GtkTreeIter *iter, NemoWindowOpenFlags flags); static void nemo_places_sidebar_style_set (GtkWidget *widget, GtkStyle *previous_style); static gboolean eject_or_unmount_bookmark (NemoPlacesSidebar *sidebar, GtkTreePath *path); static gboolean eject_or_unmount_selection (NemoPlacesSidebar *sidebar); static void check_unmount_and_eject (GMount *mount, GVolume *volume, GDrive *drive, gboolean *show_unmount, gboolean *show_eject); static void bookmarks_check_popup_sensitivity (NemoPlacesSidebar *sidebar); static void add_action_popup_items (NemoPlacesSidebar *sidebar); static void update_places (NemoPlacesSidebar *sidebar); static void update_places_on_idle (NemoPlacesSidebar *sidebar); /* Identifiers for target types */ enum { GTK_TREE_MODEL_ROW, TEXT_URI_LIST }; /* Target types for dragging from the shortcuts list */ static const GtkTargetEntry nemo_shortcuts_source_targets[] = { { (char *)"GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW } }; /* Target types for dropping into the shortcuts list */ static const GtkTargetEntry nemo_shortcuts_drop_targets [] = { { (char *)"GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }, { (char *)"text/uri-list", 0, TEXT_URI_LIST } }; /* Drag and drop interface declarations */ typedef struct { GtkTreeStore parent; NemoPlacesSidebar *sidebar; } NemoShortcutsModel; typedef struct { GtkTreeStoreClass parent_class; } NemoShortcutsModelClass; #define NEMO_TYPE_SHORTCUTS_MODEL (_nemo_shortcuts_model_get_type ()) #define NEMO_SHORTCUTS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_SHORTCUTS_MODEL_TYPE, NemoShortcutsModel)) GType _nemo_shortcuts_model_get_type (void); static void _nemo_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface); G_DEFINE_TYPE_WITH_CODE (NemoShortcutsModel, _nemo_shortcuts_model, GTK_TYPE_TREE_STORE, G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, _nemo_shortcuts_model_drag_source_init)); static GtkTreeStore *nemo_shortcuts_model_new (NemoPlacesSidebar *sidebar); G_DEFINE_TYPE (NemoPlacesSidebar, nemo_places_sidebar, GTK_TYPE_SCROLLED_WINDOW); static gint overlay_scrolling_enabled = -1; static gboolean get_overlay_scrolling_enabled (void) { if (overlay_scrolling_enabled > -1) { return overlay_scrolling_enabled == 1; } const gchar *val = g_getenv ("GTK_OVERLAY_SCROLLING"); if (val == NULL || g_strcmp0 (val, "0") == 0) { overlay_scrolling_enabled = 0; } else { overlay_scrolling_enabled = 1; } return overlay_scrolling_enabled == 1; } static void breakpoint_changed_cb (NemoPlacesSidebar *sidebar) { sidebar->bookmark_breakpoint = g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT); update_places (sidebar); } static void increment_bookmark_breakpoint (NemoPlacesSidebar *sidebar) { g_signal_handlers_block_by_func (nemo_window_state, breakpoint_changed_cb, sidebar); sidebar->bookmark_breakpoint ++; g_settings_set_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, sidebar->bookmark_breakpoint); g_signal_handlers_unblock_by_func (nemo_window_state, breakpoint_changed_cb, sidebar); } static void decrement_bookmark_breakpoint (NemoPlacesSidebar *sidebar) { g_signal_handlers_block_by_func (nemo_window_state, breakpoint_changed_cb, sidebar); sidebar->bookmark_breakpoint --; g_settings_set_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, sidebar->bookmark_breakpoint); g_signal_handlers_unblock_by_func (nemo_window_state, breakpoint_changed_cb, sidebar); } static gboolean should_show_desktop (void) { return g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_SHOW_DESKTOP) && !g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR); } static gboolean is_built_in_bookmark (NemoFile *file) { if (nemo_file_is_home (file)) { return TRUE; } if (nemo_file_is_desktop_directory (file) && should_show_desktop ()) return TRUE; else return FALSE; } static GtkTreeIter add_heading (NemoPlacesSidebar *sidebar, SectionType section_type, const gchar *title) { GtkTreeIter cat_iter; gtk_tree_store_append (sidebar->store, &cat_iter, NULL); gtk_tree_store_set (sidebar->store, &cat_iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_HEADING, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type, PLACES_SIDEBAR_COLUMN_HEADING_TEXT, title, PLACES_SIDEBAR_COLUMN_INDEX, -1, PLACES_SIDEBAR_COLUMN_EJECT, FALSE, PLACES_SIDEBAR_COLUMN_NO_EJECT, TRUE, -1); return cat_iter; } static GtkTreeIter check_heading_for_devices (NemoPlacesSidebar *sidebar, SectionType section_type, GtkTreeIter cat_iter) { if (section_type == SECTION_DEVICES) { if (!sidebar->devices_header_added) { cat_iter = add_heading (sidebar, SECTION_DEVICES, _("Devices")); sidebar->devices_header_added = TRUE; } } return cat_iter; } static GtkTreeIter add_place (NemoPlacesSidebar *sidebar, PlaceType place_type, SectionType section_type, const char *name, const char *icon, const char *uri, GDrive *drive, GVolume *volume, GMount *mount, int index, const char *tooltip, int df_percent, gboolean show_df_percent, GtkTreeIter cat_iter) { GtkTreeIter iter; gboolean show_eject, show_unmount; gboolean show_eject_button; cat_iter = check_heading_for_devices (sidebar, section_type, cat_iter); check_unmount_and_eject (mount, volume, drive, &show_unmount, &show_eject); if (show_unmount || show_eject) { g_assert (place_type != PLACES_BOOKMARK); } if (mount == NULL) { show_eject_button = FALSE; } else { show_eject_button = (show_unmount || show_eject); } gtk_tree_store_append (sidebar->store, &iter, &cat_iter); gtk_tree_store_set (sidebar->store, &iter, PLACES_SIDEBAR_COLUMN_ICON, icon, PLACES_SIDEBAR_COLUMN_NAME, name, PLACES_SIDEBAR_COLUMN_URI, uri, PLACES_SIDEBAR_COLUMN_DRIVE, drive, PLACES_SIDEBAR_COLUMN_VOLUME, volume, PLACES_SIDEBAR_COLUMN_MOUNT, mount, PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type, PLACES_SIDEBAR_COLUMN_INDEX, index, PLACES_SIDEBAR_COLUMN_EJECT, show_eject_button, PLACES_SIDEBAR_COLUMN_NO_EJECT, !show_eject_button, PLACES_SIDEBAR_COLUMN_BOOKMARK, place_type != PLACES_BOOKMARK, PLACES_SIDEBAR_COLUMN_TOOLTIP, tooltip, PLACES_SIDEBAR_COLUMN_EJECT_ICON, show_eject_button ? "media-eject-symbolic" : NULL, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type, PLACES_SIDEBAR_COLUMN_DF_PERCENT, df_percent, PLACES_SIDEBAR_COLUMN_SHOW_DF, show_df_percent, -1); return cat_iter; } typedef struct { const gchar *location; const gchar *last_uri; NemoPlacesSidebar *sidebar; GtkTreePath *path; } RestoreLocationData; static gboolean restore_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { RestoreLocationData *data = user_data; gchar *uri; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); if (g_strcmp0 (uri, data->last_uri) == 0 || g_strcmp0 (uri, data->location) == 0) { data->path = gtk_tree_path_copy (path); } g_free (uri); return (data->path != NULL); } static gboolean restore_expand_state_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { PlaceType place_type; SectionType section_type; NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (user_data); gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, -1); if (place_type == PLACES_HEADING) { if (section_type == SECTION_COMPUTER) { if (sidebar->my_computer_expanded) gtk_tree_view_expand_to_path (sidebar->tree_view, path); else gtk_tree_view_collapse_row (sidebar->tree_view, path); } else if (section_type == SECTION_BOOKMARKS) { if (sidebar->bookmarks_expanded) gtk_tree_view_expand_to_path (sidebar->tree_view, path); else gtk_tree_view_collapse_row (sidebar->tree_view, path); } else if (section_type == SECTION_DEVICES) { if (sidebar->devices_expanded) gtk_tree_view_expand_to_path (sidebar->tree_view, path); else gtk_tree_view_collapse_row (sidebar->tree_view, path); } else if (section_type == SECTION_NETWORK) { if (sidebar->network_expanded) gtk_tree_view_expand_to_path (sidebar->tree_view, path); else gtk_tree_view_collapse_row (sidebar->tree_view, path); } } return FALSE; } static void restore_expand_state (NemoPlacesSidebar *sidebar) { gtk_tree_model_foreach (GTK_TREE_MODEL (sidebar->store_filter), restore_expand_state_foreach, sidebar); } static void expand_or_collapse_category (NemoPlacesSidebar *sidebar, SectionType section_type, gboolean expand) { switch (section_type) { case SECTION_COMPUTER: sidebar->my_computer_expanded = expand; break; case SECTION_BOOKMARKS: sidebar->bookmarks_expanded = expand; break; case SECTION_DEVICES: sidebar->devices_expanded = expand; break; case SECTION_NETWORK: sidebar->network_expanded = expand; break; case SECTION_XDG_BOOKMARKS: default: break; } restore_expand_state (sidebar); } static void sidebar_update_restore_selection (NemoPlacesSidebar *sidebar, const gchar *location, const gchar *last_uri) { RestoreLocationData data; GtkTreeSelection *selection; data.location = location; data.last_uri = last_uri; data.sidebar = sidebar; data.path = NULL; gtk_tree_model_foreach (GTK_TREE_MODEL (sidebar->store_filter), restore_selection_foreach, &data); if (data.path != NULL) { selection = gtk_tree_view_get_selection (sidebar->tree_view); gtk_tree_selection_select_path (selection, data.path); gtk_tree_view_scroll_to_cell (sidebar->tree_view, data.path, NULL, TRUE, 0.5, 0.0); gtk_tree_path_free (data.path); } } static gint get_disk_full (GFile *file, gchar **tooltip_info) { GFileInfo *info; GError *error; guint64 k_used, k_total, k_free; gint df_percent; float fraction; int prefix; gchar *size_string; gchar *out_string; error = NULL; df_percent = -1; out_string = NULL; info = g_file_query_filesystem_info (file, "filesystem::*", NULL, &error); if (info != NULL) { k_used = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USED); k_total = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE); k_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); if (k_total > 0) { fraction = ((float) k_used / (float) k_total) * 100.0; df_percent = (gint) rintf(fraction); prefix = nemo_global_preferences_get_size_prefix_preference (); size_string = g_format_size_full (k_free, prefix); out_string = g_strdup_printf (_("Free space: %s"), size_string); g_free (size_string); } g_object_unref (info); } if (error != NULL) { g_printerr ("Couldn't get disk full info for: %s\n", error->message); g_clear_error (&error); } if (out_string == NULL) { out_string = g_strdup (" "); } *tooltip_info = out_string; return df_percent; } static gboolean home_on_different_fs (const gchar *home_uri) { GFile *home = g_file_new_for_uri (home_uri); GFile *root = g_file_new_for_uri ("file:///"); GFileInfo *home_info, *root_info; const gchar *home_id, *root_id; gboolean res; res = FALSE; home_info = g_file_query_info (home, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); root_info = g_file_query_info (root, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (home_info && root_info) { home_id = g_file_info_get_attribute_string (home_info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); root_id = g_file_info_get_attribute_string (root_info, G_FILE_ATTRIBUTE_ID_FILESYSTEM); res = g_strcmp0 (home_id, root_id) != 0; g_object_unref (home_info); g_object_unref (root_info); } else { if (home_info) g_object_unref (home_info); if (root_info) g_object_unref (root_info); } g_object_unref (home); g_object_unref (root); return res; } static gboolean recent_is_supported (void) { if (!g_settings_get_boolean (cinnamon_privacy_preferences, NEMO_PREFERENCES_RECENT_ENABLED)) return FALSE; const char * const *supported; int i; supported = g_vfs_get_supported_uri_schemes (g_vfs_get_default ()); for (i = 0; supported[i] != NULL; i++) { if (strcmp ("recent", supported[i]) == 0) { return TRUE; } } return FALSE; } static gchar * get_icon_name (const gchar *uri) { NemoFile *file = nemo_file_get_by_uri (uri); return nemo_file_get_control_icon_name (file); } static void update_places (NemoPlacesSidebar *sidebar) { NemoBookmark *bookmark; GtkTreeSelection *selection; GtkTreeIter last_iter, cat_iter; GtkTreeModel *model; GVolumeMonitor *volume_monitor; GList *mounts, *l, *ll; GMount *mount; GList *drives; GDrive *drive; GList *volumes; GVolume *volume; int bookmark_count, bookmark_index; char *location, *mount_uri, *name, *desktop_path, *last_uri, *identifier; const gchar *bookmark_name; gchar *icon; GFile *root, *df_file; NemoWindowSlot *slot; char *tooltip; gchar *tooltip_info; GList *network_mounts, *network_volumes; gint full; DEBUG ("Updating places sidebar"); sidebar->updating_sidebar = TRUE; model = NULL; last_uri = NULL; g_clear_pointer (&sidebar->top_bookend_uri, g_free); g_clear_pointer (&sidebar->bottom_bookend_uri, g_free); selection = gtk_tree_view_get_selection (sidebar->tree_view); if (gtk_tree_selection_get_selected (selection, &model, &last_iter)) { gtk_tree_model_get (model, &last_iter, PLACES_SIDEBAR_COLUMN_URI, &last_uri, -1); } gtk_tree_store_clear (sidebar->store); sidebar->devices_header_added = FALSE; sidebar->bookmarks_header_added = FALSE; slot = nemo_window_get_active_slot (sidebar->window); location = nemo_window_slot_get_current_uri (slot); network_mounts = network_volumes = NULL; volume_monitor = sidebar->volume_monitor; cat_iter = add_heading (sidebar, SECTION_COMPUTER, _("My Computer")); /* add built in bookmarks */ /* home folder */ mount_uri = nemo_get_home_directory_uri (); icon = get_icon_name (mount_uri); df_file = g_file_new_for_uri (mount_uri); full = get_disk_full (df_file, &tooltip_info); g_clear_object (&df_file); tooltip = g_strdup_printf (_("Open your personal folder\n%s"), tooltip_info); g_free (tooltip_info); cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, _("Home"), icon, mount_uri, NULL, NULL, NULL, 0, tooltip, full, home_on_different_fs (mount_uri) && full > -1, cat_iter); g_free (icon); sidebar->top_bookend_uri = g_strdup (mount_uri); g_free (mount_uri); g_free (tooltip); if (should_show_desktop ()) { /* desktop */ desktop_path = nemo_get_desktop_directory (); mount_uri = g_filename_to_uri (desktop_path, NULL, NULL); icon = get_icon_name (mount_uri); cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, _("Desktop"), icon, mount_uri, NULL, NULL, NULL, 0, _("Open the contents of your desktop in a folder"), 0, FALSE, cat_iter); g_free (icon); g_free (sidebar->top_bookend_uri); sidebar->top_bookend_uri = g_strdup (mount_uri); g_free (mount_uri); g_free (desktop_path); } /* add bookmarks */ bookmark_count = nemo_bookmark_list_length (sidebar->bookmarks); /* in certain situations (i.e. removed a bookmark), the breakpoint is smaller than * the number of bookmarks - make sure to fix this before iterating through a list of them. * We don't overwrite the stored breakpoint because the bookmark list could simply be reloading, * and we want the original number still when we update places again. */ gint temp_breakpoint = sidebar->bookmark_breakpoint; if (temp_breakpoint < 0 || temp_breakpoint > bookmark_count) { temp_breakpoint = bookmark_count; } for (bookmark_index = 0; bookmark_index < temp_breakpoint; ++bookmark_index) { bookmark = nemo_bookmark_list_item_at (sidebar->bookmarks, bookmark_index); root = nemo_bookmark_get_location (bookmark); bookmark_name = nemo_bookmark_get_name (bookmark); icon = nemo_bookmark_get_icon_name (bookmark); mount_uri = nemo_bookmark_get_uri (bookmark); tooltip = g_file_get_parse_name (root); cat_iter = add_place (sidebar, PLACES_BOOKMARK, SECTION_XDG_BOOKMARKS, bookmark_name, icon, mount_uri, NULL, NULL, NULL, bookmark_index, tooltip, 0, FALSE, cat_iter); g_object_unref (root); g_free (icon); g_free (mount_uri); g_free (tooltip); } if (recent_is_supported ()) { mount_uri = (char *)"recent:///"; /* No need to strdup */ icon = NEMO_ICON_SYMBOLIC_FOLDER_RECENT; cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, _("Recent"), icon, mount_uri, NULL, NULL, NULL, 0, _("Recent files"), 0, FALSE, cat_iter); sidebar->bottom_bookend_uri = g_strdup (mount_uri); } /* file system root */ mount_uri = (char *)"file:///"; /* No need to strdup */ icon = NEMO_ICON_SYMBOLIC_FILESYSTEM; df_file = g_file_new_for_uri (mount_uri); full = get_disk_full (df_file, &tooltip_info); g_clear_object (&df_file); tooltip = g_strdup_printf (_("Open the contents of the File System\n%s"), tooltip_info); g_free (tooltip_info); cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, _("File System"), icon, mount_uri, NULL, NULL, NULL, 0, tooltip, full, full > -1, cat_iter); g_free (tooltip); if (!recent_is_supported()) sidebar->bottom_bookend_uri = g_strdup (mount_uri); mount_uri = (char *)"trash:///"; /* No need to strdup */ icon = nemo_trash_monitor_get_symbolic_icon_name (); cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, _("Trash"), icon, mount_uri, NULL, NULL, NULL, 0, _("Open the trash"), 0, FALSE, cat_iter); g_free (icon); cat_iter = add_heading (sidebar, SECTION_BOOKMARKS, _("Bookmarks")); while (bookmark_index < bookmark_count) { bookmark = nemo_bookmark_list_item_at (sidebar->bookmarks, bookmark_index); root = nemo_bookmark_get_location (bookmark); bookmark_name = nemo_bookmark_get_name (bookmark); icon = nemo_bookmark_get_icon_name (bookmark); mount_uri = nemo_bookmark_get_uri (bookmark); tooltip = g_file_get_parse_name (root); cat_iter = add_place (sidebar, PLACES_BOOKMARK, SECTION_BOOKMARKS, bookmark_name, icon, mount_uri, NULL, NULL, NULL, bookmark_index, tooltip, 0, FALSE, cat_iter); g_object_unref (root); g_free (icon); g_free (mount_uri); g_free (tooltip); ++bookmark_index; } /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */ mounts = g_volume_monitor_get_mounts (volume_monitor); for (l = mounts; l != NULL; l = l->next) { mount = l->data; if (g_mount_is_shadowed (mount)) { g_object_unref (mount); continue; } volume = g_mount_get_volume (mount); if (volume != NULL) { g_object_unref (volume); g_object_unref (mount); continue; } root = g_mount_get_default_location (mount); if (!g_file_is_native (root)) { gboolean really_network = TRUE; gchar *path = g_file_get_path (root); if (!path) { network_mounts = g_list_prepend (network_mounts, mount); g_object_unref (root); continue; } gchar *escaped1 = g_uri_unescape_string (path, ""); gchar *escaped2 = g_uri_unescape_string (escaped1, ""); gchar *ptr = g_strrstr (escaped2, "file://"); if (ptr != NULL) { GFile *actual_file = g_file_new_for_uri (ptr); if (g_file_is_native(actual_file)) { really_network = FALSE; } g_object_unref(actual_file); } g_free (path); g_free (escaped1); g_free (escaped2); if (really_network) { network_mounts = g_list_prepend (network_mounts, mount); g_object_unref (root); continue; } } icon = nemo_get_mount_icon_name (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); tooltip = g_file_get_parse_name (root); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_DEVICES, name, icon, mount_uri, NULL, NULL, mount, 0, tooltip, 0, FALSE, cat_iter); g_object_unref (root); g_object_unref (mount); g_free (icon); g_free (name); g_free (mount_uri); g_free (tooltip); } g_list_free (mounts); /* first go through all connected drives */ drives = g_volume_monitor_get_connected_drives (volume_monitor); for (l = drives; l != NULL; l = l->next) { drive = l->data; volumes = g_drive_get_volumes (drive); if (volumes != NULL) { for (ll = volumes; ll != NULL; ll = ll->next) { volume = ll->data; identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS); if (g_strcmp0 (identifier, "network") == 0) { g_free (identifier); network_volumes = g_list_prepend (network_volumes, volume); continue; } g_free (identifier); mount = g_volume_get_mount (volume); if (mount != NULL) { gchar *full_display_name, *volume_id; /* Show mounted volume in the sidebar */ icon = nemo_get_mount_icon_name (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); volume_id = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); full_display_name = g_file_get_parse_name (root); df_file = g_file_new_for_uri (mount_uri); full = get_disk_full (df_file, &tooltip_info); g_clear_object (&df_file); tooltip = g_strdup_printf (_("%s (%s)\n%s"), full_display_name, volume_id, tooltip_info); g_free (tooltip_info); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_DEVICES, name, icon, mount_uri, drive, volume, mount, 0, tooltip, full, full > -1, cat_iter); g_object_unref (root); g_object_unref (mount); g_free (icon); g_free (tooltip); g_free (name); g_free (mount_uri); g_free (volume_id); g_free (full_display_name); } else { /* Do show the unmounted volumes in the sidebar; * this is so the user can mount it (in case automounting * is off). * * Also, even if automounting is enabled, this gives a visual * cue that the user should remember to yank out the media if * he just unmounted it. */ gchar *volume_id; icon = nemo_get_volume_icon_name (volume); name = g_volume_get_name (volume); volume_id = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); tooltip = g_strdup_printf (_("Mount and open %s (%s)"), name, volume_id); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_DEVICES, name, icon, NULL, drive, volume, NULL, 0, tooltip, 0, FALSE, cat_iter); g_free (icon); g_free (name); g_free (tooltip); g_free (volume_id); } g_object_unref (volume); } g_list_free (volumes); } else { if (g_drive_is_removable (drive) && !g_drive_is_media_check_automatic (drive)) { /* If the drive has no mountable volumes and we cannot detect media change.. we * display the drive in the sidebar so the user can manually poll the drive by * right clicking and selecting "Rescan..." * * This is mainly for drives like floppies where media detection doesn't * work.. but it's also for human beings who like to turn off media detection * in the OS to save battery juice. */ icon = nemo_get_drive_icon_name (drive); name = g_drive_get_name (drive); tooltip = g_strdup_printf (_("Mount and open %s"), name); cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_DEVICES, name, icon, NULL, drive, NULL, NULL, 0, tooltip, 0, FALSE, cat_iter); g_free (icon); g_free (tooltip); g_free (name); } } g_object_unref (drive); } g_list_free (drives); /* add all volumes that is not associated with a drive */ volumes = g_volume_monitor_get_volumes (volume_monitor); for (l = volumes; l != NULL; l = l->next) { volume = l->data; drive = g_volume_get_drive (volume); if (drive != NULL) { g_object_unref (volume); g_object_unref (drive); continue; } identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS); if (g_strcmp0 (identifier, "network") == 0) { g_free (identifier); network_volumes = g_list_prepend (network_volumes, volume); continue; } g_free (identifier); mount = g_volume_get_mount (volume); if (mount != NULL) { icon = nemo_get_mount_icon_name (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); df_file = g_file_new_for_uri (mount_uri); full = get_disk_full (df_file, &tooltip_info); g_clear_object (&df_file); tooltip = g_strdup_printf (_("%s\n%s"), g_file_get_parse_name (root), tooltip_info); g_free (tooltip_info); g_object_unref (root); name = g_mount_get_name (mount); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_DEVICES, name, icon, mount_uri, NULL, volume, mount, 0, tooltip, full, full > -1, cat_iter); g_object_unref (mount); g_free (icon); g_free (name); g_free (tooltip); g_free (mount_uri); } else { /* see comment above in why we add an icon for an unmounted mountable volume */ icon = nemo_get_volume_icon_name (volume); name = g_volume_get_name (volume); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_DEVICES, name, icon, NULL, NULL, volume, NULL, 0, name, 0, FALSE, cat_iter); g_free (icon); g_free (name); } g_object_unref (volume); } g_list_free (volumes); /* network */ cat_iter = add_heading (sidebar, SECTION_NETWORK, _("Network")); network_volumes = g_list_reverse (network_volumes); for (l = network_volumes; l != NULL; l = l->next) { volume = l->data; mount = g_volume_get_mount (volume); if (mount != NULL) { network_mounts = g_list_prepend (network_mounts, mount); continue; } else { icon = nemo_get_volume_icon_name (volume); name = g_volume_get_name (volume); tooltip = g_strdup_printf (_("Mount and open %s"), name); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_NETWORK, name, icon, NULL, NULL, volume, NULL, 0, tooltip, 0, FALSE, cat_iter); g_free (icon); g_free (name); g_free (tooltip); } } g_list_free_full (network_volumes, g_object_unref); network_mounts = g_list_reverse (network_mounts); for (l = network_mounts; l != NULL; l = l->next) { mount = l->data; root = g_mount_get_default_location (mount); icon = nemo_get_mount_icon_name (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); tooltip = g_file_get_parse_name (root); cat_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_NETWORK, name, icon, mount_uri, NULL, NULL, mount, 0, tooltip, 0, FALSE, cat_iter); g_object_unref (root); g_free (icon); g_free (name); g_free (mount_uri); g_free (tooltip); } g_list_free_full (network_mounts, g_object_unref); /* network:// */ mount_uri = (char *)"network:///"; /* No need to strdup */ icon = NEMO_ICON_SYMBOLIC_NETWORK; cat_iter = add_place (sidebar, PLACES_BUILT_IN, SECTION_NETWORK, _("Network"), icon, mount_uri, NULL, NULL, NULL, 0, _("Browse the contents of the network"), 0, FALSE, cat_iter); /* restore selection */ restore_expand_state (sidebar); sidebar_update_restore_selection (sidebar, location, last_uri); sidebar->updating_sidebar = FALSE; g_free (location); g_free (last_uri); } static void mount_added_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void mount_removed_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void mount_changed_callback (GVolumeMonitor *volume_monitor, GMount *mount, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void volume_added_callback (GVolumeMonitor *volume_monitor, GVolume *volume, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void volume_removed_callback (GVolumeMonitor *volume_monitor, GVolume *volume, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void volume_changed_callback (GVolumeMonitor *volume_monitor, GVolume *volume, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void drive_disconnected_callback (GVolumeMonitor *volume_monitor, GDrive *drive, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void drive_connected_callback (GVolumeMonitor *volume_monitor, GDrive *drive, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static void drive_changed_callback (GVolumeMonitor *volume_monitor, GDrive *drive, NemoPlacesSidebar *sidebar) { update_places_on_idle (sidebar); } static gboolean over_eject_button (NemoPlacesSidebar *sidebar, gint x, gint y, GtkTreePath **path) { GtkTreeViewColumn *column, *eject_column; int width, x_offset, x_col_offset; gboolean show_eject; GtkTreeIter iter; GtkTreeModel *model; *path = NULL; model = gtk_tree_view_get_model (sidebar->tree_view); if (gtk_tree_view_get_path_at_pos (sidebar->tree_view, x, y, path, &column, NULL, NULL)) { gtk_tree_model_get_iter (model, &iter, *path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_EJECT, &show_eject, -1); if (!show_eject) { goto out; } eject_column = gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar->tree_view), 3); x_col_offset = gtk_tree_view_column_get_x_offset (eject_column); /* Reload cell attributes for this particular row */ gtk_tree_view_column_cell_set_cell_data (eject_column, model, &iter, FALSE, FALSE); gtk_tree_view_column_cell_get_position (eject_column, sidebar->eject_icon_cell_renderer, &x_offset, &width); if (x - x_col_offset >= 0 && x - x_col_offset <= width) { return TRUE; } } out: if (*path != NULL) { gtk_tree_path_free (*path); *path = NULL; } return FALSE; } static gboolean clicked_eject_button (NemoPlacesSidebar *sidebar, GtkTreePath **path) { GdkEvent *event; event = gtk_get_current_event (); if (event) { GdkEventButton *button_event = (GdkEventButton *) event; if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) && over_eject_button (sidebar, button_event->x, button_event->y, path)) { return TRUE; } } return FALSE; } static void desktop_setting_changed_callback (gpointer user_data) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (user_data); update_places (sidebar); } static void loading_uri_callback (NemoWindow *window, char *location, NemoPlacesSidebar *sidebar) { GtkTreeSelection *selection; GtkTreeIter iter_cat, iter_child; gboolean valid_cat, valid_child; char *uri; gboolean found = FALSE; if (strcmp (sidebar->uri, location) != 0) { g_free (sidebar->uri); sidebar->uri = g_strdup (location); /* set selection if any place matches location */ selection = gtk_tree_view_get_selection (sidebar->tree_view); gtk_tree_selection_unselect_all (selection); valid_cat = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store_filter), &iter_cat); while (valid_cat) { valid_child = gtk_tree_model_iter_children (GTK_TREE_MODEL (sidebar->store_filter), &iter_child, &iter_cat); while (valid_child) { gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter_child, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); if (uri != NULL) { if (strcmp (uri, location) == 0) { g_free (uri); gtk_tree_selection_select_iter (selection, &iter_child); found = TRUE; break; } g_free (uri); } valid_child = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store_filter), &iter_child); } if (found) { break; } valid_cat = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store_filter), &iter_cat); } } } typedef struct { NemoPlacesSidebar *sidebar; GdkRectangle rect; SectionType section_type; } CategoryExpandPayload; static gboolean pointer_is_still_in_cell (gint x, gint y, GdkRectangle rect) { gint max_x = rect.x + rect.width; gint max_y = rect.y + rect.height; if ((x >= rect.x && x <= max_x) && (y >= rect.y && y <= max_y)) { return TRUE; } else { return FALSE; } } static gboolean maybe_expand_category (gpointer data) { CategoryExpandPayload *payload = (CategoryExpandPayload *) data; GdkDeviceManager *manager; GdkDevice *pointer; GdkWindow *window; int x, y; g_assert (GTK_IS_WIDGET (payload->sidebar->tree_view)); window = gtk_widget_get_window (GTK_WIDGET (payload->sidebar->tree_view)); manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (payload->sidebar->tree_view))); pointer = gdk_device_manager_get_client_pointer (manager); gdk_window_get_device_position (window, pointer, &x, &y, NULL); if (pointer_is_still_in_cell (x, y, payload->rect)) { expand_or_collapse_category (payload->sidebar, payload->section_type, TRUE); } g_source_remove (payload->sidebar->expand_timeout_source); payload->sidebar->expand_timeout_source = 0; return FALSE; } static gboolean cat_is_expanded (NemoPlacesSidebar *sidebar, SectionType section_type) { switch (section_type) { case SECTION_COMPUTER: return sidebar->my_computer_expanded; case SECTION_BOOKMARKS: return sidebar->bookmarks_expanded; case SECTION_DEVICES: return sidebar->devices_expanded; case SECTION_NETWORK: return sidebar->network_expanded; case SECTION_XDG_BOOKMARKS: default: return TRUE; } } static GtkTreeViewDropPosition get_drag_type (NemoPlacesSidebar *sidebar, gchar *drop_target_uri, GdkRectangle rect, int y, SectionType section_type) { gint zone; gint upper_bound = rect.y + (rect.height / 4); gint lower_bound = rect.y + rect.height - (rect.height / 4); if (y <= upper_bound) { zone = POSITION_UPPER; } else if (y > upper_bound && y < lower_bound) { return GTK_TREE_VIEW_DROP_INTO_OR_BEFORE; } else { zone = POSITION_LOWER; } if (g_strcmp0 (drop_target_uri, sidebar->top_bookend_uri) == 0 && zone == POSITION_LOWER) { return GTK_TREE_VIEW_DROP_AFTER; } else if (g_strcmp0 (drop_target_uri, sidebar->bottom_bookend_uri) == 0 && zone == POSITION_UPPER) { return GTK_TREE_VIEW_DROP_BEFORE; } if ((section_type == SECTION_XDG_BOOKMARKS || section_type == SECTION_BOOKMARKS) && zone == POSITION_UPPER) { return GTK_TREE_VIEW_DROP_BEFORE; } else if ((section_type == SECTION_XDG_BOOKMARKS || section_type == SECTION_BOOKMARKS) && zone == POSITION_LOWER) { return GTK_TREE_VIEW_DROP_AFTER; } else { /* or else you want to drag items INTO the existing bookmarks */ return GTK_TREE_VIEW_DROP_INTO_OR_BEFORE; } } /* Computes the appropriate row and position for dropping */ static gboolean compute_drop_position (GtkTreeView *tree_view, int x, int y, GtkTreePath **path, GtkTreeViewDropPosition *pos, NemoPlacesSidebar *sidebar) { GtkTreeModel *model; GtkTreeIter iter; PlaceType place_type; SectionType section_type; gchar *drop_target_uri = NULL; if (!gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, path, pos)) { return FALSE; } model = gtk_tree_view_get_model (tree_view); gtk_tree_model_get_iter (model, &iter, *path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, PLACES_SIDEBAR_COLUMN_URI, &drop_target_uri, -1); if (!cat_is_expanded (sidebar, section_type) && place_type == PLACES_HEADING) { if (sidebar->expand_timeout_source > 0) { goto fail; } CategoryExpandPayload *payload; GtkTreeViewColumn *col; col = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 2); payload = g_new0 (CategoryExpandPayload, 1); payload->sidebar = sidebar; gtk_tree_view_get_cell_area (tree_view, *path, col, &payload->rect); payload->section_type = section_type; sidebar->expand_timeout_source = g_timeout_add_full (G_PRIORITY_DEFAULT, DRAG_EXPAND_CATEGORY_DELAY, (GSourceFunc) maybe_expand_category, payload, (GDestroyNotify) g_free); goto fail; } else if (place_type == PLACES_HEADING) { if (section_type == SECTION_BOOKMARKS && (int)nemo_bookmark_list_length (sidebar->bookmarks) == sidebar->bookmark_breakpoint) { *pos = GTK_TREE_VIEW_DROP_AFTER; g_free (drop_target_uri); return TRUE; } else { goto fail; } } if (section_type != SECTION_XDG_BOOKMARKS && section_type != SECTION_BOOKMARKS && sidebar->drag_data_received && sidebar->drag_data_info == GTK_TREE_MODEL_ROW && g_strcmp0 (drop_target_uri, sidebar->top_bookend_uri) != 0) { /* don't allow dropping bookmarks into non-bookmark areas */ goto fail; } if (g_strcmp0 (drop_target_uri, "recent:///") == 0) { goto fail; } GdkRectangle rect; GtkTreeViewColumn *col; col = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 1); gtk_tree_view_get_cell_area (tree_view, *path, col, &rect); *pos = get_drag_type (sidebar, drop_target_uri, rect, y, section_type); if (*pos != GTK_TREE_VIEW_DROP_BEFORE && sidebar->drag_data_received && sidebar->drag_data_info == GTK_TREE_MODEL_ROW) { /* bookmark rows are never dragged into other bookmark rows */ *pos = GTK_TREE_VIEW_DROP_AFTER; } return TRUE; fail: g_free (drop_target_uri); gtk_tree_path_free (*path); *path = NULL; return FALSE; } static gboolean get_drag_data (GtkTreeView *tree_view, GdkDragContext *context, unsigned int time) { GdkAtom target; target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view), context, NULL); if (target == GDK_NONE) { return FALSE; } gtk_drag_get_data (GTK_WIDGET (tree_view), context, target, time); return TRUE; } static void free_drag_data (NemoPlacesSidebar *sidebar) { sidebar->drag_data_received = FALSE; if (sidebar->drag_list) { nemo_drag_destroy_selection_list (sidebar->drag_list); sidebar->drag_list = NULL; } g_clear_pointer (&sidebar->desktop_dnd_source_fs, g_free); sidebar->desktop_dnd_can_delete_source = FALSE; } static gboolean can_accept_file_as_bookmark (NemoFile *file) { return (nemo_file_is_directory (file) && !is_built_in_bookmark (file)); } static gboolean can_accept_items_as_bookmarks (const GList *items) { int max; char *uri; NemoFile *file; /* Iterate through selection checking if item will get accepted as a bookmark. * If more than 100 items selected, return an over-optimistic result. */ for (max = 100; items != NULL && max >= 0; items = items->next, max--) { uri = ((NemoDragSelectionItem *)items->data)->uri; file = nemo_file_get_by_uri (uri); if (!can_accept_file_as_bookmark (file)) { nemo_file_unref (file); return FALSE; } nemo_file_unref (file); } return TRUE; } static gboolean drag_motion_callback (GtkTreeView *tree_view, GdkDragContext *context, int x, int y, unsigned int time, NemoPlacesSidebar *sidebar) { GtkTreePath *path; GtkTreeViewDropPosition pos; int action; GtkTreeIter iter; char *uri; gboolean res; action = 0; if (!sidebar->drag_data_received) { if (!get_drag_data (tree_view, context, time)) { return FALSE; } } if (!sidebar->in_drag) { sidebar->in_drag = TRUE; gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sidebar->store_filter)); } path = NULL; res = compute_drop_position (tree_view, x, y, &path, &pos, sidebar); if (!res) { gtk_tree_view_set_drag_dest_row (tree_view, NULL, GTK_TREE_VIEW_DROP_BEFORE); goto out; } if (pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER ) { if (sidebar->drag_data_received && sidebar->drag_data_info == GTK_TREE_MODEL_ROW) { action = GDK_ACTION_MOVE; } else if (can_accept_items_as_bookmarks (sidebar->drag_list)) { action = GDK_ACTION_COPY; } else { action = 0; } } else { if (sidebar->drag_list == NULL) { action = 0; } else { gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store_filter), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); nemo_drag_default_drop_action_for_icons (context, uri, sidebar->drag_list, &action, &sidebar->desktop_dnd_source_fs, &sidebar->desktop_dnd_can_delete_source); g_free (uri); } } if (action != 0) { gtk_tree_view_set_drag_dest_row (tree_view, path, pos); } if (path != NULL) { gtk_tree_path_free (path); } out: g_signal_stop_emission_by_name (tree_view, "drag-motion"); if (action != 0) { gdk_drag_status (context, action, time); } else { gdk_drag_status (context, 0, time); } return TRUE; } static void drag_leave_callback (GtkTreeView *tree_view, GdkDragContext *context, unsigned int time, NemoPlacesSidebar *sidebar) { free_drag_data (sidebar); gtk_tree_view_set_drag_dest_row (tree_view, NULL, GTK_TREE_VIEW_DROP_BEFORE); g_signal_stop_emission_by_name (tree_view, "drag-leave"); } /* Parses a "text/uri-list" string and inserts its URIs as bookmarks */ static void bookmarks_drop_uris (NemoPlacesSidebar *sidebar, GtkSelectionData *selection_data, int position, SectionType section_type) { NemoBookmark *bookmark; NemoFile *file; char *uri; char **uris; int i; GFile *location; uris = gtk_selection_data_get_uris (selection_data); if (!uris) return; for (i = 0; uris[i]; i++) { uri = uris[i]; file = nemo_file_get_by_uri (uri); if (!can_accept_file_as_bookmark (file)) { nemo_file_unref (file); continue; } uri = nemo_file_get_drop_target_uri (file); location = g_file_new_for_uri (uri); nemo_file_unref (file); bookmark = nemo_bookmark_new (location, NULL, NULL, NULL); if (!nemo_bookmark_list_contains (sidebar->bookmarks, bookmark)) { if (position < sidebar->bookmark_breakpoint || (position == sidebar->bookmark_breakpoint && (section_type == SECTION_XDG_BOOKMARKS || section_type == SECTION_COMPUTER))) { increment_bookmark_breakpoint (sidebar); } nemo_bookmark_list_insert_item (sidebar->bookmarks, bookmark, position++); } g_object_unref (location); g_object_unref (bookmark); g_free (uri); } g_strfreev (uris); } static GList * uri_list_from_selection (GList *selection) { NemoDragSelectionItem *item; GList *ret; GList *l; ret = NULL; for (l = selection; l != NULL; l = l->next) { item = l->data; ret = g_list_prepend (ret, item->uri); } return g_list_reverse (ret); } static GList* build_selection_list (const char *data) { NemoDragSelectionItem *item; GList *result; char **uris; char *uri; int i; uris = g_uri_list_extract_uris (data); result = NULL; for (i = 0; uris[i]; i++) { uri = uris[i]; item = nemo_drag_selection_item_new (); item->uri = g_strdup (uri); item->got_icon_position = FALSE; result = g_list_prepend (result, item); } g_strfreev (uris); return g_list_reverse (result); } static gboolean get_selected_iter (NemoPlacesSidebar *sidebar, GtkTreeIter *iter) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection (sidebar->tree_view); return gtk_tree_selection_get_selected (selection, NULL, iter); } static void update_bookmark_breakpoint (NemoPlacesSidebar *sidebar, SectionType old_type, SectionType new_type) { if (old_type != new_type) { if (old_type == SECTION_XDG_BOOKMARKS && new_type != SECTION_COMPUTER) decrement_bookmark_breakpoint (sidebar); else if (old_type == SECTION_BOOKMARKS) increment_bookmark_breakpoint (sidebar); } } /* Reorders the selected bookmark to the specified position */ static void reorder_bookmarks (NemoPlacesSidebar *sidebar, int new_position, SectionType new_section_type) { GtkTreeIter iter; PlaceType type; SectionType old_section_type; int old_position; /* Get the selected path */ if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &old_section_type, PLACES_SIDEBAR_COLUMN_INDEX, &old_position, -1); if (type != PLACES_BOOKMARK || old_position < 0 || old_position >= (int)nemo_bookmark_list_length (sidebar->bookmarks)) { return; } update_bookmark_breakpoint (sidebar, old_section_type, new_section_type); nemo_bookmark_list_move_item (sidebar->bookmarks, old_position, new_position); if (old_position == new_position) update_places (sidebar); } static gboolean idle_hide_bookmarks (gpointer user_data) { NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (user_data); if (sidebar->in_drag) { sidebar->in_drag = FALSE; gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sidebar->store_filter)); } return FALSE; } static void drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, unsigned int info, unsigned int time, NemoPlacesSidebar *sidebar) { GtkTreeView *tree_view; GtkTreePath *tree_path; GtkTreeViewDropPosition tree_pos; GtkTreeIter iter; int position; GtkTreeModel *model; char *drop_uri; GList *selection_list, *uris; PlaceType place_type; SectionType section_type; gboolean success; tree_view = GTK_TREE_VIEW (widget); if (!sidebar->drag_data_received) { if (gtk_selection_data_get_target (selection_data) != GDK_NONE && info == TEXT_URI_LIST) { sidebar->drag_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data)); } else { sidebar->drag_list = NULL; } sidebar->drag_data_received = TRUE; sidebar->drag_data_info = info; } g_signal_stop_emission_by_name (widget, "drag-data-received"); if (!sidebar->drop_occured) { return; } /* Compute position */ success = compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar); if (!success) { goto out; } success = FALSE; if (tree_pos == GTK_TREE_VIEW_DROP_BEFORE || tree_pos == GTK_TREE_VIEW_DROP_AFTER) { model = gtk_tree_view_get_model (tree_view); if (!gtk_tree_model_get_iter (model, &iter, tree_path)) { goto out; } gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, PLACES_SIDEBAR_COLUMN_INDEX, &position, -1); if (section_type == SECTION_COMPUTER && tree_pos == GTK_TREE_VIEW_DROP_BEFORE) { position = nemo_bookmark_list_length(sidebar->bookmarks); } else if (section_type == SECTION_BOOKMARKS && position == -1) { /* Check for (temporarily) visible Bookmarks heading, only drop-reactive when * it has no children, so we can assume that (bookmark_breakpoint == bookmark_count) */ position = nemo_bookmark_list_length (sidebar->bookmarks); } else if (tree_pos == GTK_TREE_VIEW_DROP_AFTER && (section_type == SECTION_XDG_BOOKMARKS || section_type == SECTION_BOOKMARKS)) { position++; } switch (info) { case TEXT_URI_LIST: bookmarks_drop_uris (sidebar, selection_data, position, section_type); success = TRUE; break; case GTK_TREE_MODEL_ROW: reorder_bookmarks (sidebar, position, section_type); success = TRUE; break; default: g_assert_not_reached (); break; } } else { GdkDragAction real_action; /* file transfer requested */ real_action = gdk_drag_context_get_selected_action (context); if (real_action == GDK_ACTION_ASK) { real_action = nemo_drag_drop_action_ask (GTK_WIDGET (tree_view), gdk_drag_context_get_actions (context)); } if (real_action > 0) { model = gtk_tree_view_get_model (tree_view); gtk_tree_model_get_iter (model, &iter, tree_path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &drop_uri, -1); switch (info) { case TEXT_URI_LIST: selection_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data)); uris = uri_list_from_selection (selection_list); nemo_file_operations_copy_move (uris, NULL, drop_uri, real_action, GTK_WIDGET (tree_view), NULL, NULL); nemo_drag_destroy_selection_list (selection_list); g_list_free (uris); success = TRUE; break; case GTK_TREE_MODEL_ROW: success = FALSE; break; default: g_assert_not_reached (); break; } g_free (drop_uri); } } out: sidebar->drop_occured = FALSE; free_drag_data (sidebar); gtk_drag_finish (context, success, FALSE, time); gtk_tree_path_free (tree_path); g_timeout_add (250, (GSourceFunc) idle_hide_bookmarks, sidebar); } static gboolean drag_drop_callback (GtkTreeView *tree_view, GdkDragContext *context, int x, int y, unsigned int time, NemoPlacesSidebar *sidebar) { gboolean retval = FALSE; sidebar->drop_occured = TRUE; retval = get_drag_data (tree_view, context, time); g_signal_stop_emission_by_name (tree_view, "drag-drop"); return retval; } /* Callback used when the file list's popup menu is detached */ static void bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget, GtkMenu *menu) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (attach_widget); g_assert (NEMO_IS_PLACES_SIDEBAR (sidebar)); sidebar->popup_menu = NULL; sidebar->popup_menu_add_shortcut_item = NULL; sidebar->popup_menu_remove_item = NULL; sidebar->popup_menu_rename_item = NULL; sidebar->popup_menu_separator_item = NULL; sidebar->popup_menu_mount_item = NULL; sidebar->popup_menu_unmount_item = NULL; sidebar->popup_menu_eject_item = NULL; sidebar->popup_menu_rescan_item = NULL; sidebar->popup_menu_start_item = NULL; sidebar->popup_menu_stop_item = NULL; sidebar->popup_menu_empty_trash_item = NULL; sidebar->popup_menu_properties_separator_item = NULL; sidebar->popup_menu_properties_item = NULL; sidebar->popup_menu_action_separator_item = NULL; sidebar->popup_menu_remove_rename_separator_item = NULL; } static void check_unmount_and_eject (GMount *mount, GVolume *volume, GDrive *drive, gboolean *show_unmount, gboolean *show_eject) { *show_unmount = FALSE; *show_eject = FALSE; if (drive != NULL) { *show_eject = g_drive_can_eject (drive); } if (volume != NULL) { *show_eject |= g_volume_can_eject (volume); } if (mount != NULL) { *show_eject |= g_mount_can_eject (mount); *show_unmount = g_mount_can_unmount (mount) && !*show_eject; } } static void check_visibility (GMount *mount, GVolume *volume, GDrive *drive, gboolean *show_mount, gboolean *show_unmount, gboolean *show_eject, gboolean *show_rescan, gboolean *show_start, gboolean *show_stop) { *show_mount = FALSE; *show_rescan = FALSE; *show_start = FALSE; *show_stop = FALSE; check_unmount_and_eject (mount, volume, drive, show_unmount, show_eject); if (drive != NULL) { if (g_drive_is_removable (drive) && !g_drive_is_media_check_automatic (drive) && g_drive_can_poll_for_media (drive)) *show_rescan = TRUE; *show_start = g_drive_can_start (drive) || g_drive_can_start_degraded (drive); *show_stop = g_drive_can_stop (drive); if (*show_stop) *show_unmount = FALSE; } if (volume != NULL) { if (mount == NULL) *show_mount = g_volume_can_mount (volume); } } static void hide_all_action_items (NemoPlacesSidebar *sidebar) { GList *l; ActionPayload *p; for (l = sidebar->action_items; l != NULL; l = l->next) { p = l->data; gtk_widget_set_visible (p->item, FALSE); } } static void bookmarks_check_popup_sensitivity (NemoPlacesSidebar *sidebar) { GtkTreeIter iter; PlaceType type; GDrive *drive = NULL; GVolume *volume = NULL; GMount *mount = NULL; GFile *location; NemoDirectory *directory = NULL; gboolean show_mount; gboolean show_unmount; gboolean show_eject; gboolean show_rescan; gboolean show_start; gboolean show_stop; gboolean show_empty_trash; gboolean show_properties; char *uri = NULL; type = PLACES_BUILT_IN; if (sidebar->popup_menu == NULL) { return; } if (get_selected_iter (sidebar, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, PLACES_SIDEBAR_COLUMN_MOUNT, &mount, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); } gtk_widget_set_visible (sidebar->popup_menu_remove_rename_separator_item, (type == PLACES_MOUNTED_VOLUME || type == PLACES_BOOKMARK)); gtk_widget_set_visible (sidebar->popup_menu_add_shortcut_item, (type == PLACES_MOUNTED_VOLUME)); gtk_widget_set_visible (sidebar->popup_menu_remove_item, (type == PLACES_BOOKMARK)); gtk_widget_set_visible (sidebar->popup_menu_rename_item, (type == PLACES_BOOKMARK)); gtk_widget_set_sensitive (sidebar->popup_menu_empty_trash_item, !nemo_trash_monitor_is_empty ()); check_visibility (mount, volume, drive, &show_mount, &show_unmount, &show_eject, &show_rescan, &show_start, &show_stop); /* We actually want both eject and unmount since eject will unmount all volumes. * TODO: hide unmount if the drive only has a single mountable volume */ show_empty_trash = (uri != NULL) && (!strcmp (uri, "trash:///")); /* Only show properties for local mounts */ show_properties = (mount != NULL); if (mount != NULL) { location = g_mount_get_default_location (mount); directory = nemo_directory_get (location); show_properties = nemo_directory_is_local (directory); nemo_directory_unref (directory); g_object_unref (location); } gtk_widget_set_visible (sidebar->popup_menu_separator_item, show_mount || show_unmount || show_eject || show_empty_trash); gtk_widget_set_visible (sidebar->popup_menu_mount_item, show_mount); gtk_widget_set_visible (sidebar->popup_menu_unmount_item, show_unmount); gtk_widget_set_visible (sidebar->popup_menu_eject_item, show_eject); gtk_widget_set_visible (sidebar->popup_menu_rescan_item, show_rescan); gtk_widget_set_visible (sidebar->popup_menu_start_item, show_start); gtk_widget_set_visible (sidebar->popup_menu_stop_item, show_stop); gtk_widget_set_visible (sidebar->popup_menu_empty_trash_item, show_empty_trash); gtk_widget_set_visible (sidebar->popup_menu_properties_separator_item, show_properties); gtk_widget_set_visible (sidebar->popup_menu_properties_item, show_properties); /* Adjust start/stop items to reflect the type of the drive */ gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start")); gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop")); if ((show_start || show_stop) && drive != NULL) { switch (g_drive_get_start_stop_type (drive)) { case G_DRIVE_START_STOP_TYPE_SHUTDOWN: /* start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used */ gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Power On")); gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Safely Remove Drive")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Connect Drive")); gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Disconnect Drive")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start Multi-disk Device")); gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop Multi-disk Device")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: /* stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used */ gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Unlock Drive")); gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Lock Drive")); break; default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: /* uses defaults set above */ break; } } if (!uri) { hide_all_action_items (sidebar); gtk_widget_set_visible (sidebar->popup_menu_action_separator_item, FALSE); return; } gboolean actions_visible = FALSE; GList *l; NemoFile *file = nemo_file_get_by_uri (uri); g_clear_pointer (&sidebar->popup_file, nemo_file_unref); if (sidebar->popup_file_idle_handler != 0) { g_source_remove (sidebar->popup_file_idle_handler); } sidebar->popup_file = nemo_file_ref (file); NemoFile *parent = nemo_file_get_parent (file); GList *tmp = NULL; tmp = g_list_append (tmp, file); ActionPayload *p; for (l = sidebar->action_items; l != NULL; l = l->next) { p = l->data; if (nemo_action_get_visibility (p->action, tmp, parent, TRUE)) { gchar *action_label = nemo_action_get_label (p->action, tmp, parent); gtk_menu_item_set_label (GTK_MENU_ITEM (p->item), action_label); gtk_widget_set_visible (p->item, TRUE); g_free (action_label); actions_visible = TRUE; } else { gtk_widget_set_visible (p->item, FALSE); } } gtk_widget_set_visible (sidebar->popup_menu_action_separator_item, actions_visible); g_list_free (tmp); g_free (uri); } /* Callback used when the selection in the shortcuts tree changes */ static void bookmarks_selection_changed_cb (GtkTreeSelection *selection, NemoPlacesSidebar *sidebar) { bookmarks_check_popup_sensitivity (sidebar); } static void volume_mounted_cb (GVolume *volume, gboolean success, GObject *user_data) { GMount *mount; NemoPlacesSidebar *sidebar; GFile *location; sidebar = NEMO_PLACES_SIDEBAR (user_data); sidebar->mounting = FALSE; mount = g_volume_get_mount (volume); if (mount != NULL) { location = g_mount_get_default_location (mount); if (sidebar->go_to_after_mount_slot != NULL) { if ((sidebar->go_to_after_mount_flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) { nemo_window_slot_open_location (sidebar->go_to_after_mount_slot, location, sidebar->go_to_after_mount_flags); } else { NemoWindow *new, *cur; cur = NEMO_WINDOW (sidebar->window); new = nemo_application_create_window (nemo_application_get_singleton (), gtk_window_get_screen (GTK_WINDOW (cur))); nemo_window_go_to (new, location); } } g_object_unref (G_OBJECT (location)); g_object_unref (G_OBJECT (mount)); } if (sidebar->go_to_after_mount_slot) { g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), (gpointer *) &sidebar->go_to_after_mount_slot); sidebar->go_to_after_mount_slot = NULL; } } static void drive_start_from_bookmark_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; char *primary; char *name; error = NULL; if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { if (error->code != G_IO_ERROR_FAILED_HANDLED) { name = g_drive_get_name (G_DRIVE (source_object)); primary = g_strdup_printf (_("Unable to start %s"), name); g_free (name); eel_show_error_dialog (primary, error->message, NULL); g_free (primary); } g_error_free (error); } } static void open_selected_bookmark (NemoPlacesSidebar *sidebar, GtkTreeModel *model, GtkTreeIter *iter, NemoWindowOpenFlags flags) { NemoWindowSlot *slot; GFile *location; char *uri; if (!iter) { return; } gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); if (uri != NULL) { DEBUG ("Activating bookmark %s", uri); location = g_file_new_for_uri (uri); /* Navigate to the clicked location */ if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) { slot = nemo_window_get_active_slot (sidebar->window); nemo_window_slot_open_location (slot, location, flags); } else { NemoWindow *cur, *new; cur = NEMO_WINDOW (sidebar->window); new = nemo_application_create_window (nemo_application_get_singleton (), gtk_window_get_screen (GTK_WINDOW (cur))); nemo_window_go_to (new, location); } g_object_unref (location); g_free (uri); } else { GDrive *drive; GVolume *volume; NemoWindowSlot *slt; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, -1); if (volume != NULL && !sidebar->mounting) { sidebar->mounting = TRUE; g_assert (sidebar->go_to_after_mount_slot == NULL); slt = nemo_window_get_active_slot (sidebar->window); sidebar->go_to_after_mount_slot = slt; g_object_add_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), (gpointer *) &sidebar->go_to_after_mount_slot); sidebar->go_to_after_mount_flags = flags | NEMO_WINDOW_OPEN_FLAG_MOUNT; nemo_file_operations_mount_volume_full (NULL, volume, volume_mounted_cb, G_OBJECT (sidebar)); } else if (volume == NULL && drive != NULL && (g_drive_can_start (drive) || g_drive_can_start_degraded (drive))) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_from_bookmark_cb, NULL); g_object_unref (mount_op); } if (drive != NULL) g_object_unref (drive); if (volume != NULL) g_object_unref (volume); } } static void open_shortcut_from_menu (NemoPlacesSidebar *sidebar, NemoWindowOpenFlags flags) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path = NULL; model = gtk_tree_view_get_model (sidebar->tree_view); gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL); if (path != NULL && gtk_tree_model_get_iter (model, &iter, path)) { open_selected_bookmark (sidebar, model, &iter, flags); } gtk_tree_path_free (path); } static void open_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { open_shortcut_from_menu (sidebar, 0); } static void open_shortcut_in_new_window_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { open_shortcut_from_menu (sidebar, NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); } static void open_shortcut_in_new_tab_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { open_shortcut_from_menu (sidebar, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); } /* Add bookmark for the selected item */ static void add_bookmark (NemoPlacesSidebar *sidebar) { GtkTreeModel *model; GtkTreeIter iter; char *uri; GFile *location; NemoBookmark *bookmark; model = gtk_tree_view_get_model (sidebar->tree_view); if (get_selected_iter (sidebar, &iter)) { gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); if (uri == NULL) { return; } location = g_file_new_for_uri (uri); bookmark = nemo_bookmark_new (location, NULL, NULL, NULL); if (!nemo_bookmark_list_contains (sidebar->bookmarks, bookmark)) { nemo_bookmark_list_append (sidebar->bookmarks, bookmark); } g_object_unref (location); g_object_unref (bookmark); g_free (uri); } } static void add_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { add_bookmark (sidebar); } /* Rename the selected bookmark */ static void rename_selected_bookmark (NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GtkTreePath *path; GtkTreeViewColumn *column; GtkCellRenderer *cell; GList *renderers; PlaceType type; if (get_selected_iter (sidebar, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type != PLACES_BOOKMARK) { return; } path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store_filter), &iter); column = gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar->tree_view), 2); renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)); cell = g_list_nth_data (renderers, 5); g_list_free (renderers); g_object_set (cell, "editable", TRUE, NULL); gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (sidebar->tree_view), path, column, cell, TRUE); gtk_tree_path_free (path); } } static void rename_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { rename_selected_bookmark (sidebar); } /* Removes the selected bookmarks */ static void remove_selected_bookmarks (NemoPlacesSidebar *sidebar) { GtkTreeIter iter; PlaceType type; int index; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type != PLACES_BOOKMARK) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_INDEX, &index, -1); if (index < sidebar->bookmark_breakpoint) decrement_bookmark_breakpoint (sidebar); nemo_bookmark_list_delete_item_at (sidebar->bookmarks, index); } static void remove_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { remove_selected_bookmarks (sidebar); } static void mount_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GVolume *volume; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, -1); if (volume != NULL) { nemo_file_operations_mount_volume (NULL, volume); g_object_unref (volume); } } static void unmount_done (gpointer data) { NemoWindow *window; window = data; g_object_unref (window); } static void show_unmount_progress_cb (GMountOperation *op, const gchar *message, gint64 time_left, gint64 bytes_left, gpointer user_data) { NemoApplication *app = NEMO_APPLICATION (g_application_get_default ()); if (bytes_left == 0) { nemo_application_notify_unmount_done (app, message); } else { nemo_application_notify_unmount_show (app, message); } } static void show_unmount_progress_aborted_cb (GMountOperation *op, gpointer user_data) { NemoApplication *app = NEMO_APPLICATION (g_application_get_default ()); nemo_application_notify_unmount_done (app, NULL); } static GMountOperation * get_unmount_operation (NemoPlacesSidebar *sidebar) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); g_signal_connect (mount_op, "show-unmount-progress", G_CALLBACK (show_unmount_progress_cb), sidebar); g_signal_connect (mount_op, "aborted", G_CALLBACK (show_unmount_progress_aborted_cb), sidebar); return mount_op; } static void do_unmount (GMount *mount, NemoPlacesSidebar *sidebar) { GMountOperation *mount_op; if (mount != NULL) { mount_op = get_unmount_operation (sidebar); nemo_file_operations_unmount_mount_full (NULL, mount, mount_op, FALSE, TRUE, unmount_done, g_object_ref (sidebar->window)); g_object_unref (mount_op); } } static void do_unmount_selection (NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GMount *mount; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_MOUNT, &mount, -1); if (mount != NULL) { do_unmount (mount, sidebar); g_object_unref (mount); } } static void unmount_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { do_unmount_selection (sidebar); } static void handle_mount_unmount_failure (const gchar *primary, GError *error) { const gchar *message = NULL; if (error && error->code == G_IO_ERROR_FAILED_HANDLED) { return; } if (error) { message = error->message; } eel_show_error_dialog (primary, message, NULL); } static void drive_eject_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoWindow *window; GError *error; window = user_data; g_object_unref (window); error = NULL; if (!g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error)) { char *name, *primary; name = g_drive_get_name (G_DRIVE (source_object)); primary = g_strdup_printf (_("Unable to eject %s"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void volume_eject_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoWindow *window; GError *error; window = user_data; g_object_unref (window); error = NULL; if (!g_volume_eject_with_operation_finish (G_VOLUME (source_object), res, &error)) { char *name, *primary; name = g_volume_get_name (G_VOLUME (source_object)); primary = g_strdup_printf (_("Unable to eject %s"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void mount_eject_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoWindow *window; GError *error; window = user_data; g_object_unref (window); error = NULL; if (!g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error)) { char *name, *primary; name = g_mount_get_name (G_MOUNT (source_object)); primary = g_strdup_printf (_("Unable to eject %s"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void do_eject (GMount *mount, GVolume *volume, GDrive *drive, NemoPlacesSidebar *sidebar) { GMountOperation *mount_op = get_unmount_operation (sidebar); if (mount != NULL) { g_mount_eject_with_operation (mount, 0, mount_op, NULL, mount_eject_cb, g_object_ref (sidebar->window)); } else if (volume != NULL) { g_volume_eject_with_operation (volume, 0, mount_op, NULL, volume_eject_cb, g_object_ref (sidebar->window)); } else if (drive != NULL) { g_drive_eject_with_operation (drive, 0, mount_op, NULL, drive_eject_cb, g_object_ref (sidebar->window)); } g_object_unref (mount_op); } static void eject_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GMount *mount; GVolume *volume; GDrive *drive; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_MOUNT, &mount, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1); do_eject (mount, volume, drive, sidebar); } static gboolean eject_or_unmount_bookmark (NemoPlacesSidebar *sidebar, GtkTreePath *path) { GtkTreeModel *model; GtkTreeIter iter; gboolean can_unmount, can_eject; GMount *mount; GVolume *volume; GDrive *drive; gboolean ret; model = GTK_TREE_MODEL (sidebar->store_filter); if (!path) { return FALSE; } if (!gtk_tree_model_get_iter (model, &iter, path)) { return FALSE; } gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_MOUNT, &mount, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1); ret = FALSE; check_unmount_and_eject (mount, volume, drive, &can_unmount, &can_eject); /* if we can eject, it has priority over unmount */ if (can_eject) { do_eject (mount, volume, drive, sidebar); ret = TRUE; } else if (can_unmount) { do_unmount (mount, sidebar); ret = TRUE; } if (mount != NULL) g_object_unref (mount); if (volume != NULL) g_object_unref (volume); if (drive != NULL) g_object_unref (drive); return ret; } static gboolean eject_or_unmount_selection (NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GtkTreePath *path; gboolean ret; if (!get_selected_iter (sidebar, &iter)) { return FALSE; } path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store_filter), &iter); if (path == NULL) { return FALSE; } ret = eject_or_unmount_bookmark (sidebar, path); gtk_tree_path_free (path); return ret; } static void drive_poll_for_media_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; error = NULL; if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { char *name, *primary; name = g_drive_get_name (G_DRIVE (source_object)); primary = g_strdup_printf (_("Unable to poll %s for media changes"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void rescan_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GDrive *drive; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1); if (drive != NULL) { g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, NULL); } g_object_unref (drive); } static void drive_start_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; error = NULL; if (!g_drive_start_finish (G_DRIVE (source_object), res, &error)) { char *name, *primary; name = g_drive_get_name (G_DRIVE (source_object)); primary = g_strdup_printf (_("Unable to start %s"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void start_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GDrive *drive; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1); if (drive != NULL) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_cb, NULL); g_object_unref (mount_op); } g_object_unref (drive); } static void drive_stop_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NemoWindow *window; GError *error; window = user_data; g_object_unref (window); error = NULL; if (!g_drive_stop_finish (G_DRIVE (source_object), res, &error)) { char *name, *primary; name = g_drive_get_name (G_DRIVE (source_object)); primary = g_strdup_printf (_("Unable to stop %s"), name); handle_mount_unmount_failure (primary, error); g_free (name); g_free (primary); g_clear_error (&error); } } static void stop_shortcut_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeIter iter; GDrive *drive; if (!get_selected_iter (sidebar, &iter)) { return; } gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1); if (drive != NULL) { GMountOperation *mount_op = get_unmount_operation (sidebar); g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, mount_op, NULL, drive_stop_cb, g_object_ref (sidebar->window)); g_object_unref (mount_op); } g_object_unref (drive); } static void empty_trash_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { nemo_file_operations_empty_trash (GTK_WIDGET (sidebar->window)); } static gboolean find_prev_or_next_row (NemoPlacesSidebar *sidebar, GtkTreeIter *iter, gboolean go_up) { GtkTreeModel *model = GTK_TREE_MODEL (sidebar->store_filter); gboolean res; int place_type; if (go_up) { res = gtk_tree_model_iter_previous (model, iter); } else { res = gtk_tree_model_iter_next (model, iter); } if (res) { gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, -1); if (place_type == PLACES_HEADING) { if (go_up) { res = gtk_tree_model_iter_previous (model, iter); } else { res = gtk_tree_model_iter_next (model, iter); } } } return res; } static gboolean find_prev_row (NemoPlacesSidebar *sidebar, GtkTreeIter *iter) { return find_prev_or_next_row (sidebar, iter, TRUE); } static gboolean find_next_row (NemoPlacesSidebar *sidebar, GtkTreeIter *iter) { return find_prev_or_next_row (sidebar, iter, FALSE); } static void properties_cb (GtkMenuItem *item, NemoPlacesSidebar *sidebar) { GtkTreeModel *model; GtkTreePath *path = NULL; GtkTreeIter iter; GList *list; NemoFile *file; char *uri; model = gtk_tree_view_get_model (sidebar->tree_view); gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL); if (path == NULL || !gtk_tree_model_get_iter (model, &iter, path)) { gtk_tree_path_free (path); return; } gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); if (uri != NULL) { file = nemo_file_get_by_uri (uri); list = g_list_prepend (NULL, nemo_file_ref (file)); nemo_properties_window_present (list, GTK_WIDGET (sidebar), NULL); nemo_file_list_free (list); g_free (uri); } gtk_tree_path_free (path); } static gboolean nemo_places_sidebar_focus (GtkWidget *widget, GtkDirectionType direction) { NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (widget); GtkTreePath *path; GtkTreeIter iter, child_iter; gboolean res; res = get_selected_iter (sidebar, &iter); if (!res) { gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store_filter), &iter); gtk_tree_model_iter_children (GTK_TREE_MODEL (sidebar->store_filter), &child_iter, &iter); res = find_next_row (sidebar, &child_iter); if (res) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store_filter), &iter); gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); gtk_tree_path_free (path); } } return GTK_WIDGET_CLASS (nemo_places_sidebar_parent_class)->focus (widget, direction); } /* Handler for GtkWidget::key-press-event on the shortcuts list */ static gboolean bookmarks_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, NemoPlacesSidebar *sidebar) { guint modifiers; GtkTreeIter selected_iter; GtkTreePath *path; if (!get_selected_iter (sidebar, &selected_iter)) { return FALSE; } modifiers = gtk_accelerator_get_default_mod_mask (); if ((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_ISO_Enter || event->keyval == GDK_KEY_space)) { NemoWindowOpenFlags flags = 0; if ((event->state & modifiers) == GDK_SHIFT_MASK) { flags = NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else if ((event->state & modifiers) == GDK_CONTROL_MASK) { flags = NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } open_selected_bookmark (sidebar, GTK_TREE_MODEL (sidebar->store_filter), &selected_iter, flags); return TRUE; } if (event->keyval == GDK_KEY_Down && (event->state & modifiers) == GDK_MOD1_MASK) { return eject_or_unmount_selection (sidebar); } if (event->keyval == GDK_KEY_Up) { if (find_prev_row (sidebar, &selected_iter)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store_filter), &selected_iter); gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); gtk_tree_path_free (path); } return TRUE; } if (event->keyval == GDK_KEY_Down) { if (find_next_row (sidebar, &selected_iter)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store_filter), &selected_iter); gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); gtk_tree_path_free (path); } return TRUE; } if ((event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete) && (event->state & modifiers) == 0) { remove_selected_bookmarks (sidebar); return TRUE; } if ((event->keyval == GDK_KEY_F2) && (event->state & modifiers) == 0) { rename_selected_bookmark (sidebar); return TRUE; } return FALSE; } static gboolean free_popup_file_in_idle_cb (gpointer data) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (data); if (sidebar->popup_file != NULL) { nemo_file_unref (sidebar->popup_file); sidebar->popup_file = NULL; } sidebar->popup_file_idle_handler = 0; return FALSE; } static void popup_menu_deactivated (GtkMenuShell *menu_shell, gpointer data) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (data); /* The popup menu is deactivated. (I.E. hidden) We want to free popup_file, but can't right away as it might immediately get used if we're deactivation due to activating a menu item. So, we free it in idle */ if (sidebar->popup_file != NULL && sidebar->popup_file_idle_handler == 0) { sidebar->popup_file_idle_handler = g_idle_add (free_popup_file_in_idle_cb, sidebar); } } static void action_activated_callback (GtkMenuItem *item, ActionPayload *payload) { gchar *uri = NULL; GtkTreeIter iter; NemoPlacesSidebar *sidebar = payload->sidebar; if (get_selected_iter (sidebar, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); } if (!uri) { return; } NemoFile *file = nemo_file_get_by_uri (uri); NemoFile *parent = nemo_file_get_parent (file); GList *tmp = NULL; tmp = g_list_append (tmp, file); nemo_action_activate (NEMO_ACTION (payload->action), tmp, parent); nemo_file_list_free (tmp); g_free (uri); } static void add_action_popup_items (NemoPlacesSidebar *sidebar) { if (sidebar->action_items != NULL) g_list_free_full (sidebar->action_items, g_free); sidebar->action_items = NULL; GList *action_list = nemo_action_manager_list_actions (sidebar->action_manager); GtkWidget *item; GList *l; NemoAction *action; ActionPayload *payload; guint index = 8; for (l = action_list; l != NULL; l = l->next) { action = l->data; payload = g_new0 (ActionPayload, 1); payload->action = action; payload->sidebar = sidebar; item = gtk_menu_item_new_with_mnemonic (nemo_action_get_orig_label (action)); payload->item = item; g_signal_connect (item, "activate", G_CALLBACK (action_activated_callback), payload); gtk_widget_show (item); gtk_menu_shell_insert (GTK_MENU_SHELL (sidebar->popup_menu), item, index); sidebar->action_items = g_list_append (sidebar->action_items, payload); index ++; } } #if GTK_CHECK_VERSION (3, 24, 8) static void moved_to_rect_cb (GdkWindow *window, const GdkRectangle *flipped_rect, const GdkRectangle *final_rect, gboolean flipped_x, gboolean flipped_y, GtkMenu *menu) { g_signal_emit_by_name (menu, "popped-up", 0, flipped_rect, final_rect, flipped_x, flipped_y); // Don't let the emission run in gtkmenu.c g_signal_stop_emission_by_name (window, "moved-to-rect"); } static void popup_menu_realized (GtkWidget *menu, gpointer user_data) { GdkWindow *toplevel; toplevel = gtk_widget_get_window (gtk_widget_get_toplevel (menu)); g_signal_handlers_disconnect_by_func (toplevel, moved_to_rect_cb, menu); g_signal_connect (toplevel, "moved-to-rect", G_CALLBACK (moved_to_rect_cb), menu); } #endif /* Constructs the popup menu for the file list if needed */ static void bookmarks_build_popup_menu (NemoPlacesSidebar *sidebar) { GtkWidget *item; gboolean use_browser; if (sidebar->popup_menu) { return; } use_browser = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); sidebar->popup_menu = gtk_menu_new (); g_signal_connect (sidebar->popup_menu, "deactivate", G_CALLBACK (popup_menu_deactivated), sidebar); #if GTK_CHECK_VERSION (3, 24, 8) g_signal_connect (sidebar->popup_menu, "realize", G_CALLBACK (popup_menu_realized), sidebar); gtk_widget_realize (sidebar->popup_menu); #endif gtk_menu_attach_to_widget (GTK_MENU (sidebar->popup_menu), GTK_WIDGET (sidebar), bookmarks_popup_menu_detach_cb); item = gtk_image_menu_item_new_with_mnemonic (_("_Open")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), gtk_image_new_from_icon_name ("folder-open-symbolic", GTK_ICON_SIZE_MENU)); g_signal_connect (item, "activate", G_CALLBACK (open_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab")); sidebar->popup_menu_open_in_new_tab_item = item; g_signal_connect (item, "activate", G_CALLBACK (open_shortcut_in_new_tab_cb), sidebar); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); if (use_browser) { gtk_widget_show (item); } item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window")); g_signal_connect (item, "activate", G_CALLBACK (open_shortcut_in_new_window_cb), sidebar); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); if (use_browser) { gtk_widget_show (item); } sidebar->popup_menu_remove_rename_separator_item = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); item = gtk_menu_item_new_with_mnemonic (_("_Add Bookmark")); sidebar->popup_menu_add_shortcut_item = item; g_signal_connect (item, "activate", G_CALLBACK (add_shortcut_cb), sidebar); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_image_menu_item_new_with_label (_("Remove")); sidebar->popup_menu_remove_item = item; gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), gtk_image_new_from_icon_name ("list-remove-symbolic", GTK_ICON_SIZE_MENU)); g_signal_connect (item, "activate", G_CALLBACK (remove_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Rename...")); sidebar->popup_menu_rename_item = item; g_signal_connect (item, "activate", G_CALLBACK (rename_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); /* Nemo Actions */ sidebar->popup_menu_action_separator_item = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); /* Mount/Unmount/Eject menu items */ sidebar->popup_menu_separator_item = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); item = gtk_menu_item_new_with_mnemonic (_("_Mount")); sidebar->popup_menu_mount_item = item; g_signal_connect (item, "activate", G_CALLBACK (mount_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Unmount")); sidebar->popup_menu_unmount_item = item; g_signal_connect (item, "activate", G_CALLBACK (unmount_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Eject")); sidebar->popup_menu_eject_item = item; g_signal_connect (item, "activate", G_CALLBACK (eject_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Detect Media")); sidebar->popup_menu_rescan_item = item; g_signal_connect (item, "activate", G_CALLBACK (rescan_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Start")); sidebar->popup_menu_start_item = item; g_signal_connect (item, "activate", G_CALLBACK (start_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); item = gtk_menu_item_new_with_mnemonic (_("_Stop")); sidebar->popup_menu_stop_item = item; g_signal_connect (item, "activate", G_CALLBACK (stop_shortcut_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); /* Empty Trash menu item */ item = gtk_menu_item_new_with_mnemonic (_("Empty _Trash")); sidebar->popup_menu_empty_trash_item = item; g_signal_connect (item, "activate", G_CALLBACK (empty_trash_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); /* Properties menu item */ sidebar->popup_menu_properties_separator_item = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); item = gtk_menu_item_new_with_mnemonic (_("_Properties")); sidebar->popup_menu_properties_item = item; g_signal_connect (item, "activate", G_CALLBACK (properties_cb), sidebar); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); add_action_popup_items (sidebar); bookmarks_check_popup_sensitivity (sidebar); } static void bookmarks_update_popup_menu (NemoPlacesSidebar *sidebar) { bookmarks_build_popup_menu (sidebar); } static void bookmarks_popup_menu (NemoPlacesSidebar *sidebar, GdkEventButton *event) { bookmarks_update_popup_menu (sidebar); eel_pop_up_context_menu (GTK_MENU(sidebar->popup_menu), event); } /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */ static gboolean bookmarks_popup_menu_cb (GtkWidget *widget, NemoPlacesSidebar *sidebar) { bookmarks_popup_menu (sidebar, NULL); return TRUE; } static void actions_changed_callback (NemoPlacesSidebar *sidebar) { if (sidebar->popup_menu) { gtk_menu_detach (GTK_MENU (sidebar->popup_menu)); } } static gboolean bookmarks_button_release_event_cb (GtkWidget *widget, GdkEventButton *event, NemoPlacesSidebar *sidebar) { GtkTreePath *path; GtkTreeIter iter; GtkTreeModel *model; GtkTreeView *tree_view; gboolean res; path = NULL; if (event->type != GDK_BUTTON_RELEASE) { return TRUE; } if (clicked_eject_button (sidebar, &path)) { eject_or_unmount_bookmark (sidebar, path); gtk_tree_path_free (path); return FALSE; } tree_view = GTK_TREE_VIEW (widget); model = gtk_tree_view_get_model (tree_view); if (event->button == 1) { if (event->window != gtk_tree_view_get_bin_window (tree_view)) { return FALSE; } res = gtk_tree_view_get_path_at_pos (tree_view, (int) event->x, (int) event->y, &path, NULL, NULL, NULL); if (!res) { return FALSE; } gtk_tree_model_get_iter (model, &iter, path); open_selected_bookmark (sidebar, model, &iter, 0); gtk_tree_path_free (path); } return FALSE; } static gboolean bookmarks_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, NemoPlacesSidebar *sidebar) { GtkTreeModel *model; GtkTreeView *tree_view; GtkTreeIter iter; GtkTreePath *path = NULL; gboolean retval = FALSE; PlaceType row_type; if (event->type != GDK_BUTTON_PRESS) { /* ignore multiple clicks */ return TRUE; } tree_view = GTK_TREE_VIEW (widget); model = gtk_tree_view_get_model (tree_view); gtk_tree_view_get_path_at_pos (tree_view, (int) event->x, (int) event->y, &path, NULL, NULL, NULL); if (path == NULL || !gtk_tree_model_get_iter (model, &iter, path)) { return FALSE; } if (event->button == 3) { gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type, -1); if (row_type != PLACES_HEADING) { bookmarks_popup_menu (sidebar, event); } } else if (event->button == 2) { NemoWindowOpenFlags flags = 0; if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) { flags = (event->state & GDK_CONTROL_MASK) ? NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW : NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else { flags = NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND; } open_selected_bookmark (sidebar, model, &iter, flags); retval = TRUE; } gtk_tree_path_free (path); return retval; } static void update_expanded_state (GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data, gboolean expanded) { NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (user_data); if (sidebar->updating_sidebar) return; SectionType type; GtkTreeIter heading_iter; GtkTreeModel *model = gtk_tree_view_get_model (tree_view); gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &heading_iter, path); gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &type, -1); if (type == SECTION_COMPUTER) { sidebar->my_computer_expanded = expanded; g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_MY_COMPUTER_EXPANDED, expanded); } else if (type == SECTION_BOOKMARKS) { sidebar->bookmarks_expanded = expanded; g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_BOOKMARKS_EXPANDED, expanded); } else if (type == SECTION_DEVICES) { sidebar->devices_expanded = expanded; g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_DEVICES_EXPANDED, expanded); } else if (type == SECTION_NETWORK) { sidebar->network_expanded = expanded; g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_NETWORK_EXPANDED, expanded); } } static void row_collapsed_cb (GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { update_expanded_state (tree_view, iter, path, user_data, FALSE); } static void row_expanded_cb (GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { update_expanded_state (tree_view, iter, path, user_data, TRUE); } static void row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { GtkTreeIter iter; SectionType section_type; PlaceType place_type; NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (user_data); GtkTreeModel *model = gtk_tree_view_get_model (tree_view); gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, -1); if (place_type == PLACES_HEADING) { if (section_type == SECTION_COMPUTER) { sidebar->my_computer_expanded = !sidebar->my_computer_expanded; } else if (section_type == SECTION_BOOKMARKS) { sidebar->bookmarks_expanded = !sidebar->bookmarks_expanded; } else if (section_type == SECTION_DEVICES) { sidebar->devices_expanded = !sidebar->devices_expanded; } else if (section_type == SECTION_NETWORK) { sidebar->network_expanded = !sidebar->network_expanded; } restore_expand_state (sidebar); } } static void bookmarks_edited (GtkCellRenderer *cell, gchar *path_string, gchar *new_text, NemoPlacesSidebar *sidebar) { GtkTreePath *path; GtkTreeIter iter; NemoBookmark *bookmark; int index; g_object_set (cell, "editable", FALSE, NULL); path = gtk_tree_path_new_from_string (path_string); gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store_filter), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store_filter), &iter, PLACES_SIDEBAR_COLUMN_INDEX, &index, -1); gtk_tree_path_free (path); bookmark = nemo_bookmark_list_item_at (sidebar->bookmarks, index); if (bookmark != NULL) { nemo_bookmark_set_custom_name (bookmark, new_text); } } static void bookmarks_editing_canceled (GtkCellRenderer *cell, NemoPlacesSidebar *sidebar) { g_object_set (cell, "editable", FALSE, NULL); } static void trash_state_changed_cb (NemoTrashMonitor *trash_monitor, gboolean state, gpointer data) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (data); /* The trash icon changed, update the sidebar */ update_places (sidebar); bookmarks_check_popup_sensitivity (sidebar); } static gboolean tree_selection_func (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer user_data) { GtkTreeIter iter; PlaceType row_type; gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type, -1); if (row_type == PLACES_HEADING) { return FALSE; } return TRUE; } static void icon_cell_renderer_func (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { PlaceType type; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type == PLACES_HEADING) { g_object_set (cell, "visible", FALSE, NULL); } else { g_object_set (cell, "visible", TRUE, "xpad", 3, "ypad", 2, NULL); } } static void padding_cell_renderer_func (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { PlaceType type; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type == PLACES_HEADING) { g_object_set (cell, "visible", FALSE, "xpad", 0, "ypad", 0, NULL); } else { g_object_set (cell, "visible", TRUE, "ypad", 3, NULL); } } static void heading_cell_renderer_func (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { PlaceType type; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type == PLACES_HEADING) { g_object_set (cell, "visible", TRUE, NULL); } else { g_object_set (cell, "visible", FALSE, NULL); } } static gboolean row_visibility_function (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { NemoPlacesSidebar *sidebar = NEMO_PLACES_SIDEBAR (data); SectionType section_type; PlaceType type; gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1); if (type != PLACES_HEADING || section_type != SECTION_BOOKMARKS) return TRUE; if (sidebar->in_drag) return TRUE; if ((int)nemo_bookmark_list_length (sidebar->bookmarks) > sidebar->bookmark_breakpoint) return TRUE; return FALSE; } static void nemo_places_sidebar_init (NemoPlacesSidebar *sidebar) { GtkTreeView *tree_view; GtkTreeViewColumn *col, *expander_col, *eject_col, *expander_pad_col; GtkCellRenderer *cell; GtkTreeSelection *selection; GtkStyleContext *style_context; sidebar->action_manager = nemo_action_manager_new (); sidebar->action_manager_changed_id = g_signal_connect_swapped (sidebar->action_manager, "changed", G_CALLBACK (actions_changed_callback), sidebar); sidebar->action_items = NULL; sidebar->in_drag = FALSE; sidebar->desktop_dnd_source_fs = NULL; sidebar->desktop_dnd_can_delete_source = FALSE; sidebar->volume_monitor = g_volume_monitor_get (); sidebar->update_places_on_idle_id = 0; sidebar->my_computer_expanded = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_MY_COMPUTER_EXPANDED); sidebar->bookmarks_expanded = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_BOOKMARKS_EXPANDED); sidebar->devices_expanded = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_DEVICES_EXPANDED); sidebar->network_expanded = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_NETWORK_EXPANDED); gtk_widget_set_size_request (GTK_WIDGET (sidebar), 140, -1); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL); gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sidebar), GTK_SHADOW_IN); style_context = gtk_widget_get_style_context (GTK_WIDGET (sidebar)); gtk_style_context_set_junction_sides (style_context, GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT); /* Make it easier for theme authors to style the sidebar */ gtk_style_context_add_class (style_context, "nemo-places-sidebar"); /* tree view */ tree_view = GTK_TREE_VIEW (nemo_places_tree_view_new ()); gtk_tree_view_set_headers_visible (tree_view, FALSE); col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ()); expander_col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ()); eject_col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ()); expander_pad_col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new()); /* initial padding */ cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, cell, FALSE); /* headings */ cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, cell, FALSE); gtk_tree_view_column_set_attributes (col, cell, "text", PLACES_SIDEBAR_COLUMN_HEADING_TEXT, NULL); g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, "weight-set", TRUE, "ypad", 0, "xpad", 0, NULL); gtk_tree_view_column_set_cell_data_func (col, cell, heading_cell_renderer_func, sidebar, NULL); /* icon padding */ cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, cell, FALSE); gtk_tree_view_column_set_cell_data_func (col, cell, padding_cell_renderer_func, sidebar, NULL); /* icon renderer */ cell = gtk_cell_renderer_pixbuf_new (); g_object_set (cell, "follow-state", TRUE, NULL); gtk_tree_view_column_pack_start (col, cell, FALSE); gtk_tree_view_column_set_attributes (col, cell, "icon-name", PLACES_SIDEBAR_COLUMN_ICON, NULL); gtk_tree_view_column_set_cell_data_func (col, cell, icon_cell_renderer_func, sidebar, NULL); /* eject text renderer */ cell = nemo_cell_renderer_disk_new (); gtk_tree_view_column_pack_start (col, cell, TRUE); gtk_tree_view_column_set_attributes (col, cell, "text", PLACES_SIDEBAR_COLUMN_NAME, "visible", PLACES_SIDEBAR_COLUMN_EJECT, "disk-full-percent", PLACES_SIDEBAR_COLUMN_DF_PERCENT, "show-disk-full-percent", PLACES_SIDEBAR_COLUMN_SHOW_DF, NULL); g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); /* eject icon renderer */ cell = gtk_cell_renderer_pixbuf_new (); sidebar->eject_icon_cell_renderer = cell; g_object_set (cell, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, "yalign", 0.8, NULL); gtk_tree_view_column_pack_start (eject_col, cell, FALSE); gtk_tree_view_column_set_attributes (eject_col, cell, "visible", PLACES_SIDEBAR_COLUMN_EJECT, "icon-name", PLACES_SIDEBAR_COLUMN_EJECT_ICON, NULL); /* normal text renderer */ cell = nemo_cell_renderer_disk_new (); gtk_tree_view_column_pack_start (col, cell, TRUE); g_object_set (G_OBJECT (cell), "editable", FALSE, NULL); gtk_tree_view_column_set_attributes (col, cell, "text", PLACES_SIDEBAR_COLUMN_NAME, "visible", PLACES_SIDEBAR_COLUMN_NO_EJECT, "editable-set", PLACES_SIDEBAR_COLUMN_BOOKMARK, "disk-full-percent", PLACES_SIDEBAR_COLUMN_DF_PERCENT, "show-disk-full-percent", PLACES_SIDEBAR_COLUMN_SHOW_DF, NULL); g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); g_signal_connect (cell, "edited", G_CALLBACK (bookmarks_edited), sidebar); g_signal_connect (cell, "editing-canceled", G_CALLBACK (bookmarks_editing_canceled), sidebar); /* this is required to align the eject buttons to the right */ gtk_tree_view_column_set_max_width (GTK_TREE_VIEW_COLUMN (col), NEMO_ICON_SIZE_SMALLER); gtk_tree_view_column_set_sizing (expander_pad_col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (expander_pad_col, EXPANDER_PAD_COLUMN_WIDTH); gtk_tree_view_column_set_sizing (expander_col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (expander_col, EXPANDER_COLUMN_WIDTH); gtk_tree_view_column_set_sizing (eject_col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (eject_col, EJECT_COLUMN_WIDTH); gtk_tree_view_column_set_expand (col, TRUE); gtk_tree_view_append_column (tree_view, expander_pad_col); gtk_tree_view_append_column (tree_view, expander_col); gtk_tree_view_append_column (tree_view, col); gtk_tree_view_append_column (tree_view, eject_col); if (gtk_get_major_version () == 3 && gtk_get_minor_version () >= 16) { if (get_overlay_scrolling_enabled ()) { GtkTreeViewColumn *eject_pad_col; eject_pad_col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new()); cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (eject_pad_col, cell, FALSE); gtk_tree_view_column_set_sizing (eject_pad_col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (eject_pad_col, EJECT_PAD_COLUMN_WIDTH); gtk_tree_view_append_column (tree_view, eject_pad_col); } } gtk_tree_view_set_expander_column (tree_view, expander_col); sidebar->store = nemo_shortcuts_model_new (sidebar); gtk_tree_view_set_tooltip_column (tree_view, PLACES_SIDEBAR_COLUMN_TOOLTIP); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sidebar->store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING); sidebar->store_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sidebar->store), NULL); gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (sidebar->store_filter), (GtkTreeModelFilterVisibleFunc) row_visibility_function, sidebar, NULL); gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (sidebar->store_filter)); gtk_container_add (GTK_CONTAINER (sidebar), GTK_WIDGET (tree_view)); gtk_widget_show (GTK_WIDGET (tree_view)); gtk_widget_show (GTK_WIDGET (sidebar)); sidebar->tree_view = tree_view; gtk_tree_view_set_search_column (tree_view, PLACES_SIDEBAR_COLUMN_NAME); selection = gtk_tree_view_get_selection (tree_view); gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); gtk_tree_selection_set_select_function (selection, tree_selection_func, sidebar, NULL); gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view), GDK_BUTTON1_MASK, nemo_shortcuts_source_targets, G_N_ELEMENTS (nemo_shortcuts_source_targets), GDK_ACTION_MOVE); gtk_drag_dest_set (GTK_WIDGET (tree_view), 0, nemo_shortcuts_drop_targets, G_N_ELEMENTS (nemo_shortcuts_drop_targets), GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); g_signal_connect (tree_view, "key-press-event", G_CALLBACK (bookmarks_key_press_event_cb), sidebar); g_signal_connect (tree_view, "drag-motion", G_CALLBACK (drag_motion_callback), sidebar); g_signal_connect (tree_view, "drag-leave", G_CALLBACK (drag_leave_callback), sidebar); g_signal_connect (tree_view, "drag-data-received", G_CALLBACK (drag_data_received_callback), sidebar); g_signal_connect (tree_view, "drag-drop", G_CALLBACK (drag_drop_callback), sidebar); g_signal_connect (selection, "changed", G_CALLBACK (bookmarks_selection_changed_cb), sidebar); g_signal_connect (tree_view, "popup-menu", G_CALLBACK (bookmarks_popup_menu_cb), sidebar); g_signal_connect (tree_view, "button-press-event", G_CALLBACK (bookmarks_button_press_event_cb), sidebar); g_signal_connect (tree_view, "button-release-event", G_CALLBACK (bookmarks_button_release_event_cb), sidebar); g_signal_connect (tree_view, "row-expanded", G_CALLBACK (row_expanded_cb), sidebar); g_signal_connect (tree_view, "row-collapsed", G_CALLBACK (row_collapsed_cb), sidebar); g_signal_connect (tree_view, "row-activated", G_CALLBACK (row_activated_cb), sidebar); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR, G_CALLBACK(desktop_setting_changed_callback), sidebar); g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_SHOW_DESKTOP, G_CALLBACK(desktop_setting_changed_callback), sidebar); g_signal_connect_swapped (cinnamon_privacy_preferences, "changed::" NEMO_PREFERENCES_RECENT_ENABLED, G_CALLBACK(desktop_setting_changed_callback), sidebar); g_signal_connect_object (nemo_trash_monitor_get (), "trash_state_changed", G_CALLBACK (trash_state_changed_cb), sidebar, 0); } static void nemo_places_sidebar_dispose (GObject *object) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (object); sidebar->window = NULL; sidebar->tree_view = NULL; g_free (sidebar->uri); sidebar->uri = NULL; free_drag_data (sidebar); g_clear_object (&sidebar->unmount_notify); if (sidebar->bookmarks_changed_id != 0) { g_signal_handler_disconnect (sidebar->bookmarks, sidebar->bookmarks_changed_id); sidebar->bookmarks_changed_id = 0; } if (sidebar->action_manager_changed_id != 0) { g_signal_handler_disconnect (sidebar->action_manager, sidebar->action_manager_changed_id); sidebar->action_manager_changed_id = 0; } g_clear_object (&sidebar->action_manager); if (sidebar->popup_file != NULL) { nemo_file_unref (sidebar->popup_file); sidebar->popup_file = NULL; } if (sidebar->update_places_on_idle_id != 0) { g_source_remove (sidebar->update_places_on_idle_id); sidebar->update_places_on_idle_id = 0; } g_clear_object (&sidebar->store); if (sidebar->go_to_after_mount_slot) { g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), (gpointer *) &sidebar->go_to_after_mount_slot); sidebar->go_to_after_mount_slot = NULL; } g_signal_handlers_disconnect_by_func (nemo_window_state, breakpoint_changed_cb, sidebar); g_signal_handlers_disconnect_by_func (nemo_preferences, desktop_setting_changed_callback, sidebar); g_signal_handlers_disconnect_by_func (nemo_preferences, bookmarks_popup_menu_detach_cb, sidebar); g_signal_handlers_disconnect_by_func (gnome_background_preferences, desktop_setting_changed_callback, sidebar); g_signal_handlers_disconnect_by_func (cinnamon_privacy_preferences, desktop_setting_changed_callback, sidebar); if (sidebar->volume_monitor != NULL) { g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, volume_added_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, volume_removed_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, volume_changed_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, mount_added_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, mount_removed_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, mount_changed_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, drive_disconnected_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, drive_connected_callback, sidebar); g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, drive_changed_callback, sidebar); g_clear_object (&sidebar->volume_monitor); } G_OBJECT_CLASS (nemo_places_sidebar_parent_class)->dispose (object); } static void nemo_places_sidebar_class_init (NemoPlacesSidebarClass *class) { GObjectClass *oclass = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); oclass->dispose = nemo_places_sidebar_dispose; widget_class->style_set = nemo_places_sidebar_style_set; widget_class->focus = nemo_places_sidebar_focus; } static gboolean update_places_on_idle_callback (NemoPlacesSidebar *sidebar) { sidebar->update_places_on_idle_id = 0; update_places (sidebar); return FALSE; } static void update_places_on_idle (NemoPlacesSidebar *sidebar) { if (sidebar->update_places_on_idle_id != 0) { g_source_remove (sidebar->update_places_on_idle_id); sidebar->update_places_on_idle_id = 0; } sidebar->update_places_on_idle_id = g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) update_places_on_idle_callback, sidebar, NULL); } static void nemo_places_sidebar_set_parent_window (NemoPlacesSidebar *sidebar, NemoWindow *window) { NemoWindowSlot *slot; gint breakpoint; sidebar->window = window; slot = nemo_window_get_active_slot (window); sidebar->bookmarks = nemo_bookmark_list_get_default (); sidebar->uri = nemo_window_slot_get_current_uri (slot); breakpoint = g_settings_get_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT); if (breakpoint < 0) { // Default gsettings value is -1 (which translates to 'not previously set') breakpoint = nemo_bookmark_list_length (sidebar->bookmarks); g_settings_set_int (nemo_window_state, NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, breakpoint); } sidebar->bookmark_breakpoint = breakpoint; g_signal_connect_swapped (nemo_window_state, "changed::" NEMO_PREFERENCES_SIDEBAR_BOOKMARK_BREAKPOINT, G_CALLBACK (breakpoint_changed_cb), sidebar); sidebar->bookmarks_changed_id = g_signal_connect_swapped (sidebar->bookmarks, "changed", G_CALLBACK (update_places_on_idle), sidebar); g_signal_connect_object (window, "loading_uri", G_CALLBACK (loading_uri_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "volume_added", G_CALLBACK (volume_added_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "volume_removed", G_CALLBACK (volume_removed_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "volume_changed", G_CALLBACK (volume_changed_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "mount_added", G_CALLBACK (mount_added_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "mount_removed", G_CALLBACK (mount_removed_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "mount_changed", G_CALLBACK (mount_changed_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "drive_disconnected", G_CALLBACK (drive_disconnected_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "drive_connected", G_CALLBACK (drive_connected_callback), sidebar, 0); g_signal_connect_object (sidebar->volume_monitor, "drive_changed", G_CALLBACK (drive_changed_callback), sidebar, 0); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_ALWAYS_USE_BROWSER, G_CALLBACK (bookmarks_popup_menu_detach_cb), sidebar); update_places (sidebar); } static void nemo_places_sidebar_style_set (GtkWidget *widget, GtkStyle *previous_style) { NemoPlacesSidebar *sidebar; sidebar = NEMO_PLACES_SIDEBAR (widget); update_places (sidebar); } GtkWidget * nemo_places_sidebar_new (NemoWindow *window) { NemoPlacesSidebar *sidebar; sidebar = g_object_new (NEMO_TYPE_PLACES_SIDEBAR, NULL); nemo_places_sidebar_set_parent_window (sidebar, window); return GTK_WIDGET (sidebar); } /* Drag and drop interfaces */ /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */ static gboolean nemo_shortcuts_model_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *path) { GtkTreeModel *model; GtkTreeIter iter; PlaceType place_type; SectionType section_type; model = GTK_TREE_MODEL (drag_source); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type, -1); if (place_type != PLACES_HEADING && (section_type == SECTION_XDG_BOOKMARKS || section_type == SECTION_BOOKMARKS)) return TRUE; return FALSE; } static void _nemo_shortcuts_model_class_init (NemoShortcutsModelClass *klass) { } static void _nemo_shortcuts_model_init (NemoShortcutsModel *model) { model->sidebar = NULL; } static void _nemo_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface) { iface->row_draggable = nemo_shortcuts_model_row_draggable; } static GtkTreeStore * nemo_shortcuts_model_new (NemoPlacesSidebar *sidebar) { NemoShortcutsModel *model; GType model_types[PLACES_SIDEBAR_COLUMN_COUNT] = { G_TYPE_INT, G_TYPE_STRING, G_TYPE_DRIVE, G_TYPE_VOLUME, G_TYPE_MOUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN }; model = g_object_new (NEMO_TYPE_SHORTCUTS_MODEL, NULL); model->sidebar = sidebar; gtk_tree_store_set_column_types (GTK_TREE_STORE (model), PLACES_SIDEBAR_COLUMN_COUNT, model_types); return GTK_TREE_STORE (model); } nemo-4.4.2/src/nemo-places-sidebar.h000066400000000000000000000034361357442400300172410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * * This library 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 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA. * * Author : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk) * */ #ifndef _NEMO_PLACES_SIDEBAR_H #define _NEMO_PLACES_SIDEBAR_H #include "nemo-window.h" #include #define NEMO_PLACES_SIDEBAR_ID "places" #define NEMO_TYPE_PLACES_SIDEBAR nemo_places_sidebar_get_type() #define NEMO_PLACES_SIDEBAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PLACES_SIDEBAR, NemoPlacesSidebar)) #define NEMO_PLACES_SIDEBAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PLACES_SIDEBAR, NemoPlacesSidebarClass)) #define NEMO_IS_PLACES_SIDEBAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PLACES_SIDEBAR)) #define NEMO_IS_PLACES_SIDEBAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PLACES_SIDEBAR)) #define NEMO_PLACES_SIDEBAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PLACES_SIDEBAR, NemoPlacesSidebarClass)) GType nemo_places_sidebar_get_type (void); GtkWidget * nemo_places_sidebar_new (NemoWindow *window); #endif nemo-4.4.2/src/nemo-plugin-manager.c000066400000000000000000000031541357442400300172610ustar00rootroot00000000000000/* nemo-plugin-manager.c */ /* A GtkWidget that can be inserted into a UI that provides a simple interface for * managing the loading of extensions, actions and scripts */ #include #include "nemo-plugin-manager.h" #include "nemo-action-config-widget.h" #include "nemo-script-config-widget.h" #include "nemo-extension-config-widget.h" #include struct _NemoPluginManager { GtkBin parent_instance; }; G_DEFINE_TYPE (NemoPluginManager, nemo_plugin_manager, GTK_TYPE_BIN); static void nemo_plugin_manager_class_init (NemoPluginManagerClass *klass) { } static void nemo_plugin_manager_init (NemoPluginManager *self) { GtkWidget *widget, *grid; grid = gtk_grid_new (); gtk_widget_set_margin_left (grid, 10); gtk_widget_set_margin_right (grid, 10); gtk_widget_set_margin_top (grid, 10); gtk_widget_set_margin_bottom (grid, 10); gtk_grid_set_row_spacing (GTK_GRID (grid), 10); gtk_grid_set_column_spacing (GTK_GRID (grid), 10); gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE); gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE); widget = nemo_action_config_widget_new (); gtk_grid_attach (GTK_GRID (grid), widget, 0, 0, 1, 1); widget = nemo_script_config_widget_new (); gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1); widget = nemo_extension_config_widget_new (); gtk_grid_attach (GTK_GRID (grid), widget, 0, 1, 2, 1); gtk_container_add (GTK_CONTAINER (self), grid); gtk_widget_show_all (GTK_WIDGET (self)); } NemoPluginManager * nemo_plugin_manager_new (void) { return g_object_new (NEMO_TYPE_PLUGIN_MANAGER, NULL); } nemo-4.4.2/src/nemo-plugin-manager.h000066400000000000000000000011251357442400300172620ustar00rootroot00000000000000/* nemo-plugin-manager.h */ /* A GtkWidget that can be inserted into a UI that provides a simple interface for * managing the loading of extensions, actions and scripts */ #ifndef __NEMO_PLUGIN_MANAGER_H__ #define __NEMO_PLUGIN_MANAGER_H__ #include #include G_BEGIN_DECLS #define NEMO_TYPE_PLUGIN_MANAGER (nemo_plugin_manager_get_type()) G_DECLARE_FINAL_TYPE (NemoPluginManager, nemo_plugin_manager, NEMO, PLUGIN_MANAGER, GtkBin) NemoPluginManager *nemo_plugin_manager_new (void); G_END_DECLS #endif /* __NEMO_PLUGIN_MANAGER_H__ */ nemo-4.4.2/src/nemo-previewer.c000066400000000000000000000126311357442400300163630ustar00rootroot00000000000000/* * nemo-previewer: nemo previewer DBus wrapper * * Copyright (C) 2011, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #include "nemo-previewer.h" #define DEBUG_FLAG NEMO_DEBUG_PREVIEWER #include #include G_DEFINE_TYPE (NemoPreviewer, nemo_previewer, G_TYPE_OBJECT); #define PREVIEWER_DBUS_NAME "org.nemo.Preview" #define PREVIEWER_DBUS_IFACE "org.nemo.Preview" #define PREVIEWER_DBUS_PATH "/org/nemo/Preview" static NemoPreviewer *singleton = NULL; struct _NemoPreviewerPriv { GDBusConnection *connection; }; static void nemo_previewer_dispose (GObject *object) { NemoPreviewer *self = NEMO_PREVIEWER (object); DEBUG ("%p", self); g_clear_object (&self->priv->connection); G_OBJECT_CLASS (nemo_previewer_parent_class)->dispose (object); } static GObject * nemo_previewer_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *retval; if (singleton != NULL) return G_OBJECT (singleton); retval = G_OBJECT_CLASS (nemo_previewer_parent_class)->constructor (type, n_construct_params, construct_params); singleton = NEMO_PREVIEWER (retval); g_object_add_weak_pointer (retval, (gpointer) &singleton); return retval; } static void nemo_previewer_init (NemoPreviewer *self) { GError *error = NULL; self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_PREVIEWER, NemoPreviewerPriv); self->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (error != NULL) { g_printerr ("Unable to initialize DBus connection: %s", error->message); g_error_free (error); return; } } static void nemo_previewer_class_init (NemoPreviewerClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->constructor = nemo_previewer_constructor; oclass->dispose = nemo_previewer_dispose; g_type_class_add_private (klass, sizeof (NemoPreviewerPriv)); } static void previewer_show_file_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NemoPreviewer *self = user_data; GError *error = NULL; g_dbus_connection_call_finish (self->priv->connection, res, &error); if (error != NULL) { DEBUG ("Unable to call ShowFile on NemoPreviewer: %s", error->message); g_error_free (error); } g_object_unref (self); } static void previewer_close_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NemoPreviewer *self = user_data; GError *error = NULL; g_dbus_connection_call_finish (self->priv->connection, res, &error); if (error != NULL) { DEBUG ("Unable to call Close on NemoPreviewer: %s", error->message); g_error_free (error); } g_object_unref (self); } NemoPreviewer * nemo_previewer_get_singleton (void) { return g_object_new (NEMO_TYPE_PREVIEWER, NULL); } void nemo_previewer_call_show_file (NemoPreviewer *self, const gchar *uri, guint xid, gboolean close_if_already_visible) { if (self->priv->connection == NULL) { g_printerr ("No DBus connection available"); return; } g_dbus_connection_call (self->priv->connection, PREVIEWER_DBUS_NAME, PREVIEWER_DBUS_PATH, PREVIEWER_DBUS_IFACE, "ShowFile", g_variant_new ("(sib)", uri, xid, close_if_already_visible), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, previewer_show_file_ready_cb, g_object_ref (self)); } void nemo_previewer_call_close (NemoPreviewer *self) { if (self->priv->connection == NULL) { g_printerr ("No DBus connection available"); return; } /* don't autostart the previewer if it's not running */ g_dbus_connection_call (self->priv->connection, PREVIEWER_DBUS_NAME, PREVIEWER_DBUS_PATH, PREVIEWER_DBUS_IFACE, "Close", NULL, NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, previewer_close_ready_cb, g_object_ref (self)); } nemo-4.4.2/src/nemo-previewer.h000066400000000000000000000041611357442400300163670ustar00rootroot00000000000000/* * nemo-previewer: nemo previewer DBus wrapper * * Copyright (C) 2011, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #ifndef __NEMO_PREVIEWER_H__ #define __NEMO_PREVIEWER_H__ #include G_BEGIN_DECLS #define NEMO_TYPE_PREVIEWER nemo_previewer_get_type() #define NEMO_PREVIEWER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PREVIEWER, NemoPreviewer)) #define NEMO_PREVIEWER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PREVIEWER, NemoPreviewerClass)) #define NEMO_IS_PREVIEWER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PREVIEWER)) #define NEMO_IS_PREVIEWER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PREVIEWER)) #define NEMO_PREVIEWER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PREVIEWER, NemoPreviewerClass)) typedef struct _NemoPreviewerPriv NemoPreviewerPriv; typedef struct { GObject parent; /* private */ NemoPreviewerPriv *priv; } NemoPreviewer; typedef struct { GObjectClass parent_class; } NemoPreviewerClass; GType nemo_previewer_get_type (void); NemoPreviewer *nemo_previewer_get_singleton (void); void nemo_previewer_call_show_file (NemoPreviewer *previewer, const gchar *uri, guint xid, gboolean close_if_already_visible); void nemo_previewer_call_close (NemoPreviewer *previewer); G_END_DECLS #endif /* __NEMO_PREVIEWER_H__ */ nemo-4.4.2/src/nemo-progress-info-widget.c000066400000000000000000000243401357442400300204310ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-progress-info-widget.h: file operation progress user interface. * * Copyright (C) 2007, 2011 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Alexander Larsson * Cosimo Cecchi * */ #include #include #include "nemo-progress-info-widget.h" #include "nemo-job-queue.h" enum { PROP_INFO = 1, NUM_PROPERTIES }; #define START_ICON "media-playback-start-symbolic" #define STOP_ICON "media-playback-stop-symbolic" static GParamSpec *properties[NUM_PROPERTIES] = { NULL }; G_DEFINE_TYPE (NemoProgressInfoWidget, nemo_progress_info_widget, GTK_TYPE_BOX); static void update_data (NemoProgressInfoWidget *self) { char *status, *details; char *markup; status = nemo_progress_info_get_status (self->priv->info); gtk_label_set_text (GTK_LABEL (self->priv->status), status); g_free (status); details = nemo_progress_info_get_details (self->priv->info); markup = g_markup_printf_escaped ("%s", details); gtk_label_set_markup (GTK_LABEL (self->priv->details), markup); g_free (details); g_free (markup); } static void update_progress (NemoProgressInfoWidget *self) { double progress; progress = nemo_progress_info_get_progress (self->priv->info); if (progress < 0) { gtk_progress_bar_pulse (GTK_PROGRESS_BAR (self->priv->progress_bar)); } else { gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (self->priv->progress_bar), progress); } } static void on_info_started (NemoProgressInfoWidget *self) { gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), "running"); } static void on_info_finished (NemoProgressInfoWidget *self) { gtk_widget_destroy (GTK_WIDGET (self)); } static void cancel_clicked (GtkWidget *button, NemoProgressInfoWidget *self) { nemo_progress_info_cancel (self->priv->info); NemoJobQueue *queue = nemo_job_queue_get (); nemo_job_queue_start_job_by_info (queue, self->priv->info); gtk_widget_set_sensitive (button, FALSE); } static void start_clicked (GtkWidget *button, NemoProgressInfoWidget *self) { NemoJobQueue *queue = nemo_job_queue_get (); nemo_job_queue_start_job_by_info (queue, self->priv->info); } static void nemo_progress_info_widget_constructed (GObject *obj) { GtkWidget *label, *progress_bar, *hbox, *vbox, *button, *view, *bb, *main_box; NemoProgressInfoWidget *self = NEMO_PROGRESS_INFO_WIDGET (obj); NemoProgressInfoWidgetPriv *priv = NEMO_PROGRESS_INFO_WIDGET (obj)->priv; G_OBJECT_CLASS (nemo_progress_info_widget_parent_class)->constructed (obj); main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (self), main_box); priv->separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start (GTK_BOX (main_box), priv->separator, FALSE, FALSE, 5); priv->stack = gtk_stack_new (); gtk_stack_set_transition_type (GTK_STACK (priv->stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE); gtk_stack_set_transition_duration (GTK_STACK (priv->stack), 200); gtk_box_pack_start (GTK_BOX (main_box), priv->stack, FALSE, FALSE, 0); gtk_widget_show_all (main_box); /* contruct the initial stack page (job just queued, minimal info and * start & cancel buttons) */ view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_stack_add_named (GTK_STACK (priv->stack), view, "pending"); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (view), hbox, TRUE, TRUE, 0); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gchar *initial_details = nemo_progress_info_get_initial_details (self->priv->info); gchar *markup = g_markup_printf_escaped ("%s", initial_details); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (initial_details); g_free (markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_label_set_max_width_chars (GTK_LABEL (label), 50); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); priv->pre_info = label; bb = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_set_halign (bb, GTK_ALIGN_START); gtk_widget_set_valign (bb, GTK_ALIGN_CENTER); gtk_box_pack_end (GTK_BOX (hbox), bb, FALSE, FALSE, 0); button = gtk_button_new_from_icon_name (START_ICON, GTK_ICON_SIZE_BUTTON); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_box_pack_start (GTK_BOX (bb), button, FALSE, FALSE, 2); g_signal_connect (button, "clicked", G_CALLBACK (start_clicked), self); button = gtk_button_new_from_icon_name (STOP_ICON, GTK_ICON_SIZE_BUTTON); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_box_pack_start (GTK_BOX (bb), button, FALSE, FALSE, 2); g_signal_connect (button, "clicked", G_CALLBACK (cancel_clicked), self); gtk_widget_show_all (view); /* construct normal in-progress stack page */ view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_stack_add_named (GTK_STACK (priv->stack), view, "running"); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (view), hbox, TRUE, TRUE, 0); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); label = gtk_label_new ("status"); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_label_set_max_width_chars (GTK_LABEL (label), 40); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, FALSE, 2); priv->status = label; progress_bar = gtk_progress_bar_new (); priv->progress_bar = progress_bar; gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (progress_bar), 0.05); gtk_box_pack_start(GTK_BOX (vbox), progress_bar, TRUE, FALSE, 2); label = gtk_label_new ("details"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_max_width_chars (GTK_LABEL (label), 50); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, FALSE, 2); priv->details = label; bb = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_set_halign (bb, GTK_ALIGN_START); gtk_widget_set_valign (bb, GTK_ALIGN_CENTER); gtk_box_pack_end (GTK_BOX (hbox), bb, FALSE, FALSE, 0); button = gtk_button_new_from_icon_name (START_ICON, GTK_ICON_SIZE_BUTTON); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_set_sensitive (button, FALSE); gtk_box_pack_start (GTK_BOX (bb), button, FALSE, FALSE, 2); button = gtk_button_new_from_icon_name (STOP_ICON, GTK_ICON_SIZE_BUTTON); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_box_pack_start (GTK_BOX (bb), button, FALSE, FALSE, 2); g_signal_connect (button, "clicked", G_CALLBACK (cancel_clicked), self); gtk_widget_show_all (view); update_data (self); update_progress (self); g_signal_connect_swapped (priv->info, "changed", G_CALLBACK (update_data), self); g_signal_connect_swapped (priv->info, "progress-changed", G_CALLBACK (update_progress), self); gboolean started = nemo_progress_info_get_is_started (self->priv->info); gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), started ? "running" : "pending"); g_signal_connect_swapped (priv->info, "started", G_CALLBACK (on_info_started), self); g_signal_connect_swapped (priv->info, "finished", G_CALLBACK (on_info_finished), self); } static void nemo_progress_info_widget_dispose (GObject *obj) { NemoProgressInfoWidget *self = NEMO_PROGRESS_INFO_WIDGET (obj); g_clear_object (&self->priv->info); G_OBJECT_CLASS (nemo_progress_info_widget_parent_class)->dispose (obj); } static void nemo_progress_info_widget_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoProgressInfoWidget *self = NEMO_PROGRESS_INFO_WIDGET (object); switch (property_id) { case PROP_INFO: self->priv->info = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_progress_info_widget_init (NemoProgressInfoWidget *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_PROGRESS_INFO_WIDGET, NemoProgressInfoWidgetPriv); } static void nemo_progress_info_widget_class_init (NemoProgressInfoWidgetClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->set_property = nemo_progress_info_widget_set_property; oclass->constructed = nemo_progress_info_widget_constructed; oclass->dispose = nemo_progress_info_widget_dispose; properties[PROP_INFO] = g_param_spec_object ("info", "NemoProgressInfo", "The NemoProgressInfo associated with this widget", NEMO_TYPE_PROGRESS_INFO, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); g_type_class_add_private (klass, sizeof (NemoProgressInfoWidgetPriv)); } GtkWidget * nemo_progress_info_widget_new (NemoProgressInfo *info) { return g_object_new (NEMO_TYPE_PROGRESS_INFO_WIDGET, "info", info, "orientation", GTK_ORIENTATION_VERTICAL, "homogeneous", FALSE, "spacing", 5, NULL); } nemo-4.4.2/src/nemo-progress-info-widget.h000066400000000000000000000051131357442400300204330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-progress-info-widget.h: file operation progress user interface. * * Copyright (C) 2007, 2011 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Alexander Larsson * Cosimo Cecchi * */ #ifndef __NEMO_PROGRESS_INFO_WIDGET_H__ #define __NEMO_PROGRESS_INFO_WIDGET_H__ #include #include #define NEMO_TYPE_PROGRESS_INFO_WIDGET nemo_progress_info_widget_get_type() #define NEMO_PROGRESS_INFO_WIDGET(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PROGRESS_INFO_WIDGET, NemoProgressInfoWidget)) #define NEMO_PROGRESS_INFO_WIDGET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PROGRESS_INFO_WIDGET, NemoProgressInfoWidgetClass)) #define NEMO_IS_PROGRESS_INFO_WIDGET(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PROGRESS_INFO_WIDGET)) #define NEMO_IS_PROGRESS_INFO_WIDGET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PROGRESS_INFO_WIDGET)) #define NEMO_PROGRESS_INFO_WIDGET_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PROGRESS_INFO_WIDGET, NemoProgressInfoWidgetClass)) typedef struct _NemoProgressInfoWidgetPriv NemoProgressInfoWidgetPriv; typedef struct { GtkBox parent; /* private */ NemoProgressInfoWidgetPriv *priv; } NemoProgressInfoWidget; typedef struct { GtkBoxClass parent_class; } NemoProgressInfoWidgetClass; struct _NemoProgressInfoWidgetPriv { NemoProgressInfo *info; GtkWidget *stack; GtkWidget *separator; /* pre-start page */ GtkWidget *pre_info; /* GtkLabel */ GtkWidget *status; /* GtkLabel */ GtkWidget *details; /* GtkLabel */ GtkWidget *progress_bar; }; GType nemo_progress_info_widget_get_type (void); GtkWidget * nemo_progress_info_widget_new (NemoProgressInfo *info); #endif /* __NEMO_PROGRESS_INFO_WIDGET_H__ */ nemo-4.4.2/src/nemo-progress-ui-handler.c000066400000000000000000000340241357442400300202450ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-progress-ui-handler.c: file operation progress user interface. * * Copyright (C) 2007, 2011 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Alexander Larsson * Cosimo Cecchi * */ #include #include "nemo-progress-ui-handler.h" #include "nemo-application.h" #include "nemo-progress-info-widget.h" #include #include #include #include #include #include struct _NemoProgressUIHandlerPriv { NemoProgressInfoManager *manager; GtkWidget *progress_window; GtkWidget *window_vbox; GtkWidget *list; guint active_infos; guint active_percent; GList *infos; GtkStatusIcon *status_icon; gboolean should_show_status_icon; }; G_DEFINE_TYPE (NemoProgressUIHandler, nemo_progress_ui_handler, G_TYPE_OBJECT); static gboolean status_icon_button_release_cb (GtkStatusIcon *icon, GdkEvent *event, NemoProgressUIHandler *self) { self->priv->should_show_status_icon = FALSE; gtk_status_icon_set_visible (icon, FALSE); gtk_window_present (GTK_WINDOW (self->priv->progress_window)); return FALSE; } static void progress_ui_handler_ensure_status_icon (NemoProgressUIHandler *self) { GtkStatusIcon *status_icon; if (self->priv->status_icon != NULL) { return; } status_icon = gtk_status_icon_new_from_icon_name ("progress-0-symbolic"); g_signal_connect (status_icon, "button-release-event", (GCallback) status_icon_button_release_cb, self); gtk_status_icon_set_visible (status_icon, FALSE); self->priv->status_icon = status_icon; } static gchar * get_icon_name_from_percent (guint pct) { gchar *icon_name; guint rounded = 0; gint ones = pct % 10; if (ones < 5) rounded = pct - ones; else rounded = pct + (10 - ones); icon_name = g_strdup_printf ("progress-%d", rounded); return icon_name; } static void progress_ui_handler_update_status_icon (NemoProgressUIHandler *self) { gchar *tooltip; progress_ui_handler_ensure_status_icon (self); gchar *launchpad_sucks = THOU_TO_STR (self->priv->active_infos); tooltip = g_strdup_printf (ngettext ("%1$s file operation active. %2$d%% complete.", "%1$s file operations active. %2$d%% complete.", self->priv->active_infos), launchpad_sucks, self->priv->active_percent); gtk_status_icon_set_tooltip_text (self->priv->status_icon, tooltip); gchar *name = get_icon_name_from_percent (self->priv->active_percent); gtk_status_icon_set_from_icon_name (self->priv->status_icon, name); g_free (name); g_free (tooltip); gtk_status_icon_set_visible (self->priv->status_icon, self->priv->should_show_status_icon); } static gboolean progress_window_delete_event (GtkWidget *widget, GdkEvent *event, NemoProgressUIHandler *self) { gtk_widget_hide (widget); self->priv->should_show_status_icon = TRUE; progress_ui_handler_update_status_icon (self); return TRUE; } static void ensure_first_separator_hidden (NemoProgressUIHandler *self) { GList *l = gtk_container_get_children (GTK_CONTAINER (self->priv->list)); if (l == NULL) return; NemoProgressInfoWidgetPriv *priv = NEMO_PROGRESS_INFO_WIDGET (l->data)->priv; gtk_widget_hide (GTK_WIDGET (priv->separator)); g_list_free (l); } static void progress_ui_handler_sort_by_active (NemoProgressUIHandler *self) { gint first_pending = -1; gint current_index = 0; GList *iter; GList *l = gtk_container_get_children (GTK_CONTAINER (self->priv->list)); if (l == NULL) return; for (iter = l; iter != NULL; iter = iter->next) { NemoProgressInfoWidgetPriv *priv = NEMO_PROGRESS_INFO_WIDGET (iter->data)->priv; if (nemo_progress_info_get_is_started (priv->info)) { if (first_pending > 0) { gtk_box_reorder_child (GTK_BOX (self->priv->list), GTK_WIDGET (iter->data), first_pending); break; } } else { if (first_pending == -1) { first_pending = current_index; } } current_index++; } g_list_free (l); } static void progress_ui_handler_ensure_window (NemoProgressUIHandler *self) { NemoProgressUIHandlerPriv *priv = NEMO_PROGRESS_UI_HANDLER (self)->priv; GtkWidget *main_box, *progress_window; GtkWidget *w, *frame; if (self->priv->progress_window != NULL) { return; } progress_window = xapp_gtk_window_new (GTK_WINDOW_TOPLEVEL); self->priv->progress_window = progress_window; gtk_window_set_resizable (GTK_WINDOW (progress_window), FALSE); gtk_window_set_default_size (GTK_WINDOW (progress_window), 500, -1); gtk_window_set_title (GTK_WINDOW (progress_window), _("File Operations")); gtk_window_set_wmclass (GTK_WINDOW (progress_window), "file_progress", "Nemo"); gtk_window_set_position (GTK_WINDOW (progress_window), GTK_WIN_POS_CENTER); xapp_gtk_window_set_icon_name (XAPP_GTK_WINDOW (progress_window), "system-run"); main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); gtk_container_add (GTK_CONTAINER (progress_window), main_box); self->priv->window_vbox = main_box; frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); priv->list = w; gtk_container_add (GTK_CONTAINER (frame), w); g_object_set (priv->list, "margin-left", 5, "margin-right", 5, "margin-top", 5, "margin-bottom", 5, NULL); gtk_box_pack_start (GTK_BOX (main_box), frame, FALSE, FALSE, 0); gtk_widget_show_all (main_box); g_signal_connect (progress_window, "delete-event", (GCallback) progress_window_delete_event, self); } static void progress_ui_handler_add_to_window (NemoProgressUIHandler *self, NemoProgressInfo *info) { GtkWidget *progress; progress = nemo_progress_info_widget_new (info); progress_ui_handler_ensure_window (self); gtk_box_pack_start (GTK_BOX (self->priv->list), progress, FALSE, FALSE, 0); gtk_widget_show (progress); ensure_first_separator_hidden (self); progress_ui_handler_sort_by_active (self); } static void progress_ui_handler_show_complete_notification (NemoProgressUIHandler *self) { NotifyNotification *complete_notification; complete_notification = notify_notification_new (_("File Operations"), _("All file operations have been successfully completed"), NULL); notify_notification_show (complete_notification, NULL); g_object_unref (complete_notification); } static void progress_ui_handler_hide_status (NemoProgressUIHandler *self) { if (self->priv->status_icon != NULL) { self->priv->should_show_status_icon = FALSE; gtk_status_icon_set_visible (self->priv->status_icon, FALSE); } } static void progress_info_finished_cb (NemoProgressInfo *info, NemoProgressUIHandler *self) { self->priv->active_infos--; self->priv->infos = g_list_remove (self->priv->infos, info); if (self->priv->active_infos > 0) { if (!gtk_widget_get_visible (self->priv->progress_window)) { progress_ui_handler_update_status_icon (self); } ensure_first_separator_hidden (self); } else { if (gtk_widget_get_visible (self->priv->progress_window)) { gtk_widget_hide (self->priv->progress_window); } else { progress_ui_handler_hide_status (self); progress_ui_handler_show_complete_notification (self); } } } static void progress_info_changed_cb (NemoProgressInfo *info, NemoProgressUIHandler *self) { if (g_list_length(self->priv->infos) > 0) { NemoProgressInfo *first_info = (NemoProgressInfo *) g_list_first(self->priv->infos)->data; GList *l; double progress = 0.0; int i = 0; for (l = self->priv->infos; l != NULL; l = l->next) { progress = (progress + nemo_progress_info_get_progress (l->data)) / (double) ++i; } if (progress > 0) { int iprogress = progress * 100; gchar *str = g_strdup_printf (_("%d%% %s"), iprogress, nemo_progress_info_get_status(first_info)); gtk_window_set_title (GTK_WINDOW (self->priv->progress_window), str); xapp_gtk_window_set_progress (XAPP_GTK_WINDOW (self->priv->progress_window), iprogress); g_free (str); self->priv->active_percent = iprogress; if (self->priv->should_show_status_icon) { progress_ui_handler_update_status_icon (self); } } else { gtk_window_set_title (GTK_WINDOW (self->priv->progress_window), nemo_progress_info_get_status(first_info)); xapp_gtk_window_set_progress (XAPP_GTK_WINDOW (self->priv->progress_window), 0); } } } static void progress_info_started_cb (NemoProgressUIHandler *self) { progress_ui_handler_sort_by_active (self); ensure_first_separator_hidden (self); } static void handle_new_progress_info (NemoProgressUIHandler *self, NemoProgressInfo *info) { self->priv->infos = g_list_append (self->priv->infos, info); g_signal_connect_after (info, "finished", G_CALLBACK (progress_info_finished_cb), self); g_signal_connect_swapped (info, "started", G_CALLBACK (progress_info_started_cb), self); g_signal_connect (info, "progress-changed", G_CALLBACK (progress_info_changed_cb), self); self->priv->active_infos++; if (self->priv->active_infos == 1) { /* this is the only active operation, present the window */ progress_ui_handler_add_to_window (self, info); gtk_window_present (GTK_WINDOW (self->priv->progress_window)); gtk_window_set_title (GTK_WINDOW (self->priv->progress_window), nemo_progress_info_get_details(info)); xapp_gtk_window_set_icon_name (XAPP_GTK_WINDOW (self->priv->progress_window), "system-run"); } else { progress_ui_handler_add_to_window (self, info); if (self->priv->should_show_status_icon) { progress_ui_handler_update_status_icon (self); } if (gtk_widget_get_visible (GTK_WIDGET (self->priv->progress_window))) { gtk_window_present (GTK_WINDOW (self->priv->progress_window)); } } } typedef struct { NemoProgressInfo *info; NemoProgressUIHandler *self; } TimeoutData; static void timeout_data_free (TimeoutData *data) { g_clear_object (&data->self); g_clear_object (&data->info); g_slice_free (TimeoutData, data); } static TimeoutData * timeout_data_new (NemoProgressUIHandler *self, NemoProgressInfo *info) { TimeoutData *retval; retval = g_slice_new0 (TimeoutData); retval->self = g_object_ref (self); retval->info = g_object_ref (info); return retval; } static gboolean new_op_queued_timeout (TimeoutData *data) { NemoProgressInfo *info = data->info; NemoProgressUIHandler *self = data->self; if (nemo_progress_info_get_is_paused (info)) { return TRUE; } if (!nemo_progress_info_get_is_finished (info)) { handle_new_progress_info (self, info); } timeout_data_free (data); return FALSE; } static void release_application (NemoProgressInfo *info, NemoProgressUIHandler *self) { NemoApplication *app; /* release the GApplication hold we acquired */ app = nemo_application_get_singleton (); g_application_release (G_APPLICATION (app)); } static void progress_info_queued_cb (NemoProgressInfo *info, NemoProgressUIHandler *self) { NemoApplication *app; TimeoutData *data; /* hold GApplication so we never quit while there's an operation pending */ app = nemo_application_get_singleton (); g_application_hold (G_APPLICATION (app)); g_signal_connect (info, "finished", G_CALLBACK (release_application), self); data = timeout_data_new (self, info); /* timeout for the progress window to appear */ g_timeout_add_seconds (2, (GSourceFunc) new_op_queued_timeout, data); } static void new_progress_info_cb (NemoProgressInfoManager *manager, NemoProgressInfo *info, NemoProgressUIHandler *self) { g_signal_connect (info, "queued", G_CALLBACK (progress_info_queued_cb), self); } static void nemo_progress_ui_handler_dispose (GObject *obj) { NemoProgressUIHandler *self = NEMO_PROGRESS_UI_HANDLER (obj); g_clear_object (&self->priv->manager); G_OBJECT_CLASS (nemo_progress_ui_handler_parent_class)->dispose (obj); } static void nemo_progress_ui_handler_init (NemoProgressUIHandler *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_PROGRESS_UI_HANDLER, NemoProgressUIHandlerPriv); self->priv->manager = nemo_progress_info_manager_new (); g_signal_connect (self->priv->manager, "new-progress-info", G_CALLBACK (new_progress_info_cb), self); self->priv->should_show_status_icon = FALSE; } static void nemo_progress_ui_handler_class_init (NemoProgressUIHandlerClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->dispose = nemo_progress_ui_handler_dispose; g_type_class_add_private (klass, sizeof (NemoProgressUIHandlerPriv)); } NemoProgressUIHandler * nemo_progress_ui_handler_new (void) { return g_object_new (NEMO_TYPE_PROGRESS_UI_HANDLER, NULL); } nemo-4.4.2/src/nemo-progress-ui-handler.h000066400000000000000000000044021357442400300202470ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-progress-ui-handler.h: file operation progress user interface. * * Copyright (C) 2007, 2011 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Alexander Larsson * Cosimo Cecchi * */ #ifndef __NEMO_PROGRESS_UI_HANDLER_H__ #define __NEMO_PROGRESS_UI_HANDLER_H__ #include G_BEGIN_DECLS #define NEMO_TYPE_PROGRESS_UI_HANDLER nemo_progress_ui_handler_get_type() #define NEMO_PROGRESS_UI_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PROGRESS_UI_HANDLER, NemoProgressUIHandler)) #define NEMO_PROGRESS_UI_HANDLER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PROGRESS_UI_HANDLER, NemoProgressUIHandlerClass)) #define NEMO_IS_PROGRESS_UI_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PROGRESS_UI_HANDLER)) #define NEMO_IS_PROGRESS_UI_HANDLER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PROGRESS_UI_HANDLER)) #define NEMO_PROGRESS_UI_HANDLER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PROGRESS_UI_HANDLER, NemoProgressUIHandlerClass)) typedef struct _NemoProgressUIHandlerPriv NemoProgressUIHandlerPriv; typedef struct { GObject parent; /* private */ NemoProgressUIHandlerPriv *priv; } NemoProgressUIHandler; typedef struct { GObjectClass parent_class; } NemoProgressUIHandlerClass; GType nemo_progress_ui_handler_get_type (void); NemoProgressUIHandler * nemo_progress_ui_handler_new (void); G_END_DECLS #endif /* __NEMO_PROGRESS_UI_HANDLER_H__ */ nemo-4.4.2/src/nemo-properties-window.c000066400000000000000000004304611357442400300200610ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-properties-window.c - window that lets user modify file properties Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #include #include "nemo-properties-window.h" #include "nemo-desktop-item-properties.h" #include "nemo-error-reporting.h" #include "nemo-mime-actions.h" #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_VFS_H #include #elif HAVE_SYS_MOUNT_H #if HAVE_SYS_PARAM_H #include #endif #include #endif #define USED_FILL_R 0.988235294 #define USED_FILL_G 0.91372549 #define USED_FILL_B 0.309803922 #define FREE_FILL_R 0.447058824 #define FREE_FILL_G 0.623529412 #define FREE_FILL_B 0.811764706 #define PREVIEW_IMAGE_WIDTH 96 #define STACK_INNER_BORDER 12 #define ROW_PAD 6 static GHashTable *windows; static GHashTable *pending_lists; struct NemoPropertiesWindowDetails { GList *original_files; GList *target_files; GtkStack *stack; GtkGrid *basic_grid; GtkWidget *icon_button; GtkWidget *icon_image; GtkWidget *icon_chooser; GtkLabel *name_label; GtkWidget *name_field; unsigned int name_row; char *pending_name; GtkLabel *directory_contents_title_field; GtkLabel *directory_contents_value_field; guint update_directory_contents_timeout_id; guint update_files_timeout_id; NemoFile *group_change_file; char *group_change_group; unsigned int group_change_timeout; NemoFile *owner_change_file; char *owner_change_owner; unsigned int owner_change_timeout; GList *permission_buttons; GList *permission_combos; GHashTable *initial_permissions; gboolean has_recursive_apply; GList *value_fields; GList *mime_list; gboolean deep_count_finished; guint total_count; goffset total_size; guint hidden_count; guint long_operation_underway; GList *changed_files; guint64 volume_capacity; guint64 volume_free; GdkRGBA used_color; GdkRGBA free_color; GdkRGBA used_stroke_color; GdkRGBA free_stroke_color; }; typedef enum { PERMISSIONS_CHECKBOXES_READ, PERMISSIONS_CHECKBOXES_WRITE, PERMISSIONS_CHECKBOXES_EXECUTE } CheckboxType; enum { TITLE_COLUMN, VALUE_COLUMN, COLUMN_COUNT }; typedef struct { GList *original_files; GList *target_files; GtkWidget *parent_widget; char *startup_id; char *pending_key; GHashTable *pending_files; } StartupData; /* drag and drop definitions */ enum { TARGET_URI_LIST, TARGET_GNOME_URI_LIST, }; static const GtkTargetEntry target_table[] = { { (char *)"text/uri-list", 0, TARGET_URI_LIST }, { (char *)"x-special/gnome-icon-list", 0, TARGET_GNOME_URI_LIST }, }; #define DIRECTORY_CONTENTS_UPDATE_INTERVAL 200 /* milliseconds */ #define FILES_UPDATE_INTERVAL 200 /* milliseconds */ #define NEMO_RESPONSE_REVERT 10 /* * A timeout before changes through the user/group combo box will be applied. * When quickly changing owner/groups (i.e. by keyboard or scroll wheel), * this ensures that the GUI doesn't end up unresponsive. * * Both combos react on changes by scheduling a new change and unscheduling * or cancelling old pending changes. */ #define CHOWN_CHGRP_TIMEOUT 300 /* milliseconds */ static void directory_contents_value_field_update (NemoPropertiesWindow *window); static void file_changed_callback (NemoFile *file, gpointer user_data); static void permission_button_update (NemoPropertiesWindow *window, GtkToggleButton *button); static void permission_combo_update (NemoPropertiesWindow *window, GtkComboBox *combo); static void value_field_update (NemoPropertiesWindow *window, GtkLabel *field); static void properties_window_update (NemoPropertiesWindow *window, GList *files); static void is_directory_ready_callback (NemoFile *file, gpointer data); static void cancel_group_change_callback (NemoPropertiesWindow *window); static void cancel_owner_change_callback (NemoPropertiesWindow *window); static void parent_widget_destroyed_callback (GtkWidget *widget, gpointer callback_data); static void select_image_button_callback (GtkWidget *widget, NemoPropertiesWindow *properties_window); static void set_icon (const char *icon_string, NemoPropertiesWindow *properties_window); static void remove_pending (StartupData *data, gboolean cancel_call_when_ready, gboolean cancel_timed_wait, gboolean cancel_destroy_handler); static void append_extension_pages (NemoPropertiesWindow *window); static gboolean name_field_focus_out (NemoEntry *name_field, GdkEventFocus *event, gpointer callback_data); static void name_field_activate (NemoEntry *name_field, gpointer callback_data); static GtkLabel *attach_ellipsizing_value_label (GtkGrid *grid, GtkWidget *sibling, const char *initial_text, PangoEllipsizeMode ellipsize_mode); static GtkWidget* create_pie_widget (NemoPropertiesWindow *window); G_DEFINE_TYPE (NemoPropertiesWindow, nemo_properties_window, GTK_TYPE_DIALOG); static gboolean is_multi_file_window (NemoPropertiesWindow *window) { GList *l; guint count; count = 0; for (l = window->details->original_files; l != NULL; l = l->next) { if (!nemo_file_is_gone (NEMO_FILE (l->data))) { count++; if (count > 1) { return TRUE; } } } return FALSE; } static int get_not_gone_original_file_count (NemoPropertiesWindow *window) { GList *l; int count; count = 0; for (l = window->details->original_files; l != NULL; l = l->next) { if (!nemo_file_is_gone (NEMO_FILE (l->data))) { count++; } } return count; } static NemoFile * get_original_file (NemoPropertiesWindow *window) { g_return_val_if_fail (!is_multi_file_window (window), NULL); if (window->details->original_files == NULL) { return NULL; } return NEMO_FILE (window->details->original_files->data); } static NemoFile * get_target_file_for_original_file (NemoFile *file) { NemoFile *target_file; GFile *location; char *uri_to_display; NemoDesktopLink *link; target_file = NULL; if (NEMO_IS_DESKTOP_ICON_FILE (file)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file)); if (link != NULL) { /* map to linked URI for these types of links */ location = nemo_desktop_link_get_activation_location (link); if (location) { target_file = nemo_file_get (location); g_object_unref (location); } g_object_unref (link); } } else { uri_to_display = nemo_file_get_activation_uri (file); if (uri_to_display != NULL) { target_file = nemo_file_get_by_uri (uri_to_display); g_free (uri_to_display); } } if (target_file != NULL) { return target_file; } /* Ref passed-in file here since we've decided to use it. */ nemo_file_ref (file); return file; } static NemoFile * get_target_file (NemoPropertiesWindow *window) { return NEMO_FILE (window->details->target_files->data); } static void add_prompt (GtkWidget *vbox, const char *prompt_text, gboolean pack_at_start) { GtkWidget *prompt; prompt = gtk_label_new (prompt_text); gtk_label_set_justify (GTK_LABEL (prompt), GTK_JUSTIFY_LEFT); gtk_label_set_line_wrap (GTK_LABEL (prompt), TRUE); gtk_widget_show (prompt); if (pack_at_start) { gtk_box_pack_start (GTK_BOX (vbox), prompt, FALSE, FALSE, 0); } else { gtk_box_pack_end (GTK_BOX (vbox), prompt, FALSE, FALSE, 0); } } static void add_prompt_and_separator (GtkWidget *vbox, const char *prompt_text) { GtkWidget *separator_line; add_prompt (vbox, prompt_text, FALSE); separator_line = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_widget_show (separator_line); gtk_box_pack_end (GTK_BOX (vbox), separator_line, TRUE, TRUE, 2*ROW_PAD); } static void get_image_for_properties_window (NemoPropertiesWindow *window, char **icon_name, GdkPixbuf **icon_pixbuf) { NemoIconInfo *icon, *new_icon; GList *l; gint icon_scale; icon = NULL; icon_scale = gtk_widget_get_scale_factor(GTK_WIDGET(window->details->stack)); for (l = window->details->original_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (!icon) { icon = nemo_file_get_icon (file, NEMO_ICON_SIZE_STANDARD, 0, icon_scale, NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS | NEMO_FILE_ICON_FLAGS_IGNORE_VISITING); } else { new_icon = nemo_file_get_icon (file, NEMO_ICON_SIZE_STANDARD, 0, icon_scale, NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS | NEMO_FILE_ICON_FLAGS_IGNORE_VISITING); if (!new_icon || new_icon != icon) { nemo_icon_info_unref (icon); nemo_icon_info_unref (new_icon); icon = NULL; break; } nemo_icon_info_unref (new_icon); } } if (!icon) { icon = nemo_icon_info_lookup_from_name ("text-x-generic", NEMO_ICON_SIZE_STANDARD, icon_scale); } if (icon_name != NULL) { *icon_name = g_strdup (nemo_icon_info_get_used_name (icon)); } if (icon_pixbuf != NULL) { *icon_pixbuf = nemo_icon_info_get_pixbuf_at_size (icon, NEMO_ICON_SIZE_STANDARD); } nemo_icon_info_unref (icon); } static void update_properties_window_icon (NemoPropertiesWindow *window) { GdkPixbuf *pixbuf; cairo_surface_t *surface; char *name; get_image_for_properties_window (window, &name, &pixbuf); if (name != NULL) { gtk_window_set_icon_name (GTK_WINDOW (window), name); } else { gtk_window_set_icon (GTK_WINDOW (window), pixbuf); } surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, gtk_widget_get_scale_factor (GTK_WIDGET (window)), gtk_widget_get_window (GTK_WIDGET (window))); gtk_image_set_from_surface (GTK_IMAGE (window->details->icon_image), surface); g_free (name); g_object_unref (pixbuf); cairo_surface_destroy (surface); } /* utility to test if a uri refers to a local image */ static gboolean uri_is_local_image (const char *uri) { GdkPixbuf *pixbuf; char *image_path; image_path = g_filename_from_uri (uri, NULL, NULL); if (image_path == NULL) { return FALSE; } pixbuf = gdk_pixbuf_new_from_file (image_path, NULL); g_free (image_path); if (pixbuf == NULL) { return FALSE; } g_object_unref (pixbuf); return TRUE; } static void reset_icon (NemoPropertiesWindow *properties_window) { GList *l; for (l = properties_window->details->original_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_SCALE, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL, NULL); } } static void nemo_properties_window_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint time) { char **uris; gboolean exactly_one; GtkImage *image; GtkWindow *window; image = GTK_IMAGE (widget); window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (image))); uris = g_strsplit ((const gchar *) gtk_selection_data_get_data (selection_data), "\r\n", 0); exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); if (!exactly_one) { eel_show_error_dialog (_("You cannot assign more than one custom icon at a time!"), _("Please drag just one image to set a custom icon."), window); } else { if (uri_is_local_image (uris[0])) { set_icon (uris[0], NEMO_PROPERTIES_WINDOW (window)); } else { GFile *f; f = g_file_new_for_uri (uris[0]); if (!g_file_is_native (f)) { eel_show_error_dialog (_("The file that you dropped is not local."), _("You can only use local images as custom icons."), window); } else { eel_show_error_dialog (_("The file that you dropped is not an image."), _("You can only use local images as custom icons."), window); } g_object_unref (f); } } g_strfreev (uris); } static GtkWidget * create_image_widget (NemoPropertiesWindow *window, gboolean is_customizable) { GtkWidget *button; GtkWidget *image; image = gtk_image_new (); window->details->icon_image = image; update_properties_window_icon (window); gtk_widget_show (image); button = NULL; if (is_customizable) { button = gtk_button_new (); gtk_container_add (GTK_CONTAINER (button), image); /* prepare the image to receive dropped objects to assign custom images */ gtk_drag_dest_set (GTK_WIDGET (image), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target_table, G_N_ELEMENTS (target_table), GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (image, "drag_data_received", G_CALLBACK (nemo_properties_window_drag_data_received), NULL); g_signal_connect (button, "clicked", G_CALLBACK (select_image_button_callback), window); } window->details->icon_button = button; return button != NULL ? button : image; } static void set_name_field (NemoPropertiesWindow *window, const gchar *original_name, const gchar *name) { gboolean new_widget; gboolean use_label; /* There are four cases here: * 1) Changing the text of a label * 2) Changing the text of an entry * 3) Creating label (potentially replacing entry) * 4) Creating entry (potentially replacing label) */ use_label = is_multi_file_window (window) || !nemo_file_can_rename (get_original_file (window)); new_widget = !window->details->name_field || (use_label ? NEMO_IS_ENTRY (window->details->name_field) : GTK_IS_LABEL (window->details->name_field)); if (new_widget) { if (window->details->name_field) { gtk_widget_destroy (window->details->name_field); } if (use_label) { window->details->name_field = GTK_WIDGET (attach_ellipsizing_value_label (window->details->basic_grid, GTK_WIDGET (window->details->name_label), name, PANGO_ELLIPSIZE_END)); } else { window->details->name_field = nemo_entry_new (); gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); gtk_widget_show (window->details->name_field); gtk_grid_attach_next_to (window->details->basic_grid, window->details->name_field, GTK_WIDGET (window->details->name_label), GTK_POS_RIGHT, 1, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (window->details->name_label), window->details->name_field); /* FIXME bugzilla.gnome.org 42151: * With this (and one place elsewhere in this file, not sure which is the * trouble-causer) code in place, bug 2151 happens (crash on quit). Since * we've removed Undo from Nemo for now, I'm just ifdeffing out this * code rather than trying to fix 2151 now. Note that it might be possible * to fix 2151 without making Undo actually work, it's just not worth the * trouble. */ #ifdef UNDO_ENABLED /* Set up name field for undo */ nemo_undo_set_up_nemo_entry_for_undo ( NEMO_ENTRY (window->details->name_field)); nemo_undo_editable_set_undo_key (GTK_EDITABLE (window->details->name_field), TRUE); #endif g_signal_connect_object (window->details->name_field, "focus_out_event", G_CALLBACK (name_field_focus_out), window, 0); g_signal_connect_object (window->details->name_field, "activate", G_CALLBACK (name_field_activate), window, 0); } gtk_widget_show (window->details->name_field); } /* Only replace text if the file's name has changed. */ else if (original_name == NULL || strcmp (original_name, name) != 0) { if (use_label) { gtk_label_set_text (GTK_LABEL (window->details->name_field), name); } else { /* Only reset the text if it's different from what is * currently showing. This causes minimal ripples (e.g. * selection change). */ gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1); if (strcmp (displayed_name, name) != 0) { gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); } g_free (displayed_name); } } } static void update_name_field (NemoPropertiesWindow *window) { NemoFile *file; gtk_label_set_text_with_mnemonic (window->details->name_label, ngettext ("_Name:", "_Names:", get_not_gone_original_file_count (window))); if (is_multi_file_window (window)) { /* Multifile property dialog, show all names */ GString *str; char *name; gboolean first; GList *l; str = g_string_new (""); first = TRUE; for (l = window->details->target_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (!nemo_file_is_gone (file)) { if (!first) { g_string_append (str, ", "); } first = FALSE; name = nemo_file_get_display_name (file); g_string_append (str, name); g_free (name); } } set_name_field (window, NULL, str->str); g_string_free (str, TRUE); } else { const char *original_name = NULL; char *current_name; file = get_original_file (window); if (file == NULL || nemo_file_is_gone (file)) { current_name = g_strdup (""); } else { current_name = nemo_file_get_display_name (file); } /* If the file name has changed since the original name was stored, * update the text in the text field, possibly (deliberately) clobbering * an edit in progress. If the name hasn't changed (but some other * aspect of the file might have), then don't clobber changes. */ if (window->details->name_field) { original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field), "original_name"); } set_name_field (window, original_name, current_name); if (original_name == NULL || g_strcmp0 (original_name, current_name) != 0) { g_object_set_data_full (G_OBJECT (window->details->name_field), "original_name", current_name, g_free); } else { g_free (current_name); } } } static void name_field_restore_original_name (NemoEntry *name_field) { const char *original_name; char *displayed_name; original_name = (const char *) g_object_get_data (G_OBJECT (name_field), "original_name"); if (!original_name) { return; } displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); if (strcmp (original_name, displayed_name) != 0) { gtk_entry_set_text (GTK_ENTRY (name_field), original_name); } nemo_entry_select_all (name_field); g_free (displayed_name); } static void rename_callback (NemoFile *file, GFile *res_loc, GError *error, gpointer callback_data) { NemoPropertiesWindow *window; window = NEMO_PROPERTIES_WINDOW (callback_data); /* Complain to user if rename failed. */ if (error != NULL) { nemo_report_error_renaming_file (file, window->details->pending_name, error, GTK_WINDOW (window)); if (window->details->name_field != NULL) { name_field_restore_original_name (NEMO_ENTRY (window->details->name_field)); } } g_object_unref (window); } static void set_pending_name (NemoPropertiesWindow *window, const char *name) { g_free (window->details->pending_name); window->details->pending_name = g_strdup (name); } static void name_field_done_editing (NemoEntry *name_field, NemoPropertiesWindow *window) { NemoFile *file; char *new_name; const char *original_name; g_return_if_fail (NEMO_IS_ENTRY (name_field)); /* Don't apply if the dialog has more than one file */ if (is_multi_file_window (window)) { return; } file = get_original_file (window); /* This gets called when the window is closed, which might be * caused by the file having been deleted. */ if (file == NULL || nemo_file_is_gone (file)) { return; } new_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); /* Special case: silently revert text if new text is empty. */ if (strlen (new_name) == 0) { name_field_restore_original_name (NEMO_ENTRY (name_field)); } else { original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field), "original_name"); /* Don't rename if not changed since we read the display name. This is needed so that we don't save the display name to the file when nothing is changed */ if (strcmp (new_name, original_name) != 0) { set_pending_name (window, new_name); g_object_ref (window); nemo_file_rename (file, new_name, rename_callback, window); } } g_free (new_name); } static gboolean name_field_focus_out (NemoEntry *name_field, GdkEventFocus *event, gpointer callback_data) { g_assert (NEMO_IS_PROPERTIES_WINDOW (callback_data)); if (gtk_widget_get_sensitive (GTK_WIDGET (name_field))) { name_field_done_editing (name_field, NEMO_PROPERTIES_WINDOW (callback_data)); } return FALSE; } static void name_field_activate (NemoEntry *name_field, gpointer callback_data) { g_assert (NEMO_IS_ENTRY (name_field)); g_assert (NEMO_IS_PROPERTIES_WINDOW (callback_data)); /* Accept changes. */ name_field_done_editing (name_field, NEMO_PROPERTIES_WINDOW (callback_data)); nemo_entry_select_all_at_idle (name_field); } static void update_properties_window_title (NemoPropertiesWindow *window) { char *name, *title; NemoFile *file; g_return_if_fail (GTK_IS_WINDOW (window)); title = g_strdup_printf (_("Properties")); if (!is_multi_file_window (window)) { file = get_original_file (window); if (file != NULL) { g_free (title); name = nemo_file_get_display_name (file); title = g_strdup_printf (_("%s Properties"), name); g_free (name); } } gtk_window_set_title (GTK_WINDOW (window), title); g_free (title); } static void clear_extension_callback (GtkWidget *page, gpointer data) { if (g_object_get_data (G_OBJECT (page), "is-extension-page")) { gtk_widget_destroy (page); } } static void clear_extension_pages (NemoPropertiesWindow *window) { gtk_container_foreach (GTK_CONTAINER (window->details->stack), clear_extension_callback, NULL); } static void refresh_extension_pages (NemoPropertiesWindow *window) { clear_extension_pages (window); append_extension_pages (window); } static void remove_from_dialog (NemoPropertiesWindow *window, NemoFile *file) { int index; GList *original_link; GList *target_link; NemoFile *original_file; NemoFile *target_file; index = g_list_index (window->details->target_files, file); if (index == -1) { index = g_list_index (window->details->original_files, file); g_return_if_fail (index != -1); } original_link = g_list_nth (window->details->original_files, index); target_link = g_list_nth (window->details->target_files, index); g_return_if_fail (original_link && target_link); original_file = NEMO_FILE (original_link->data); target_file = NEMO_FILE (target_link->data); window->details->original_files = g_list_remove_link (window->details->original_files, original_link); g_list_free (original_link); window->details->target_files = g_list_remove_link (window->details->target_files, target_link); g_list_free (target_link); g_hash_table_remove (window->details->initial_permissions, target_file); g_signal_handlers_disconnect_by_func (original_file, G_CALLBACK (file_changed_callback), window); g_signal_handlers_disconnect_by_func (target_file, G_CALLBACK (file_changed_callback), window); nemo_file_monitor_remove (original_file, &window->details->original_files); nemo_file_monitor_remove (target_file, &window->details->target_files); nemo_file_unref (original_file); nemo_file_unref (target_file); } static gboolean mime_list_equal (GList *a, GList *b) { while (a && b) { if (strcmp (a->data, b->data)) { return FALSE; } a = a->next; b = b->next; } return (a == b); } static GList * get_mime_list (NemoPropertiesWindow *window) { GList *ret; GList *l; ret = NULL; for (l = window->details->target_files; l != NULL; l = l->next) { ret = g_list_append (ret, nemo_file_get_mime_type (NEMO_FILE (l->data))); } ret = g_list_reverse (ret); return ret; } static void properties_window_update (NemoPropertiesWindow *window, GList *files) { GList *l; GList *mime_list; GList *tmp; NemoFile *changed_file; gboolean dirty_original = FALSE; gboolean dirty_target = FALSE; if (files == NULL) { dirty_original = TRUE; dirty_target = TRUE; } for (tmp = files; tmp != NULL; tmp = tmp->next) { changed_file = NEMO_FILE (tmp->data); if (changed_file && nemo_file_is_gone (changed_file)) { /* Remove the file from the property dialog */ remove_from_dialog (window, changed_file); changed_file = NULL; if (window->details->original_files == NULL) { return; } } if (changed_file == NULL || g_list_find (window->details->original_files, changed_file)) { dirty_original = TRUE; } if (changed_file == NULL || g_list_find (window->details->target_files, changed_file)) { dirty_target = TRUE; } } if (dirty_original) { update_properties_window_title (window); update_properties_window_icon (window); update_name_field (window); /* If any of the value fields start to depend on the original * value, value_field_updates should be added here */ } if (dirty_target) { for (l = window->details->permission_buttons; l != NULL; l = l->next) { permission_button_update (window, GTK_TOGGLE_BUTTON (l->data)); } for (l = window->details->permission_combos; l != NULL; l = l->next) { permission_combo_update (window, GTK_COMBO_BOX (l->data)); } for (l = window->details->value_fields; l != NULL; l = l->next) { value_field_update (window, GTK_LABEL (l->data)); } } mime_list = get_mime_list (window); if (!window->details->mime_list) { window->details->mime_list = mime_list; } else { if (!mime_list_equal (window->details->mime_list, mime_list)) { refresh_extension_pages (window); } g_list_free_full (window->details->mime_list, g_free); window->details->mime_list = mime_list; } } static gboolean update_files_callback (gpointer data) { NemoPropertiesWindow *window; window = NEMO_PROPERTIES_WINDOW (data); window->details->update_files_timeout_id = 0; properties_window_update (window, window->details->changed_files); if (window->details->original_files == NULL) { /* Close the window if no files are left */ gtk_widget_destroy (GTK_WIDGET (window)); } else { nemo_file_list_free (window->details->changed_files); window->details->changed_files = NULL; } return FALSE; } static void schedule_files_update (NemoPropertiesWindow *window) { g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); if (window->details->update_files_timeout_id == 0) { window->details->update_files_timeout_id = g_timeout_add (FILES_UPDATE_INTERVAL, update_files_callback, window); } } static gboolean file_list_attributes_identical (GList *file_list, const char *attribute_name) { gboolean identical; char *first_attr; GList *l; first_attr = NULL; identical = TRUE; for (l = file_list; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (nemo_file_is_gone (file)) { continue; } if (first_attr == NULL) { first_attr = nemo_file_get_string_attribute_with_default (file, attribute_name); } else { char *attr; attr = nemo_file_get_string_attribute_with_default (file, attribute_name); if (strcmp (attr, first_attr)) { identical = FALSE; g_free (attr); break; } g_free (attr); } } g_free (first_attr); return identical; } static char * file_list_get_string_attribute (GList *file_list, const char *attribute_name, const char *inconsistent_value) { if (file_list_attributes_identical (file_list, attribute_name)) { GList *l; for (l = file_list; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (!nemo_file_is_gone (file)) { return nemo_file_get_string_attribute_with_default (file, attribute_name); } } return g_strdup (_("unknown")); } else { return g_strdup (inconsistent_value); } } static gboolean file_list_all_directories (GList *file_list) { GList *l; for (l = file_list; l != NULL; l = l->next) { if (!nemo_file_is_directory (NEMO_FILE (l->data))) { return FALSE; } } return TRUE; } static void value_field_update_internal (GtkLabel *label, GList *file_list) { const char *attribute_name; char *attribute_value; char *inconsistent_string; char *mime_type, *tmp; g_assert (GTK_IS_LABEL (label)); attribute_name = g_object_get_data (G_OBJECT (label), "file_attribute"); inconsistent_string = g_object_get_data (G_OBJECT (label), "inconsistent_string"); attribute_value = file_list_get_string_attribute (file_list, attribute_name, inconsistent_string); if (!strcmp (attribute_name, "type") && strcmp (attribute_value, inconsistent_string)) { mime_type = file_list_get_string_attribute (file_list, "mime_type", inconsistent_string); if (strcmp (mime_type, inconsistent_string)) { tmp = attribute_value; attribute_value = g_strdup_printf (C_("MIME type description (MIME type)", "%s (%s)"), attribute_value, mime_type); g_free (tmp); } g_free (mime_type); } gtk_label_set_text (label, attribute_value); gtk_widget_set_tooltip_text (GTK_WIDGET (label), attribute_value); g_free (attribute_value); } static void value_field_update (NemoPropertiesWindow *window, GtkLabel *label) { gboolean use_original; use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), "show_original")); value_field_update_internal (label, (use_original ? window->details->original_files : window->details->target_files)); } static GtkLabel * attach_label (GtkGrid *grid, GtkWidget *sibling, const char *initial_text, PangoEllipsizeMode ellipsize_mode, gboolean selectable, gboolean mnemonic) { GtkWidget *label_field; if (ellipsize_mode != PANGO_ELLIPSIZE_NONE) { label_field = gtk_label_new (initial_text); gtk_label_set_ellipsize (GTK_LABEL (label_field), ellipsize_mode); } else if (mnemonic) { label_field = gtk_label_new_with_mnemonic (initial_text); } else { label_field = gtk_label_new (initial_text); } if (selectable) { gtk_label_set_selectable (GTK_LABEL (label_field), TRUE); } gtk_misc_set_alignment (GTK_MISC (label_field), 0, 0.5); gtk_widget_show (label_field); if (ellipsize_mode != PANGO_ELLIPSIZE_NONE) { gtk_widget_set_hexpand (label_field, TRUE); } if (sibling != NULL) { gtk_grid_attach_next_to (grid, label_field, sibling, GTK_POS_RIGHT, 1, 1); } else { gtk_container_add (GTK_CONTAINER (grid), label_field); } return GTK_LABEL (label_field); } static GtkLabel * attach_value_label (GtkGrid *grid, GtkWidget *sibling, const char *initial_text) { return attach_label (grid, sibling, initial_text, PANGO_ELLIPSIZE_NONE, TRUE, FALSE); } static GtkLabel * attach_ellipsizing_value_label (GtkGrid *grid, GtkWidget *sibling, const char *initial_text, PangoEllipsizeMode ellipsize_mode) { return attach_label (grid, sibling, initial_text, ellipsize_mode, TRUE, FALSE); } static GtkWidget* attach_value_field_ellipsizing (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling, const char *file_attribute_name, const char *inconsistent_string, gboolean show_original, PangoEllipsizeMode ellipsize_mode) { GtkLabel *value_field; value_field = attach_ellipsizing_value_label (grid, sibling, "", ellipsize_mode); /* Stash a copy of the file attribute name in this field for the callback's sake. */ g_object_set_data_full (G_OBJECT (value_field), "file_attribute", g_strdup (file_attribute_name), g_free); g_object_set_data_full (G_OBJECT (value_field), "inconsistent_string", g_strdup (inconsistent_string), g_free); g_object_set_data (G_OBJECT (value_field), "show_original", GINT_TO_POINTER (show_original)); window->details->value_fields = g_list_prepend (window->details->value_fields, value_field); return GTK_WIDGET(value_field); } static GtkWidget* attach_value_field (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling, const char *file_attribute_name, const char *inconsistent_string, gboolean show_original) { return attach_value_field_ellipsizing (window, grid, sibling, file_attribute_name, inconsistent_string, show_original, PANGO_ELLIPSIZE_NONE); } static void group_change_callback (NemoFile *file, GFile *res_loc, GError *error, NemoPropertiesWindow *window) { char *group; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); g_assert (window->details->group_change_file == file); group = window->details->group_change_group; g_assert (group != NULL); /* Report the error if it's an error. */ eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, window); nemo_report_error_setting_group (file, error, GTK_WINDOW (window)); nemo_file_unref (file); g_free (group); window->details->group_change_file = NULL; window->details->group_change_group = NULL; g_object_unref (G_OBJECT (window)); } static void cancel_group_change_callback (NemoPropertiesWindow *window) { NemoFile *file; char *group; file = window->details->group_change_file; g_assert (NEMO_IS_FILE (file)); group = window->details->group_change_group; g_assert (group != NULL); nemo_file_cancel (file, (NemoFileOperationCallback) group_change_callback, window); g_free (group); nemo_file_unref (file); window->details->group_change_file = NULL; window->details->group_change_group = NULL; g_object_unref (window); } static gboolean schedule_group_change_timeout (NemoPropertiesWindow *window) { NemoFile *file; char *group; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); file = window->details->group_change_file; g_assert (NEMO_IS_FILE (file)); group = window->details->group_change_group; g_assert (group != NULL); eel_timed_wait_start ((EelCancelCallback) cancel_group_change_callback, window, _("Cancel Group Change?"), GTK_WINDOW (window)); nemo_file_set_group (file, group, (NemoFileOperationCallback) group_change_callback, window); window->details->group_change_timeout = 0; return FALSE; } static void schedule_group_change (NemoPropertiesWindow *window, NemoFile *file, const char *group) { g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); g_assert (window->details->group_change_group == NULL); g_assert (window->details->group_change_file == NULL); g_assert (NEMO_IS_FILE (file)); window->details->group_change_file = nemo_file_ref (file); window->details->group_change_group = g_strdup (group); g_object_ref (G_OBJECT (window)); window->details->group_change_timeout = g_timeout_add (CHOWN_CHGRP_TIMEOUT, (GSourceFunc) schedule_group_change_timeout, window); } static void unschedule_or_cancel_group_change (NemoPropertiesWindow *window) { NemoFile *file; char *group; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); file = window->details->group_change_file; group = window->details->group_change_group; g_assert ((file == NULL && group == NULL) || (file != NULL && group != NULL)); if (file != NULL) { g_assert (NEMO_IS_FILE (file)); if (window->details->group_change_timeout == 0) { nemo_file_cancel (file, (NemoFileOperationCallback) group_change_callback, window); eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, window); } nemo_file_unref (file); g_free (group); window->details->group_change_file = NULL; window->details->group_change_group = NULL; g_object_unref (G_OBJECT (window)); } if (window->details->group_change_timeout > 0) { g_assert (file != NULL); g_source_remove (window->details->group_change_timeout); window->details->group_change_timeout = 0; } } static void changed_group_callback (GtkComboBox *combo_box, NemoFile *file) { NemoPropertiesWindow *window; char *group; char *cur_group; g_assert (GTK_IS_COMBO_BOX (combo_box)); g_assert (NEMO_IS_FILE (file)); group = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo_box)); cur_group = nemo_file_get_group_name (file); if (group != NULL && strcmp (group, cur_group) != 0) { /* Try to change file group. If this fails, complain to user. */ window = NEMO_PROPERTIES_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (combo_box), GTK_TYPE_WINDOW)); unschedule_or_cancel_group_change (window); schedule_group_change (window, file, group); } g_free (group); g_free (cur_group); } /* checks whether the given column at the first level * of model has the specified entries in the given order. */ static gboolean tree_model_entries_equal (GtkTreeModel *model, unsigned int column, GList *entries) { GtkTreeIter iter; gboolean empty_model; g_assert (GTK_IS_TREE_MODEL (model)); g_assert (gtk_tree_model_get_column_type (model, column) == G_TYPE_STRING); empty_model = !gtk_tree_model_get_iter_first (model, &iter); if (!empty_model && entries != NULL) { GList *l; l = entries; do { char *val; gtk_tree_model_get (model, &iter, column, &val, -1); if ((val == NULL && l->data != NULL) || (val != NULL && l->data == NULL) || (val != NULL && strcmp (val, l->data))) { g_free (val); return FALSE; } g_free (val); l = l->next; } while (gtk_tree_model_iter_next (model, &iter)); return l == NULL; } else { return (empty_model && entries == NULL) || (!empty_model && entries != NULL); } } static char * combo_box_get_active_entry (GtkComboBox *combo_box, unsigned int column) { GtkTreeModel *model; GtkTreeIter iter; char *val; g_assert (GTK_IS_COMBO_BOX (combo_box)); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter)) { model = gtk_combo_box_get_model (combo_box); g_assert (GTK_IS_TREE_MODEL (model)); gtk_tree_model_get (model, &iter, column, &val, -1); return val; } return NULL; } /* returns the index of the given entry in the the given column * at the first level of model. Returns -1 if entry can't be found * or entry is NULL. * */ static int tree_model_get_entry_index (GtkTreeModel *model, unsigned int column, const char *entry) { GtkTreeIter iter; int index; gboolean empty_model; g_assert (GTK_IS_TREE_MODEL (model)); g_assert (gtk_tree_model_get_column_type (model, column) == G_TYPE_STRING); empty_model = !gtk_tree_model_get_iter_first (model, &iter); if (!empty_model && entry != NULL) { index = 0; do { char *val; gtk_tree_model_get (model, &iter, column, &val, -1); if (val != NULL && !strcmp (val, entry)) { g_free (val); return index; } g_free (val); index++; } while (gtk_tree_model_iter_next (model, &iter)); } return -1; } static void synch_groups_combo_box (GtkComboBox *combo_box, NemoFile *file) { GList *groups; GList *node; GtkTreeModel *model; GtkListStore *store; const char *group_name; char *current_group_name; int group_index; int current_group_index; g_assert (GTK_IS_COMBO_BOX (combo_box)); g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_gone (file)) { return; } groups = nemo_file_get_settable_group_names (file); model = gtk_combo_box_get_model (combo_box); store = GTK_LIST_STORE (model); g_assert (GTK_IS_LIST_STORE (model)); if (!tree_model_entries_equal (model, 0, groups)) { /* Clear the contents of ComboBox in a wacky way because there * is no function to clear all items and also no function to obtain * the number of items in a combobox. */ gtk_list_store_clear (store); for (node = groups, group_index = 0; node != NULL; node = node->next, ++group_index) { group_name = (const char *)node->data; gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), group_name); } } current_group_name = nemo_file_get_group_name (file); current_group_index = tree_model_get_entry_index (model, 0, current_group_name); /* If current group wasn't in list, we prepend it (with a separator). * This can happen if the current group is an id with no matching * group in the groups file. */ if (current_group_index < 0 && current_group_name != NULL) { if (groups != NULL) { /* add separator */ gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo_box), "-"); } gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo_box), current_group_name); current_group_index = 0; } gtk_combo_box_set_active (combo_box, current_group_index); g_free (current_group_name); g_list_free_full (groups, g_free); } static gboolean combo_box_row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gchar *text; gboolean ret; gtk_tree_model_get (model, iter, 0, &text, -1); if (text == NULL) { return FALSE; } if (strcmp (text, "-") == 0) { ret = TRUE; } else { ret = FALSE; } g_free (text); return ret; } static GtkComboBox * attach_combo_box (GtkGrid *grid, GtkWidget *sibling, gboolean two_columns) { GtkWidget *combo_box; GtkWidget *aligner; if (!two_columns) { combo_box = gtk_combo_box_text_new (); } else { GtkTreeModel *model; GtkCellRenderer *renderer; model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING)); combo_box = gtk_combo_box_new_with_model (model); g_object_unref (G_OBJECT (model)); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), renderer, "text", 0); } gtk_widget_show (combo_box); gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo_box), combo_box_row_separator_func, NULL, NULL); /* Put combo box in alignment to make it left-justified * but minimally sized. */ aligner = gtk_alignment_new (0, 0.5, 0, 0); gtk_widget_show (aligner); gtk_container_add (GTK_CONTAINER (aligner), combo_box); gtk_grid_attach_next_to (grid, aligner, sibling, GTK_POS_RIGHT, 1, 1); return GTK_COMBO_BOX (combo_box); } static GtkComboBox* attach_group_combo_box (GtkGrid *grid, GtkWidget *sibling, NemoFile *file) { GtkComboBox *combo_box; combo_box = attach_combo_box (grid, sibling, FALSE); synch_groups_combo_box (combo_box, file); /* Connect to signal to update menu when file changes. */ g_signal_connect_object (file, "changed", G_CALLBACK (synch_groups_combo_box), combo_box, G_CONNECT_SWAPPED); g_signal_connect_data (combo_box, "changed", G_CALLBACK (changed_group_callback), nemo_file_ref (file), (GClosureNotify)nemo_file_unref, 0); return combo_box; } static void owner_change_callback (NemoFile *file, GFile *result_location, GError *error, NemoPropertiesWindow *window) { char *owner; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); g_assert (window->details->owner_change_file == file); owner = window->details->owner_change_owner; g_assert (owner != NULL); /* Report the error if it's an error. */ eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, window); nemo_report_error_setting_owner (file, error, GTK_WINDOW (window)); nemo_file_unref (file); g_free (owner); window->details->owner_change_file = NULL; window->details->owner_change_owner = NULL; g_object_unref (G_OBJECT (window)); } static void cancel_owner_change_callback (NemoPropertiesWindow *window) { NemoFile *file; char *owner; file = window->details->owner_change_file; g_assert (NEMO_IS_FILE (file)); owner = window->details->owner_change_owner; g_assert (owner != NULL); nemo_file_cancel (file, (NemoFileOperationCallback) owner_change_callback, window); nemo_file_unref (file); g_free (owner); window->details->owner_change_file = NULL; window->details->owner_change_owner = NULL; g_object_unref (window); } static gboolean schedule_owner_change_timeout (NemoPropertiesWindow *window) { NemoFile *file; char *owner; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); file = window->details->owner_change_file; g_assert (NEMO_IS_FILE (file)); owner = window->details->owner_change_owner; g_assert (owner != NULL); eel_timed_wait_start ((EelCancelCallback) cancel_owner_change_callback, window, _("Cancel Owner Change?"), GTK_WINDOW (window)); nemo_file_set_owner (file, owner, (NemoFileOperationCallback) owner_change_callback, window); window->details->owner_change_timeout = 0; return FALSE; } static void schedule_owner_change (NemoPropertiesWindow *window, NemoFile *file, const char *owner) { g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); g_assert (window->details->owner_change_owner == NULL); g_assert (window->details->owner_change_file == NULL); g_assert (NEMO_IS_FILE (file)); window->details->owner_change_file = nemo_file_ref (file); window->details->owner_change_owner = g_strdup (owner); g_object_ref (G_OBJECT (window)); window->details->owner_change_timeout = g_timeout_add (CHOWN_CHGRP_TIMEOUT, (GSourceFunc) schedule_owner_change_timeout, window); } static void unschedule_or_cancel_owner_change (NemoPropertiesWindow *window) { NemoFile *file; char *owner; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); file = window->details->owner_change_file; owner = window->details->owner_change_owner; g_assert ((file == NULL && owner == NULL) || (file != NULL && owner != NULL)); if (file != NULL) { g_assert (NEMO_IS_FILE (file)); if (window->details->owner_change_timeout == 0) { nemo_file_cancel (file, (NemoFileOperationCallback) owner_change_callback, window); eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, window); } nemo_file_unref (file); g_free (owner); window->details->owner_change_file = NULL; window->details->owner_change_owner = NULL; g_object_unref (G_OBJECT (window)); } if (window->details->owner_change_timeout > 0) { g_assert (file != NULL); g_source_remove (window->details->owner_change_timeout); window->details->owner_change_timeout = 0; } } static void changed_owner_callback (GtkComboBox *combo_box, NemoFile* file) { NemoPropertiesWindow *window; char *owner_text; char **name_array; char *new_owner; char *cur_owner; g_assert (GTK_IS_COMBO_BOX (combo_box)); g_assert (NEMO_IS_FILE (file)); owner_text = combo_box_get_active_entry (combo_box, 0); if (! owner_text) return; name_array = g_strsplit (owner_text, " - ", 2); new_owner = name_array[0]; g_free (owner_text); cur_owner = nemo_file_get_owner_name (file); if (strcmp (new_owner, cur_owner) != 0) { /* Try to change file owner. If this fails, complain to user. */ window = NEMO_PROPERTIES_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (combo_box), GTK_TYPE_WINDOW)); unschedule_or_cancel_owner_change (window); schedule_owner_change (window, file, new_owner); } g_strfreev (name_array); g_free (cur_owner); } static void synch_user_menu (GtkComboBox *combo_box, NemoFile *file) { GList *users; GList *node; GtkTreeModel *model; GtkListStore *store; GtkTreeIter iter; char *user_name; char *owner_name; int user_index; int owner_index; char **name_array; char *combo_text; g_assert (GTK_IS_COMBO_BOX (combo_box)); g_assert (NEMO_IS_FILE (file)); if (nemo_file_is_gone (file)) { return; } users = nemo_get_user_names (); model = gtk_combo_box_get_model (combo_box); store = GTK_LIST_STORE (model); g_assert (GTK_IS_LIST_STORE (model)); if (!tree_model_entries_equal (model, 1, users)) { /* Clear the contents of ComboBox in a wacky way because there * is no function to clear all items and also no function to obtain * the number of items in a combobox. */ gtk_list_store_clear (store); for (node = users, user_index = 0; node != NULL; node = node->next, ++user_index) { user_name = (char *)node->data; name_array = g_strsplit (user_name, "\n", 2); if (name_array[1] != NULL) { combo_text = g_strdup_printf ("%s - %s", name_array[0], name_array[1]); } else { combo_text = g_strdup (name_array[0]); } gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, combo_text, 1, user_name, -1); g_strfreev (name_array); g_free (combo_text); } } owner_name = nemo_file_get_string_attribute (file, "owner"); owner_index = tree_model_get_entry_index (model, 0, owner_name); /* If owner wasn't in list, we prepend it (with a separator). * This can happen if the owner is an id with no matching * identifier in the passwords file. */ if (owner_index < 0 && owner_name != NULL) { if (users != NULL) { /* add separator */ gtk_list_store_prepend (store, &iter); gtk_list_store_set (store, &iter, 0, "-", 1, NULL, -1); } name_array = g_strsplit (owner_name, " - ", 2); if (name_array[1] != NULL) { user_name = g_strdup_printf ("%s\n%s", name_array[0], name_array[1]); } else { user_name = g_strdup (name_array[0]); } owner_index = 0; gtk_list_store_prepend (store, &iter); gtk_list_store_set (store, &iter, 0, owner_name, 1, user_name, -1); g_free (user_name); g_strfreev (name_array); } gtk_combo_box_set_active (combo_box, owner_index); g_free (owner_name); g_list_free_full (users, g_free); } static GtkComboBox* attach_owner_combo_box (GtkGrid *grid, GtkWidget *sibling, NemoFile *file) { GtkComboBox *combo_box; combo_box = attach_combo_box (grid, sibling, TRUE); synch_user_menu (combo_box, file); /* Connect to signal to update menu when file changes. */ g_signal_connect_object (file, "changed", G_CALLBACK (synch_user_menu), combo_box, G_CONNECT_SWAPPED); g_signal_connect_data (combo_box, "changed", G_CALLBACK (changed_owner_callback), nemo_file_ref (file), (GClosureNotify)nemo_file_unref, 0); return combo_box; } static gboolean file_has_prefix (NemoFile *file, GList *prefix_candidates) { GList *p; GFile *location, *candidate_location; location = nemo_file_get_location (file); for (p = prefix_candidates; p != NULL; p = p->next) { if (file == p->data) { continue; } candidate_location = nemo_file_get_location (NEMO_FILE (p->data)); if (g_file_has_prefix (location, candidate_location)) { g_object_unref (location); g_object_unref (candidate_location); return TRUE; } g_object_unref (candidate_location); } g_object_unref (location); return FALSE; } static void directory_contents_value_field_update (NemoPropertiesWindow *window) { NemoRequestStatus file_status, status; char *text, *temp; guint directory_count; guint file_count; guint total_count; guint unreadable_directory_count; guint hidden_count; guint total_hidden; goffset total_size; gboolean used_two_lines; NemoFile *file; GList *l; guint file_unreadable; goffset file_size; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); status = NEMO_REQUEST_DONE; total_count = window->details->total_count; total_size = window->details->total_size; total_hidden = window->details->hidden_count; unreadable_directory_count = FALSE; for (l = window->details->target_files; l; l = l->next) { file = NEMO_FILE (l->data); if (file_has_prefix (file, window->details->target_files)) { /* don't count nested files twice */ continue; } if (nemo_file_is_directory (file)) { file_status = nemo_file_get_deep_counts (file, &directory_count, &file_count, &file_unreadable, &hidden_count, &file_size, TRUE); total_count += (file_count + directory_count); total_size += file_size; total_hidden += hidden_count; if (file_unreadable) { unreadable_directory_count = TRUE; } if (file_status != NEMO_REQUEST_DONE) { status = file_status; } } else { ++total_count; total_size += nemo_file_get_size (file); } } /* If we've already displayed the total once, don't do another visible * count-up if the deep_count happens to get invalidated. * But still display the new total, since it might have changed. */ if (window->details->deep_count_finished && status != NEMO_REQUEST_DONE) { return; } text = NULL; used_two_lines = FALSE; if (total_count == 0) { switch (status) { case NEMO_REQUEST_DONE: if (unreadable_directory_count == 0) { text = g_strdup (_("nothing")); } else { text = g_strdup (_("unreadable")); } break; case NEMO_REQUEST_NOT_STARTED: case NEMO_REQUEST_IN_PROGRESS: default: text = g_strdup ("..."); } } else { char *size_str; int prefix; prefix = nemo_global_preferences_get_size_prefix_preference (); size_str = g_format_size_full (total_size, prefix); if (total_hidden > 0) { text = g_strdup_printf (ngettext("%1$s item (and %2$s hidden), with size %3$s", "%1$s items (and %2$s hidden), totalling %3$s", total_count), g_strdup_printf("%'d", total_count), g_strdup_printf("%'d", total_hidden), size_str); } else { text = g_strdup_printf (ngettext("%1$s item, with size %2$s", "%1$s items, totalling %2$s", total_count), g_strdup_printf("%'d", total_count), size_str); } g_free (size_str); if (unreadable_directory_count != 0) { temp = text; text = g_strconcat (temp, "\n", _("(some contents unreadable)"), NULL); g_free (temp); used_two_lines = TRUE; } } gtk_label_set_text (window->details->directory_contents_value_field, text); g_free (text); /* Also set the title field here, with a trailing carriage return & * space if the value field has two lines. This is a hack to get the * "Contents:" title to line up with the first line of the * 2-line value. Maybe there's a better way to do this, but I * couldn't think of one. */ text = g_strdup (_("Contents:")); if (used_two_lines) { temp = text; text = g_strconcat (temp, "\n ", NULL); g_free (temp); } gtk_label_set_text (window->details->directory_contents_title_field, text); g_free (text); if (status == NEMO_REQUEST_DONE) { window->details->deep_count_finished = TRUE; } } static gboolean update_directory_contents_callback (gpointer data) { NemoPropertiesWindow *window; window = NEMO_PROPERTIES_WINDOW (data); window->details->update_directory_contents_timeout_id = 0; directory_contents_value_field_update (window); return FALSE; } static void schedule_directory_contents_update (NemoPropertiesWindow *window) { g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); if (window->details->update_directory_contents_timeout_id == 0) { window->details->update_directory_contents_timeout_id = g_timeout_add (DIRECTORY_CONTENTS_UPDATE_INTERVAL, update_directory_contents_callback, window); } } static GtkLabel * attach_directory_contents_value_field (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling) { GtkLabel *value_field; GList *l; NemoFile *file; value_field = attach_value_label (grid, sibling, ""); g_assert (window->details->directory_contents_value_field == NULL); window->details->directory_contents_value_field = value_field; gtk_label_set_line_wrap (value_field, TRUE); /* Fill in the initial value. */ directory_contents_value_field_update (window); for (l = window->details->target_files; l; l = l->next) { file = NEMO_FILE (l->data); nemo_file_recompute_deep_counts (file); g_signal_connect_object (file, "updated_deep_count_in_progress", G_CALLBACK (schedule_directory_contents_update), window, G_CONNECT_SWAPPED); } return value_field; } static GtkLabel * attach_title_field (GtkGrid *grid, const char *title) { return attach_label (grid, NULL, title, PANGO_ELLIPSIZE_NONE, FALSE, TRUE); } #define INCONSISTENT_STATE_STRING \ "\xE2\x80\x92" static void append_title_value_pair (NemoPropertiesWindow *window, GtkGrid *grid, const char *title, const char *file_attribute_name, const char *inconsistent_state, gboolean show_original) { GtkLabel *title_label; GtkWidget *value; title_label = attach_title_field (grid, title); value = attach_value_field (window, grid, GTK_WIDGET (title_label), file_attribute_name, inconsistent_state, show_original); gtk_label_set_mnemonic_widget (title_label, value); } static void append_title_and_ellipsizing_value (NemoPropertiesWindow *window, GtkGrid *grid, const char *title, const char *file_attribute_name, const char *inconsistent_state, gboolean show_original, PangoEllipsizeMode ellipsize_mode) { GtkLabel *title_label; GtkWidget *value; title_label = attach_title_field (grid, title); value = attach_value_field_ellipsizing (window, grid, GTK_WIDGET (title_label), file_attribute_name, inconsistent_state, show_original, ellipsize_mode); gtk_label_set_mnemonic_widget (title_label, value); } static void append_directory_contents_fields (NemoPropertiesWindow *window, GtkGrid *grid) { GtkLabel *title_field, *value_field; title_field = attach_title_field (grid, ""); window->details->directory_contents_title_field = title_field; gtk_label_set_line_wrap (title_field, TRUE); value_field = attach_directory_contents_value_field (window, grid, GTK_WIDGET (title_field)); gtk_label_set_mnemonic_widget (title_field, GTK_WIDGET(value_field)); } static GtkWidget * create_page_with_hbox (GtkStack *stack, const char *name, const char *title, const char *help_uri) { GtkWidget *hbox; g_assert (GTK_IS_STACK (stack)); g_assert (name != NULL); g_assert (title != NULL); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show (hbox); gtk_container_set_border_width (GTK_CONTAINER (hbox), STACK_INNER_BORDER); gtk_box_set_spacing (GTK_BOX (hbox), 12); gtk_stack_add_titled(stack, hbox, name, title); g_object_set_data_full (G_OBJECT (hbox), "help-uri", g_strdup (help_uri), g_free); return hbox; } static GtkWidget * create_page_with_vbox (GtkStack *stack, const char *name, const char *title, const char *help_uri) { GtkWidget *vbox; g_assert (GTK_IS_STACK (stack)); g_assert (name != NULL); g_assert (title != NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show (vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), STACK_INNER_BORDER); gtk_stack_add_titled(stack, vbox, name, title); g_object_set_data_full (G_OBJECT (vbox), "help-uri", g_strdup (help_uri), g_free); return vbox; } static GtkWidget * append_blank_row (GtkGrid *grid) { return GTK_WIDGET (attach_title_field (grid, "")); } static void append_blank_slim_row (GtkGrid *grid) { GtkWidget *w; PangoAttribute *attribute; PangoAttrList *attr_list; attr_list = pango_attr_list_new (); attribute = pango_attr_scale_new (0.30); pango_attr_list_insert (attr_list, attribute); w = gtk_label_new (NULL); gtk_label_set_attributes (GTK_LABEL (w), attr_list); gtk_widget_show (w); pango_attr_list_unref (attr_list); gtk_container_add (GTK_CONTAINER (grid), w); } static GtkWidget * create_grid_with_standard_properties (void) { GtkWidget *grid; grid = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (grid), 6); gtk_grid_set_row_spacing (GTK_GRID (grid), ROW_PAD); gtk_grid_set_column_spacing (GTK_GRID (grid), 12); gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); gtk_widget_show (grid); return grid; } static gboolean is_computer_directory (NemoFile *file) { char *file_uri; gboolean result; file_uri = nemo_file_get_uri (file); result = strcmp (file_uri, "computer:///") == 0; g_free (file_uri); return result; } static gboolean is_network_directory (NemoFile *file) { char *file_uri; gboolean result; file_uri = nemo_file_get_uri (file); result = strcmp (file_uri, "network:///") == 0; g_free (file_uri); return result; } static gboolean is_burn_directory (NemoFile *file) { char *file_uri; gboolean result; file_uri = nemo_file_get_uri (file); result = strcmp (file_uri, "burn:///") == 0; g_free (file_uri); return result; } static gboolean should_show_custom_icon_buttons (NemoPropertiesWindow *window) { if (is_multi_file_window (window)) { return FALSE; } return TRUE; } static gboolean should_show_file_type (NemoPropertiesWindow *window) { if (!is_multi_file_window (window) && (nemo_file_is_in_trash (get_target_file (window)) || is_computer_directory (get_target_file (window)) || is_network_directory (get_target_file (window)) || is_burn_directory (get_target_file (window)))) { return FALSE; } return TRUE; } static gboolean should_show_location_info (NemoPropertiesWindow *window) { if (!is_multi_file_window (window) && (nemo_file_is_in_trash (get_target_file (window)) || is_computer_directory (get_target_file (window)) || is_network_directory (get_target_file (window)) || is_burn_directory (get_target_file (window)))) { return FALSE; } return TRUE; } static gboolean should_show_accessed_date (NemoPropertiesWindow *window) { /* Accessed date for directory seems useless. If we some * day decide that it is useful, we should separately * consider whether it's useful for "trash:". */ if (file_list_all_directories (window->details->target_files)) { return FALSE; } return TRUE; } static gboolean should_show_link_target (NemoPropertiesWindow *window) { if (!is_multi_file_window (window) && nemo_file_is_symbolic_link (get_target_file (window))) { return TRUE; } return FALSE; } static gboolean location_show_original (NemoPropertiesWindow *window) { NemoFile *file; /* there is no way a recent item will be mixed with other items so just pick the first file to check */ file = NEMO_FILE (g_list_nth_data (window->details->original_files, 0)); return (file != NULL && !nemo_file_is_in_recent (file)); } static gboolean should_show_free_space (NemoPropertiesWindow *window) { if (!is_multi_file_window (window) && (nemo_file_is_in_trash (get_target_file (window)) || is_computer_directory (get_target_file (window)) || is_network_directory (get_target_file (window)) || nemo_file_is_in_recent (get_target_file (window)) || is_burn_directory (get_target_file (window)))) { return FALSE; } if (file_list_all_directories (window->details->target_files)) { return TRUE; } return FALSE; } static gboolean should_show_volume_usage (NemoPropertiesWindow *window) { NemoFile *file; gboolean success = FALSE; if (is_multi_file_window (window)) { return FALSE; } file = get_original_file (window); if (file == NULL) { return FALSE; } if (nemo_file_can_unmount (file)) { return TRUE; } #ifdef TODO_GIO /* Look at is_mountpoint for activation uri */ #endif return success; } static void paint_used_legend (GtkWidget *widget, cairo_t *cr, gpointer data) { NemoPropertiesWindow *window; gint width, height; GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); width = allocation.width; height = allocation.height; window = NEMO_PROPERTIES_WINDOW (data); cairo_rectangle (cr, 2, 2, width - 4, height - 4); gdk_cairo_set_source_rgba (cr, &window->details->used_color); cairo_fill_preserve (cr); gdk_cairo_set_source_rgba (cr, &window->details->used_stroke_color); cairo_stroke (cr); } static void paint_free_legend (GtkWidget *widget, cairo_t *cr, gpointer data) { NemoPropertiesWindow *window; gint width, height; GtkAllocation allocation; window = NEMO_PROPERTIES_WINDOW (data); gtk_widget_get_allocation (widget, &allocation); width = allocation.width; height = allocation.height; cairo_rectangle (cr, 2, 2, width - 4, height - 4); gdk_cairo_set_source_rgba (cr, &window->details->free_color); cairo_fill_preserve(cr); gdk_cairo_set_source_rgba (cr, &window->details->free_stroke_color); cairo_stroke (cr); } static void paint_pie_chart (GtkWidget *widget, cairo_t *cr, gpointer data) { NemoPropertiesWindow *window; gint width, height; double free, used; double angle1, angle2, split, xc, yc, radius; GtkAllocation allocation; GtkStyleContext *stack_ctx; GdkRGBA bg_color; window = NEMO_PROPERTIES_WINDOW (data); gtk_widget_get_allocation (widget, &allocation); width = allocation.width; height = allocation.height; stack_ctx = gtk_widget_get_style_context (GTK_WIDGET (window->details->stack)); gtk_style_context_get_background_color (stack_ctx, gtk_widget_get_state_flags (GTK_WIDGET (window->details->stack)), &bg_color); cairo_save (cr); gdk_cairo_set_source_rgba (cr, &bg_color); cairo_paint (cr); cairo_restore (cr); free = (double)window->details->volume_free / (double)window->details->volume_capacity; used = 1.0 - free; angle1 = free * 2 * G_PI; angle2 = used * 2 * G_PI; split = (2 * G_PI - angle1) * .5; xc = width / 2; yc = height / 2; if (width < height) { radius = width / 2 - 8; } else { radius = height / 2 - 8; } if (angle1 != 2 * G_PI && angle1 != 0) { angle1 = angle1 + split; } if (angle2 != 2 * G_PI && angle2 != 0) { angle2 = angle2 - split; } if (used > 0) { if (free != 0) { cairo_move_to (cr,xc,yc); } cairo_arc (cr, xc, yc, radius, angle1, angle2); if (free != 0) { cairo_line_to (cr,xc,yc); } gdk_cairo_set_source_rgba (cr, &window->details->used_color); cairo_fill_preserve (cr); gdk_cairo_set_source_rgba (cr, &window->details->used_stroke_color); cairo_stroke (cr); } if (free > 0) { if (used != 0) { cairo_move_to (cr,xc,yc); } cairo_arc_negative (cr, xc, yc, radius, angle1, angle2); if (used != 0) { cairo_line_to (cr,xc,yc); } gdk_cairo_set_source_rgba (cr, &window->details->free_color); cairo_fill_preserve(cr); gdk_cairo_set_source_rgba (cr, &window->details->free_stroke_color); cairo_stroke (cr); } } /* Copied from gtk/gtkstyle.c */ static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) { gdouble min; gdouble max; gdouble red; gdouble green; gdouble blue; gdouble h, l, s; gdouble delta; red = *r; green = *g; blue = *b; if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } l = (max + min) / 2; s = 0; h = 0; if (max != min) { if (l <= 0.5) s = (max - min) / (max + min); else s = (max - min) / (2 - max - min); delta = max -min; if (red == max) h = (green - blue) / delta; else if (green == max) h = 2 + (blue - red) / delta; else if (blue == max) h = 4 + (red - green) / delta; h *= 60; if (h < 0.0) h += 360; } *r = h; *g = l; *b = s; } static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s) { gdouble hue; gdouble lightness; gdouble saturation; gdouble m1, m2; gdouble r, g, b; lightness = *l; saturation = *s; if (lightness <= 0.5) m2 = lightness * (1 + saturation); else m2 = lightness + saturation - lightness * saturation; m1 = 2 * lightness - m2; if (saturation == 0) { *h = lightness; *l = lightness; *s = lightness; } else { hue = *h + 120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) r = m1 + (m2 - m1) * hue / 60; else if (hue < 180) r = m2; else if (hue < 240) r = m1 + (m2 - m1) * (240 - hue) / 60; else r = m1; hue = *h; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) g = m1 + (m2 - m1) * hue / 60; else if (hue < 180) g = m2; else if (hue < 240) g = m1 + (m2 - m1) * (240 - hue) / 60; else g = m1; hue = *h - 120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) b = m1 + (m2 - m1) * hue / 60; else if (hue < 180) b = m2; else if (hue < 240) b = m1 + (m2 - m1) * (240 - hue) / 60; else b = m1; *h = r; *l = g; *s = b; } } static void _pie_style_shade (GdkRGBA *a, GdkRGBA *b, gdouble k) { gdouble red; gdouble green; gdouble blue; red = a->red; green = a->green; blue = a->blue; rgb_to_hls (&red, &green, &blue); green *= k; if (green > 1.0) green = 1.0; else if (green < 0.0) green = 0.0; blue *= k; if (blue > 1.0) blue = 1.0; else if (blue < 0.0) blue = 0.0; hls_to_rgb (&red, &green, &blue); b->red = red; b->green = green; b->blue = blue; b->alpha = a->alpha; } static GtkWidget* create_pie_widget (NemoPropertiesWindow *window) { NemoFile *file; GtkGrid *grid; GtkStyleContext *style; GtkWidget *pie_canvas; GtkWidget *used_canvas; GtkWidget *used_label; GtkWidget *free_canvas; GtkWidget *free_label; GtkWidget *capacity_label; GtkWidget *fstype_label; gchar *capacity; gchar *used; gchar *free; const char *fs_type; gchar *uri; GFile *location; GFileInfo *info; int prefix; prefix = nemo_global_preferences_get_size_prefix_preference (); capacity = g_format_size_full (window->details->volume_capacity, prefix); free = g_format_size_full (window->details->volume_free, prefix); used = g_format_size_full (window->details->volume_capacity - window->details->volume_free, prefix); file = get_original_file (window); uri = nemo_file_get_activation_uri (file); grid = GTK_GRID (gtk_grid_new ()); gtk_container_set_border_width (GTK_CONTAINER (grid), 5); gtk_grid_set_column_spacing (GTK_GRID (grid), 5); style = gtk_widget_get_style_context (GTK_WIDGET (grid)); if (!gtk_style_context_lookup_color (style, "chart_rgba_1", &window->details->used_color)) { window->details->used_color.red = USED_FILL_R; window->details->used_color.green = USED_FILL_G; window->details->used_color.blue = USED_FILL_B; window->details->used_color.alpha = 1; } if (!gtk_style_context_lookup_color (style, "chart_rgba_2", &window->details->free_color)) { window->details->free_color.red = FREE_FILL_R; window->details->free_color.green = FREE_FILL_G; window->details->free_color.blue = FREE_FILL_B; window->details->free_color.alpha = 1; } _pie_style_shade (&window->details->used_color, &window->details->used_stroke_color, 0.7); _pie_style_shade (&window->details->free_color, &window->details->free_stroke_color, 0.7); pie_canvas = gtk_drawing_area_new (); gtk_widget_set_size_request (pie_canvas, 200, 200); used_canvas = gtk_drawing_area_new (); gtk_widget_set_valign (used_canvas, GTK_ALIGN_CENTER); gtk_widget_set_halign (used_canvas, GTK_ALIGN_CENTER); gtk_widget_set_size_request (used_canvas, 20, 20); /* Translators: "used" refers to the capacity of the filesystem */ used_label = gtk_label_new (g_strconcat (used, " ", _("used"), NULL)); free_canvas = gtk_drawing_area_new (); gtk_widget_set_valign (free_canvas, GTK_ALIGN_CENTER); gtk_widget_set_halign (free_canvas, GTK_ALIGN_CENTER); gtk_widget_set_size_request (free_canvas, 20, 20); /* Translators: "free" refers to the capacity of the filesystem */ free_label = gtk_label_new (g_strconcat (free, " ", _("free"), NULL)); capacity_label = gtk_label_new (g_strconcat (_("Total capacity:"), " ", capacity, NULL)); fstype_label = gtk_label_new (NULL); location = g_file_new_for_uri (uri); info = g_file_query_filesystem_info (location, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, NULL, NULL); if (info) { fs_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE); if (fs_type != NULL) { gchar *str = g_strconcat (_("Filesystem type:"), " ", fs_type, NULL); gtk_label_set_text (GTK_LABEL (fstype_label), str); g_free (str); } g_object_unref (info); } g_object_unref (location); g_free (uri); g_free (capacity); g_free (used); g_free (free); gtk_container_add_with_properties (GTK_CONTAINER (grid), pie_canvas, "height", 4, NULL); gtk_grid_attach_next_to (grid, used_canvas, pie_canvas, GTK_POS_RIGHT, 1, 1); gtk_grid_attach_next_to (grid, used_label, used_canvas, GTK_POS_RIGHT, 1, 1); gtk_grid_attach_next_to (grid, free_canvas, used_canvas, GTK_POS_BOTTOM, 1, 1); gtk_grid_attach_next_to (grid, free_label, free_canvas, GTK_POS_RIGHT, 1, 1); gtk_grid_attach_next_to (grid, capacity_label, free_canvas, GTK_POS_BOTTOM, 2, 1); gtk_grid_attach_next_to (grid, fstype_label, capacity_label, GTK_POS_BOTTOM, 2, 1); g_signal_connect (pie_canvas, "draw", G_CALLBACK (paint_pie_chart), window); g_signal_connect (used_canvas, "draw", G_CALLBACK (paint_used_legend), window); g_signal_connect (free_canvas, "draw", G_CALLBACK (paint_free_legend), window); return GTK_WIDGET (grid); } static GtkWidget* create_volume_usage_widget (NemoPropertiesWindow *window) { GtkWidget *piewidget; gchar *uri; NemoFile *file; GFile *location; GFileInfo *info; file = get_original_file (window); uri = nemo_file_get_activation_uri (file); location = g_file_new_for_uri (uri); info = g_file_query_filesystem_info (location, "filesystem::*", NULL, NULL); if (info) { window->details->volume_capacity = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE); window->details->volume_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); g_object_unref (info); } else { window->details->volume_capacity = 0; window->details->volume_free = 0; } g_object_unref (location); piewidget = create_pie_widget (window); gtk_widget_show_all (piewidget); return piewidget; } static void create_basic_page (NemoPropertiesWindow *window) { GtkGrid *grid; GtkWidget *icon_aligner; GtkWidget *icon_pixmap_widget; GtkWidget *volume_usage; GtkWidget *hbox, *vbox; hbox = create_page_with_hbox (window->details->stack, "basic", _("Basic"), "help:gnome-help/nemo-file-properties-basic"); /* Icon pixmap */ icon_pixmap_widget = create_image_widget ( window, should_show_custom_icon_buttons (window)); gtk_widget_show (icon_pixmap_widget); icon_aligner = gtk_alignment_new (1, 0, 0, 0); gtk_widget_show (icon_aligner); gtk_container_add (GTK_CONTAINER (icon_aligner), icon_pixmap_widget); gtk_box_pack_start (GTK_BOX (hbox), icon_aligner, FALSE, FALSE, 0); window->details->icon_chooser = NULL; /* Grid */ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (hbox), vbox); grid = GTK_GRID (create_grid_with_standard_properties ()); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (grid), FALSE, FALSE, 0); window->details->basic_grid = grid; /* Name label. The text will be determined in update_name_field */ window->details->name_label = attach_title_field (grid, NULL); /* Name field */ window->details->name_field = NULL; update_name_field (window); /* Start with name field selected, if it's an entry. */ if (NEMO_IS_ENTRY (window->details->name_field)) { nemo_entry_select_all (NEMO_ENTRY (window->details->name_field)); gtk_widget_grab_focus (GTK_WIDGET (window->details->name_field)); } if (nemo_desktop_item_properties_should_show (window->details->target_files)) { GtkSizeGroup *label_size_group; GtkWidget *box; label_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget (label_size_group, GTK_WIDGET (window->details->name_label)); box = nemo_desktop_item_properties_make_box (label_size_group, window->details->target_files); gtk_grid_attach_next_to (window->details->basic_grid, box, GTK_WIDGET (window->details->name_label), GTK_POS_BOTTOM, 2, 1); } if (should_show_file_type (window)) { append_title_and_ellipsizing_value (window, grid, _("Type:"), "type", INCONSISTENT_STATE_STRING, FALSE, PANGO_ELLIPSIZE_END); } if (should_show_link_target (window)) { append_title_and_ellipsizing_value (window, grid, _("Link target:"), "link_target", INCONSISTENT_STATE_STRING, FALSE, PANGO_ELLIPSIZE_MIDDLE); } if (is_multi_file_window (window) || nemo_file_is_directory (get_target_file (window))) { append_directory_contents_fields (window, grid); } else { append_title_value_pair (window, grid, _("Size:"), "size_detail", INCONSISTENT_STATE_STRING, FALSE); } append_blank_row (grid); if (should_show_location_info (window)) { append_title_and_ellipsizing_value (window, grid, _("Location:"), "where", INCONSISTENT_STATE_STRING, location_show_original (window), PANGO_ELLIPSIZE_MIDDLE); append_title_and_ellipsizing_value (window, grid, _("Volume:"), "volume", INCONSISTENT_STATE_STRING, FALSE, PANGO_ELLIPSIZE_END); } if (should_show_accessed_date (window)) { append_blank_row (grid); append_title_value_pair (window, grid, _("Accessed:"), "date_accessed_full", INCONSISTENT_STATE_STRING, FALSE); append_title_value_pair (window, grid, _("Modified:"), "date_modified_full", INCONSISTENT_STATE_STRING, FALSE); append_title_value_pair (window, grid, _("Created:"), "date_created_full", INCONSISTENT_STATE_STRING, FALSE); } if (should_show_free_space (window)) { append_blank_row (grid); append_title_value_pair (window, grid, _("Free space:"), "free_space", INCONSISTENT_STATE_STRING, FALSE); } if (should_show_volume_usage (window)) { volume_usage = create_volume_usage_widget (window); gtk_container_add_with_properties (GTK_CONTAINER (grid), volume_usage, "width", 2, NULL); } } static gboolean files_has_directory (NemoPropertiesWindow *window) { GList *l; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (nemo_file_is_directory (file)) { return TRUE; } } return FALSE; } static gboolean files_has_changable_permissions_directory (NemoPropertiesWindow *window) { GList *l; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (nemo_file_is_directory (file) && nemo_file_can_get_permissions (file) && nemo_file_can_set_permissions (file)) { return TRUE; } } return FALSE; } static gboolean files_has_file (NemoPropertiesWindow *window) { GList *l; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (!nemo_file_is_directory (file)) { return TRUE; } } return FALSE; } static void start_long_operation (NemoPropertiesWindow *window) { if (window->details->long_operation_underway == 0) { /* start long operation */ GdkCursor * cursor; cursor = gdk_cursor_new (GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor); g_object_unref (cursor); } window->details->long_operation_underway ++; } static void end_long_operation (NemoPropertiesWindow *window) { if (gtk_widget_get_window (GTK_WIDGET (window)) != NULL && window->details->long_operation_underway == 1) { /* finished !! */ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL); } window->details->long_operation_underway--; } static void permission_change_callback (NemoFile *file, GFile *res_loc, GError *error, gpointer callback_data) { NemoPropertiesWindow *window; g_assert (callback_data != NULL); window = NEMO_PROPERTIES_WINDOW (callback_data); end_long_operation (window); /* Report the error if it's an error. */ nemo_report_error_setting_permissions (file, error, NULL); g_object_unref (window); } static void update_permissions (NemoPropertiesWindow *window, guint32 vfs_new_perm, guint32 vfs_mask, gboolean is_folder, gboolean apply_to_both_folder_and_dir, gboolean use_original) { GList *l; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; guint32 permissions; file = NEMO_FILE (l->data); if (!nemo_file_can_get_permissions (file)) { continue; } if (!apply_to_both_folder_and_dir && ((nemo_file_is_directory (file) && !is_folder) || (!nemo_file_is_directory (file) && is_folder))) { continue; } permissions = nemo_file_get_permissions (file); if (use_original) { gpointer ptr; if (g_hash_table_lookup_extended (window->details->initial_permissions, file, NULL, &ptr)) { permissions = (permissions & ~vfs_mask) | (GPOINTER_TO_INT (ptr) & vfs_mask); } } else { permissions = (permissions & ~vfs_mask) | vfs_new_perm; } start_long_operation (window); g_object_ref (window); nemo_file_set_permissions (file, permissions, permission_change_callback, window); } } static gboolean initial_permission_state_consistent (NemoPropertiesWindow *window, guint32 mask, gboolean is_folder, gboolean both_folder_and_dir) { GList *l; gboolean first; guint32 first_permissions; first = TRUE; first_permissions = 0; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; guint32 permissions; file = l->data; if (!both_folder_and_dir && ((nemo_file_is_directory (file) && !is_folder) || (!nemo_file_is_directory (file) && is_folder))) { continue; } permissions = GPOINTER_TO_INT (g_hash_table_lookup (window->details->initial_permissions, file)); if (first) { if ((permissions & mask) != mask && (permissions & mask) != 0) { /* Not fully on or off -> inconsistent */ return FALSE; } first_permissions = permissions; first = FALSE; } else if ((permissions & mask) != first_permissions) { /* Not same permissions as first -> inconsistent */ return FALSE; } } return TRUE; } static void permission_button_toggled (GtkToggleButton *button, NemoPropertiesWindow *window) { gboolean is_folder, is_special; guint32 permission_mask; gboolean inconsistent; gboolean on; permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "permission")); is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-folder")); is_special = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-special")); if (gtk_toggle_button_get_active (button) && !gtk_toggle_button_get_inconsistent (button)) { /* Go to the initial state unless the initial state was consistent, or we support recursive apply */ inconsistent = TRUE; on = TRUE; if (!window->details->has_recursive_apply && initial_permission_state_consistent (window, permission_mask, is_folder, is_special)) { inconsistent = FALSE; on = TRUE; } } else if (gtk_toggle_button_get_inconsistent (button) && !gtk_toggle_button_get_active (button)) { inconsistent = FALSE; on = TRUE; } else { inconsistent = FALSE; on = FALSE; } g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (permission_button_toggled), window); gtk_toggle_button_set_active (button, on); gtk_toggle_button_set_inconsistent (button, inconsistent); g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (permission_button_toggled), window); update_permissions (window, on?permission_mask:0, permission_mask, is_folder, is_special, inconsistent); } static void permission_button_update (NemoPropertiesWindow *window, GtkToggleButton *button) { GList *l; gboolean all_set; gboolean all_unset; gboolean all_cannot_set; gboolean is_folder, is_special; gboolean no_match; gboolean sensitive; guint32 button_permission; if (gtk_toggle_button_get_inconsistent (button) && window->details->has_recursive_apply) { /* Never change from an inconsistent state if we have dirs, even * if the current state is now consistent, because its a useful * state for recursive apply. */ return; } button_permission = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "permission")); is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-folder")); is_special = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-special")); all_set = TRUE; all_unset = TRUE; all_cannot_set = TRUE; no_match = TRUE; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; guint32 file_permissions; file = NEMO_FILE (l->data); if (!nemo_file_can_get_permissions (file)) { continue; } if (!is_special && ((nemo_file_is_directory (file) && !is_folder) || (!nemo_file_is_directory (file) && is_folder))) { continue; } no_match = FALSE; file_permissions = nemo_file_get_permissions (file); if ((file_permissions & button_permission) == button_permission) { all_unset = FALSE; } else if ((file_permissions & button_permission) == 0) { all_set = FALSE; } else { all_unset = FALSE; all_set = FALSE; } if (nemo_file_can_set_permissions (file)) { all_cannot_set = FALSE; } } sensitive = !all_cannot_set; if (!is_folder) { /* Don't insitive files when we have recursive apply */ sensitive |= window->details->has_recursive_apply; } g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (permission_button_toggled), window); gtk_toggle_button_set_active (button, !all_unset); /* if actually inconsistent, or default value for file buttons if no files are selected. (useful for recursive apply) */ gtk_toggle_button_set_inconsistent (button, (!all_unset && !all_set) || (!is_folder && no_match)); gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive); g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (permission_button_toggled), window); } static void set_up_permissions_checkbox (NemoPropertiesWindow *window, GtkWidget *check_button, guint32 permission, gboolean is_folder) { /* Load up the check_button with data we'll need when updating its state. */ g_object_set_data (G_OBJECT (check_button), "permission", GINT_TO_POINTER (permission)); g_object_set_data (G_OBJECT (check_button), "properties_window", window); g_object_set_data (G_OBJECT (check_button), "is-folder", GINT_TO_POINTER (is_folder)); window->details->permission_buttons = g_list_prepend (window->details->permission_buttons, check_button); g_signal_connect_object (check_button, "toggled", G_CALLBACK (permission_button_toggled), window, 0); } static GtkWidget * add_permissions_checkbox_with_label (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling, const char *label, guint32 permission_to_check, GtkLabel *label_for, gboolean is_folder) { GtkWidget *check_button; gboolean a11y_enabled; check_button = gtk_check_button_new_with_mnemonic (label); gtk_widget_show (check_button); if (sibling) { gtk_grid_attach_next_to (grid, check_button, sibling, GTK_POS_RIGHT, 1, 1); } else { gtk_container_add (GTK_CONTAINER (grid), check_button); } set_up_permissions_checkbox (window, check_button, permission_to_check, is_folder); a11y_enabled = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (check_button)); if (a11y_enabled && label_for != NULL) { eel_accessibility_set_up_label_widget_relation (GTK_WIDGET (label_for), check_button); } return check_button; } static GtkWidget * add_permissions_checkbox (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling, CheckboxType type, guint32 permission_to_check, GtkLabel *label_for, gboolean is_folder) { const gchar *label; if (type == PERMISSIONS_CHECKBOXES_READ) { label = _("_Read"); } else if (type == PERMISSIONS_CHECKBOXES_WRITE) { label = _("_Write"); } else { label = _("E_xecute"); } return add_permissions_checkbox_with_label (window, grid, sibling, label, permission_to_check, label_for, is_folder); } enum { UNIX_PERM_SUID = S_ISUID, UNIX_PERM_SGID = S_ISGID, UNIX_PERM_STICKY = 01000, /* S_ISVTX not defined on all systems */ UNIX_PERM_USER_READ = S_IRUSR, UNIX_PERM_USER_WRITE = S_IWUSR, UNIX_PERM_USER_EXEC = S_IXUSR, UNIX_PERM_USER_ALL = S_IRUSR | S_IWUSR | S_IXUSR, UNIX_PERM_GROUP_READ = S_IRGRP, UNIX_PERM_GROUP_WRITE = S_IWGRP, UNIX_PERM_GROUP_EXEC = S_IXGRP, UNIX_PERM_GROUP_ALL = S_IRGRP | S_IWGRP | S_IXGRP, UNIX_PERM_OTHER_READ = S_IROTH, UNIX_PERM_OTHER_WRITE = S_IWOTH, UNIX_PERM_OTHER_EXEC = S_IXOTH, UNIX_PERM_OTHER_ALL = S_IROTH | S_IWOTH | S_IXOTH }; typedef enum { PERMISSION_READ = (1<<0), PERMISSION_WRITE = (1<<1), PERMISSION_EXEC = (1<<2) } PermissionValue; typedef enum { PERMISSION_USER, PERMISSION_GROUP, PERMISSION_OTHER } PermissionType; static guint32 vfs_perms[3][3] = { {UNIX_PERM_USER_READ, UNIX_PERM_USER_WRITE, UNIX_PERM_USER_EXEC}, {UNIX_PERM_GROUP_READ, UNIX_PERM_GROUP_WRITE, UNIX_PERM_GROUP_EXEC}, {UNIX_PERM_OTHER_READ, UNIX_PERM_OTHER_WRITE, UNIX_PERM_OTHER_EXEC}, }; static guint32 permission_to_vfs (PermissionType type, PermissionValue perm) { guint32 vfs_perm; g_assert (type >= 0 && type < 3); vfs_perm = 0; if (perm & PERMISSION_READ) { vfs_perm |= vfs_perms[type][0]; } if (perm & PERMISSION_WRITE) { vfs_perm |= vfs_perms[type][1]; } if (perm & PERMISSION_EXEC) { vfs_perm |= vfs_perms[type][2]; } return vfs_perm; } static PermissionValue permission_from_vfs (PermissionType type, guint32 vfs_perm) { PermissionValue perm; g_assert (type >= 0 && type < 3); perm = 0; if (vfs_perm & vfs_perms[type][0]) { perm |= PERMISSION_READ; } if (vfs_perm & vfs_perms[type][1]) { perm |= PERMISSION_WRITE; } if (vfs_perm & vfs_perms[type][2]) { perm |= PERMISSION_EXEC; } return perm; } static void permission_combo_changed (GtkWidget *combo, NemoPropertiesWindow *window) { GtkTreeIter iter; GtkTreeModel *model; gboolean is_folder, use_original; PermissionType type; int new_perm, mask; guint32 vfs_new_perm, vfs_mask; is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "is-folder")); type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "permission-type")); if (is_folder) { mask = PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC; } else { mask = PERMISSION_READ|PERMISSION_WRITE; } vfs_mask = permission_to_vfs (type, mask); model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { return; } gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); vfs_new_perm = permission_to_vfs (type, new_perm); update_permissions (window, vfs_new_perm, vfs_mask, is_folder, FALSE, use_original); } static void permission_combo_add_multiple_choice (GtkComboBox *combo, GtkTreeIter *iter) { GtkTreeModel *model; GtkListStore *store; gboolean found; model = gtk_combo_box_get_model (combo); store = GTK_LIST_STORE (model); found = FALSE; gtk_tree_model_get_iter_first (model, iter); do { gboolean multi; gtk_tree_model_get (model, iter, 2, &multi, -1); if (multi) { found = TRUE; break; } } while (gtk_tree_model_iter_next (model, iter)); if (!found) { gtk_list_store_append (store, iter); gtk_list_store_set (store, iter, 0, "---", 1, 0, 2, TRUE, -1); } } static void permission_combo_update (NemoPropertiesWindow *window, GtkComboBox *combo) { PermissionType type; PermissionValue perm, all_dir_perm, all_file_perm, all_perm; gboolean is_folder, no_files, no_dirs, all_file_same, all_dir_same, all_same; gboolean all_dir_cannot_set, all_file_cannot_set, sensitive; GtkTreeIter iter; int mask; GtkTreeModel *model; GtkListStore *store; GList *l; gboolean is_multi; model = gtk_combo_box_get_model (combo); is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "is-folder")); type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "permission-type")); is_multi = FALSE; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { gtk_tree_model_get (model, &iter, 2, &is_multi, -1); } if (is_multi && window->details->has_recursive_apply) { /* Never change from an inconsistent state if we have dirs, even * if the current state is now consistent, because its a useful * state for recursive apply. */ return; } no_files = TRUE; no_dirs = TRUE; all_dir_same = TRUE; all_file_same = TRUE; all_dir_perm = 0; all_file_perm = 0; all_dir_cannot_set = TRUE; all_file_cannot_set = TRUE; for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; guint32 file_permissions; file = NEMO_FILE (l->data); if (!nemo_file_can_get_permissions (file)) { continue; } if (nemo_file_is_directory (file)) { mask = PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC; } else { mask = PERMISSION_READ|PERMISSION_WRITE; } file_permissions = nemo_file_get_permissions (file); perm = permission_from_vfs (type, file_permissions) & mask; if (nemo_file_is_directory (file)) { if (no_dirs) { all_dir_perm = perm; no_dirs = FALSE; } else if (perm != all_dir_perm) { all_dir_same = FALSE; } if (nemo_file_can_set_permissions (file)) { all_dir_cannot_set = FALSE; } } else { if (no_files) { all_file_perm = perm; no_files = FALSE; } else if (perm != all_file_perm) { all_file_same = FALSE; } if (nemo_file_can_set_permissions (file)) { all_file_cannot_set = FALSE; } } } if (is_folder) { all_same = all_dir_same; all_perm = all_dir_perm; } else { all_same = all_file_same && !no_files; all_perm = all_file_perm; } store = GTK_LIST_STORE (model); if (all_same) { gboolean found; found = FALSE; gtk_tree_model_get_iter_first (model, &iter); do { PermissionValue current_perm; gtk_tree_model_get (model, &iter, 1, ¤t_perm, -1); if (current_perm == all_perm) { found = TRUE; break; } } while (gtk_tree_model_iter_next (model, &iter)); if (!found) { GString *str; str = g_string_new (""); if (!(all_perm & PERMISSION_READ)) { /* translators: this gets concatenated to "no read", * "no access", etc. (see following strings) */ g_string_append (str, _("no ")); } if (is_folder) { g_string_append (str, _("list")); } else { g_string_append (str, _("read")); } g_string_append (str, ", "); if (!(all_perm & PERMISSION_WRITE)) { g_string_append (str, _("no ")); } if (is_folder) { g_string_append (str, _("create/delete")); } else { g_string_append (str, _("write")); } if (is_folder) { g_string_append (str, ", "); if (!(all_perm & PERMISSION_EXEC)) { g_string_append (str, _("no ")); } g_string_append (str, _("access")); } gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, str->str, 1, all_perm, -1); g_string_free (str, TRUE); } } else { permission_combo_add_multiple_choice (combo, &iter); } g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK (permission_combo_changed), window); gtk_combo_box_set_active_iter (combo, &iter); /* Also enable if no files found (for recursive file changes when only selecting folders) */ if (is_folder) { sensitive = !all_dir_cannot_set; } else { sensitive = !all_file_cannot_set || window->details->has_recursive_apply; } gtk_widget_set_sensitive (GTK_WIDGET (combo), sensitive); g_signal_handlers_unblock_by_func (G_OBJECT (combo), G_CALLBACK (permission_combo_changed), window); } static void add_permissions_combo_box (NemoPropertiesWindow *window, GtkGrid *grid, PermissionType type, gboolean is_folder, gboolean short_label) { GtkWidget *combo; GtkLabel *label; GtkListStore *store; GtkCellRenderer *cell; GtkTreeIter iter; if (short_label) { label = attach_title_field (grid, _("Access:")); } else if (is_folder) { label = attach_title_field (grid, _("Folder access:")); } else { label = attach_title_field (grid, _("File access:")); } store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN); combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); g_object_set_data (G_OBJECT (combo), "is-folder", GINT_TO_POINTER (is_folder)); g_object_set_data (G_OBJECT (combo), "permission-type", GINT_TO_POINTER (type)); if (is_folder) { if (type != PERMISSION_USER) { gtk_list_store_append (store, &iter); /* Translators: this is referred to the permissions * the user has in a directory. */ gtk_list_store_set (store, &iter, 0, _("None"), 1, 0, -1); } gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("List files only"), 1, PERMISSION_READ, -1); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("Access files"), 1, PERMISSION_READ|PERMISSION_EXEC, -1); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("Create and delete files"), 1, PERMISSION_READ|PERMISSION_EXEC|PERMISSION_WRITE, -1); } else { if (type != PERMISSION_USER) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("None"), 1, 0, -1); } gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("Read-only"), 1, PERMISSION_READ, -1); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, _("Read and write"), 1, PERMISSION_READ|PERMISSION_WRITE, -1); } if (window->details->has_recursive_apply) { permission_combo_add_multiple_choice (GTK_COMBO_BOX (combo), &iter); } g_object_unref (store); window->details->permission_combos = g_list_prepend (window->details->permission_combos, combo); g_signal_connect (combo, "changed", G_CALLBACK (permission_combo_changed), window); cell = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell, "text", 0, NULL); gtk_label_set_mnemonic_widget (label, combo); gtk_widget_show (combo); gtk_grid_attach_next_to (grid, combo, GTK_WIDGET (label), GTK_POS_RIGHT, 1, 1); } static GtkWidget * append_special_execution_checkbox (NemoPropertiesWindow *window, GtkGrid *grid, GtkWidget *sibling, const char *label_text, guint32 permission_to_check) { GtkWidget *check_button; check_button = gtk_check_button_new_with_mnemonic (label_text); gtk_widget_show (check_button); if (sibling != NULL) { gtk_grid_attach_next_to (grid, check_button, sibling, GTK_POS_RIGHT, 1, 1); } else { gtk_container_add_with_properties (GTK_CONTAINER (grid), check_button, "left-attach", 1, NULL); } set_up_permissions_checkbox (window, check_button, permission_to_check, FALSE); g_object_set_data (G_OBJECT (check_button), "is-special", GINT_TO_POINTER (TRUE)); return check_button; } static void append_special_execution_flags (NemoPropertiesWindow *window, GtkGrid *grid) { GtkWidget *title; append_blank_slim_row (grid); title = GTK_WIDGET (attach_title_field (grid, _("Special flags:"))); append_special_execution_checkbox (window, grid, title, _("Set _user ID"), UNIX_PERM_SUID); append_special_execution_checkbox (window, grid, NULL, _("Set gro_up ID"), UNIX_PERM_SGID); append_special_execution_checkbox (window, grid, NULL, _("_Sticky"), UNIX_PERM_STICKY); } static gboolean all_can_get_permissions (GList *file_list) { GList *l; for (l = file_list; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (!nemo_file_can_get_permissions (file)) { return FALSE; } } return TRUE; } static gboolean all_can_set_permissions (GList *file_list) { GList *l; for (l = file_list; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); if (!nemo_file_can_set_permissions (file)) { return FALSE; } } return TRUE; } static GHashTable * get_initial_permissions (GList *file_list) { GHashTable *ret; GList *l; ret = g_hash_table_new (g_direct_hash, g_direct_equal); for (l = file_list; l != NULL; l = l->next) { guint32 permissions; NemoFile *file; file = NEMO_FILE (l->data); permissions = nemo_file_get_permissions (file); g_hash_table_insert (ret, file, GINT_TO_POINTER (permissions)); } return ret; } static void create_simple_permissions (NemoPropertiesWindow *window, GtkGrid *page_grid) { gboolean has_file, has_directory; GtkLabel *group_label; GtkLabel *owner_label; GtkWidget *value; GtkComboBox *group_combo_box; GtkComboBox *owner_combo_box; has_file = files_has_file (window); has_directory = files_has_directory (window); if (!is_multi_file_window (window) && nemo_file_can_set_owner (get_target_file (window))) { owner_label = attach_title_field (page_grid, _("_Owner:")); /* Combo box in this case. */ owner_combo_box = attach_owner_combo_box (page_grid, GTK_WIDGET (owner_label), get_target_file (window)); gtk_label_set_mnemonic_widget (owner_label, GTK_WIDGET (owner_combo_box)); } else { owner_label = attach_title_field (page_grid, _("Owner:")); /* Static text in this case. */ value = attach_value_field (window, page_grid, GTK_WIDGET (owner_label), "owner", INCONSISTENT_STATE_STRING, FALSE); gtk_label_set_mnemonic_widget (owner_label, value); } if (has_directory) { add_permissions_combo_box (window, page_grid, PERMISSION_USER, TRUE, FALSE); } if (has_file || window->details->has_recursive_apply) { add_permissions_combo_box (window, page_grid, PERMISSION_USER, FALSE, !has_directory); } append_blank_slim_row (page_grid); if (!is_multi_file_window (window) && nemo_file_can_set_group (get_target_file (window))) { group_label = attach_title_field (page_grid, _("_Group:")); /* Combo box in this case. */ group_combo_box = attach_group_combo_box (page_grid, GTK_WIDGET (group_label), get_target_file (window)); gtk_label_set_mnemonic_widget (group_label, GTK_WIDGET (group_combo_box)); } else { group_label = attach_title_field (page_grid, _("Group:")); /* Static text in this case. */ value = attach_value_field (window, page_grid, GTK_WIDGET (group_label), "group", INCONSISTENT_STATE_STRING, FALSE); gtk_label_set_mnemonic_widget (group_label, value); } if (has_directory) { add_permissions_combo_box (window, page_grid, PERMISSION_GROUP, TRUE, FALSE); } if (has_file || window->details->has_recursive_apply) { add_permissions_combo_box (window, page_grid, PERMISSION_GROUP, FALSE, !has_directory); } append_blank_slim_row (page_grid);; if (has_directory) { add_permissions_combo_box (window, page_grid, PERMISSION_OTHER, TRUE, FALSE); } if (has_file || window->details->has_recursive_apply) { add_permissions_combo_box (window, page_grid, PERMISSION_OTHER, FALSE, !has_directory); } if (!has_directory) { GtkLabel *execute_label; append_blank_slim_row (page_grid); execute_label = attach_title_field (page_grid, _("Execute:")); add_permissions_checkbox_with_label (window, page_grid, GTK_WIDGET (execute_label), _("Allow _executing file as program"), UNIX_PERM_USER_EXEC|UNIX_PERM_GROUP_EXEC|UNIX_PERM_OTHER_EXEC, execute_label, FALSE); } } static void create_permission_checkboxes (NemoPropertiesWindow *window, GtkGrid *page_grid, gboolean is_folder) { GtkLabel *owner_perm_label; GtkLabel *group_perm_label; GtkLabel *other_perm_label; GtkGrid *check_button_grid; GtkWidget *w; owner_perm_label = attach_title_field (page_grid, _("Owner:")); group_perm_label = attach_title_field (page_grid, _("Group:")); other_perm_label = attach_title_field (page_grid, _("Others:")); check_button_grid = GTK_GRID (create_grid_with_standard_properties ()); gtk_widget_show (GTK_WIDGET (check_button_grid)); gtk_grid_attach_next_to (page_grid, GTK_WIDGET (check_button_grid), GTK_WIDGET (owner_perm_label), GTK_POS_RIGHT, 1, 3); w = add_permissions_checkbox (window, check_button_grid, NULL, PERMISSIONS_CHECKBOXES_READ, UNIX_PERM_USER_READ, owner_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_WRITE, UNIX_PERM_USER_WRITE, owner_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_EXECUTE, UNIX_PERM_USER_EXEC, owner_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, NULL, PERMISSIONS_CHECKBOXES_READ, UNIX_PERM_GROUP_READ, group_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_WRITE, UNIX_PERM_GROUP_WRITE, group_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_EXECUTE, UNIX_PERM_GROUP_EXEC, group_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, NULL, PERMISSIONS_CHECKBOXES_READ, UNIX_PERM_OTHER_READ, other_perm_label, is_folder); w = add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_WRITE, UNIX_PERM_OTHER_WRITE, other_perm_label, is_folder); add_permissions_checkbox (window, check_button_grid, w, PERMISSIONS_CHECKBOXES_EXECUTE, UNIX_PERM_OTHER_EXEC, other_perm_label, is_folder); } static void create_advanced_permissions (NemoPropertiesWindow *window, GtkGrid *page_grid) { GtkLabel *group_label; GtkLabel *owner_label; GtkComboBox *group_combo_box; GtkComboBox *owner_combo_box; gboolean has_directory, has_file; if (!is_multi_file_window (window) && nemo_file_can_set_owner (get_target_file (window))) { owner_label = attach_title_field (page_grid, _("_Owner:")); /* Combo box in this case. */ owner_combo_box = attach_owner_combo_box (page_grid, GTK_WIDGET (owner_label), get_target_file (window)); gtk_label_set_mnemonic_widget (owner_label, GTK_WIDGET (owner_combo_box)); } else { GtkWidget *value; owner_label = attach_title_field (page_grid, _("Owner:")); /* Static text in this case. */ value = attach_value_field (window, page_grid, GTK_WIDGET (owner_label), "owner", INCONSISTENT_STATE_STRING, FALSE); gtk_label_set_mnemonic_widget (owner_label, value); } if (!is_multi_file_window (window) && nemo_file_can_set_group (get_target_file (window))) { group_label = attach_title_field (page_grid, _("_Group:")); /* Combo box in this case. */ group_combo_box = attach_group_combo_box (page_grid, GTK_WIDGET (group_label), get_target_file (window)); gtk_label_set_mnemonic_widget (group_label, GTK_WIDGET (group_combo_box)); } else { group_label = attach_title_field (page_grid, _("Group:")); /* Static text in this case. */ attach_value_field (window, page_grid, GTK_WIDGET (group_label), "group", INCONSISTENT_STATE_STRING, FALSE); } append_blank_slim_row (page_grid); has_directory = files_has_directory (window); has_file = files_has_file (window); if (has_directory) { if (has_file || window->details->has_recursive_apply) { attach_title_field (page_grid, _("Folder Permissions:")); } create_permission_checkboxes (window, page_grid, TRUE); } if (has_file || window->details->has_recursive_apply) { if (has_directory) { attach_title_field (page_grid, _("File Permissions:")); } create_permission_checkboxes (window, page_grid, FALSE); } append_blank_slim_row (page_grid); append_special_execution_flags (window, page_grid); append_title_value_pair (window, page_grid, _("Text view:"), "permissions", INCONSISTENT_STATE_STRING, FALSE); } static void set_recursive_permissions_done (gboolean success, gpointer callback_data) { NemoPropertiesWindow *window; window = NEMO_PROPERTIES_WINDOW (callback_data); end_long_operation (window); g_object_unref (window); } static void apply_recursive_clicked (GtkWidget *recursive_button, NemoPropertiesWindow *window) { guint32 file_permission, file_permission_mask; guint32 dir_permission, dir_permission_mask; guint32 vfs_mask, vfs_new_perm, p; GtkWidget *button, *combo; gboolean active, is_folder, is_special, use_original; GList *l; GtkTreeModel *model; GtkTreeIter iter; PermissionType type; int new_perm, mask; file_permission = 0; file_permission_mask = 0; dir_permission = 0; dir_permission_mask = 0; /* Advanced mode and execute checkbox: */ for (l = window->details->permission_buttons; l != NULL; l = l->next) { button = l->data; if (gtk_toggle_button_get_inconsistent (GTK_TOGGLE_BUTTON (button))) { continue; } active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); p = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "permission")); is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-folder")); is_special = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "is-special")); if (is_folder || is_special) { dir_permission_mask |= p; if (active) { dir_permission |= p; } } if (!is_folder || is_special) { file_permission_mask |= p; if (active) { file_permission |= p; } } } /* Simple mode, minus exec checkbox */ for (l = window->details->permission_combos; l != NULL; l = l->next) { combo = l->data; if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { continue; } type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "permission-type")); is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "is-folder")); model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); if (use_original) { continue; } vfs_new_perm = permission_to_vfs (type, new_perm); if (is_folder) { mask = PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC; } else { mask = PERMISSION_READ|PERMISSION_WRITE; } vfs_mask = permission_to_vfs (type, mask); if (is_folder) { dir_permission_mask |= vfs_mask; dir_permission |= vfs_new_perm; } else { file_permission_mask |= vfs_mask; file_permission |= vfs_new_perm; } } for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; char *uri; file = NEMO_FILE (l->data); if (nemo_file_is_directory (file) && nemo_file_can_set_permissions (file)) { uri = nemo_file_get_uri (file); start_long_operation (window); g_object_ref (window); nemo_file_set_permissions_recursive (uri, file_permission, file_permission_mask, dir_permission, dir_permission_mask, set_recursive_permissions_done, window); g_free (uri); } } } static void create_permissions_page (NemoPropertiesWindow *window) { GtkWidget *vbox, *button, *hbox; GtkGrid *page_grid; char *file_name, *prompt_text; GList *file_list; vbox = create_page_with_vbox (window->details->stack, "permissions", _("Permissions"), "help:gnome-help/nemo-file-properties-permissions"); file_list = window->details->original_files; window->details->initial_permissions = NULL; if (all_can_get_permissions (file_list) && all_can_get_permissions (window->details->target_files)) { window->details->initial_permissions = get_initial_permissions (window->details->target_files); window->details->has_recursive_apply = files_has_changable_permissions_directory (window); if (!all_can_set_permissions (file_list)) { add_prompt_and_separator ( vbox, _("You are not the owner, so you cannot change these permissions.")); } page_grid = GTK_GRID (create_grid_with_standard_properties ()); gtk_widget_show (GTK_WIDGET (page_grid)); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (page_grid), TRUE, TRUE, 0); if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_ADVANCED_PERMISSIONS)) { create_advanced_permissions (window, page_grid); } else { create_simple_permissions (window, page_grid); } append_blank_slim_row (page_grid); #ifdef HAVE_SELINUX append_title_value_pair (window, page_grid, _("SELinux context:"), "selinux_context", INCONSISTENT_STATE_STRING, FALSE); #endif append_title_value_pair (window, page_grid, _("Last changed:"), "date_permissions", INCONSISTENT_STATE_STRING, FALSE); if (window->details->has_recursive_apply) { hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show (hbox); gtk_container_add_with_properties (GTK_CONTAINER (page_grid), hbox, "width", 2, NULL); button = gtk_button_new_with_mnemonic (_("Apply Permissions to Enclosed Files")); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (apply_recursive_clicked), window); } } else { if (!is_multi_file_window (window)) { file_name = nemo_file_get_display_name (get_target_file (window)); prompt_text = g_strdup_printf (_("The permissions of \"%s\" could not be determined."), file_name); g_free (file_name); } else { prompt_text = g_strdup (_("The permissions of the selected file could not be determined.")); } add_prompt (vbox, prompt_text, TRUE); g_free (prompt_text); } } static void append_extension_pages (NemoPropertiesWindow *window) { GList *providers; GList *p; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_PROPERTY_PAGE_PROVIDER); for (p = providers; p != NULL; p = p->next) { NemoPropertyPageProvider *provider; GList *pages; GList *l; provider = NEMO_PROPERTY_PAGE_PROVIDER (p->data); pages = nemo_property_page_provider_get_pages (provider, window->details->original_files); for (l = pages; l != NULL; l = l->next) { NemoPropertyPage *page; GtkWidget *page_widget; GtkLabel *label; page = NEMO_PROPERTY_PAGE (l->data); g_object_get (G_OBJECT (page), "page", &page_widget, "label", &label, NULL); gtk_container_set_border_width (GTK_CONTAINER (page_widget), STACK_INNER_BORDER); gtk_stack_add_titled(window->details->stack, page_widget, gtk_label_get_text(label), gtk_label_get_text(label)); g_object_set_data (G_OBJECT (page_widget), "is-extension-page", page); g_object_unref (page_widget); g_object_unref (label); g_object_unref (page); } g_list_free (pages); } nemo_module_extension_list_free (providers); } static gboolean should_show_permissions (NemoPropertiesWindow *window) { NemoFile *file; file = get_target_file (window); /* Don't show permissions for Trash and Computer since they're not * really file system objects. */ if (!is_multi_file_window (window) && (nemo_file_is_in_trash (file) || nemo_file_is_in_recent (file) || is_computer_directory (file))) { return FALSE; } return TRUE; } static char * get_pending_key (GList *file_list) { GList *l; GList *uris; GString *key; char *ret; uris = NULL; for (l = file_list; l != NULL; l = l->next) { uris = g_list_prepend (uris, nemo_file_get_uri (NEMO_FILE (l->data))); } uris = g_list_sort (uris, (GCompareFunc)strcmp); key = g_string_new (""); for (l = uris; l != NULL; l = l->next) { g_string_append (key, l->data); g_string_append (key, ";"); } g_list_free_full (uris, g_free); ret = key->str; g_string_free (key, FALSE); return ret; } static StartupData * startup_data_new (GList *original_files, GList *target_files, const char *pending_key, GtkWidget *parent_widget, const char *startup_id) { StartupData *data; GList *l; data = g_new0 (StartupData, 1); data->original_files = nemo_file_list_copy (original_files); data->target_files = nemo_file_list_copy (target_files); data->parent_widget = parent_widget; data->startup_id = g_strdup (startup_id); data->pending_key = g_strdup (pending_key); data->pending_files = g_hash_table_new (g_direct_hash, g_direct_equal); for (l = data->target_files; l != NULL; l = l->next) { g_hash_table_insert (data->pending_files, l->data, l->data); } return data; } static void startup_data_free (StartupData *data) { nemo_file_list_free (data->original_files); nemo_file_list_free (data->target_files); g_hash_table_destroy (data->pending_files); g_free (data->pending_key); g_free (data->startup_id); g_free (data); } static void file_changed_callback (NemoFile *file, gpointer user_data) { NemoPropertiesWindow *window = NEMO_PROPERTIES_WINDOW (user_data); if (!g_list_find (window->details->changed_files, file)) { nemo_file_ref (file); window->details->changed_files = g_list_prepend (window->details->changed_files, file); schedule_files_update (window); } } static gboolean is_a_special_file (NemoFile *file) { if (file == NULL || NEMO_IS_DESKTOP_ICON_FILE (file) || nemo_file_is_nemo_link (file) || nemo_file_is_in_trash (file) || is_computer_directory (file)) { return TRUE; } return FALSE; } static gboolean should_show_open_with (NemoPropertiesWindow *window) { NemoFile *file; /* Don't show open with tab for desktop special icons (trash, etc) * or desktop files. We don't get the open-with menu for these anyway. * * Also don't show it for folders. Changing the default app for folders * leads to all sort of hard to understand errors. */ if (is_multi_file_window (window)) { if (!file_list_attributes_identical (window->details->original_files, "mime_type")) { return FALSE; } else { GList *l; for (l = window->details->original_files; l; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_is_directory (file) || is_a_special_file (file)) { return FALSE; } } } } else { file = get_original_file (window); if (nemo_file_is_directory (file) || is_a_special_file (file)) { return FALSE; } } return TRUE; } static void create_open_with_page (NemoPropertiesWindow *window) { GtkWidget *vbox; char *mime_type; char *uri = NULL; GList *uris = NULL; mime_type = nemo_file_get_mime_type (get_target_file (window)); if (!is_multi_file_window (window)) { uri = nemo_file_get_uri (get_target_file (window)); if (uri == NULL) { return; } } else { uris = window->details->original_files; if (uris == NULL) { return; } } vbox = nemo_mime_application_chooser_new (uri, uris, mime_type, NULL); gtk_widget_show (vbox); g_free (mime_type); g_object_set_data_full (G_OBJECT (vbox), "help-uri", g_strdup ("help:gnome-help/files-open"), g_free); gtk_container_set_border_width (GTK_CONTAINER (vbox), STACK_INNER_BORDER); gtk_stack_add_titled (window->details->stack, vbox, "open_with", _("Open With")); } static NemoPropertiesWindow * create_properties_window (StartupData *startup_data) { NemoPropertiesWindow *window; GList *l; window = NEMO_PROPERTIES_WINDOW (gtk_widget_new (NEMO_TYPE_PROPERTIES_WINDOW, NULL)); window->details->original_files = nemo_file_list_copy (startup_data->original_files); window->details->target_files = nemo_file_list_copy (startup_data->target_files); gtk_window_set_wmclass (GTK_WINDOW (window), "file_properties", "Nemo"); gtk_window_set_default_size (GTK_WINDOW (window), 500, -1); if (startup_data->parent_widget) { gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (startup_data->parent_widget)); } if (startup_data->startup_id) { gtk_window_set_startup_id (GTK_WINDOW (window), startup_data->startup_id); } gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DIALOG); /* Set initial window title */ update_properties_window_title (window); /* Start monitoring the file attributes we display. Note that some * of the attributes are for the original file, and some for the * target files. */ for (l = window->details->original_files; l != NULL; l = l->next) { NemoFile *file; NemoFileAttributes attributes; file = NEMO_FILE (l->data); attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; nemo_file_monitor_add (file, &window->details->original_files, attributes); } for (l = window->details->target_files; l != NULL; l = l->next) { NemoFile *file; NemoFileAttributes attributes; file = NEMO_FILE (l->data); attributes = 0; if (nemo_file_is_directory (file)) { attributes |= NEMO_FILE_ATTRIBUTE_DEEP_COUNTS; } attributes |= NEMO_FILE_ATTRIBUTE_INFO; nemo_file_monitor_add (file, &window->details->target_files, attributes); } for (l = window->details->target_files; l != NULL; l = l->next) { g_signal_connect_object (NEMO_FILE (l->data), "changed", G_CALLBACK (file_changed_callback), G_OBJECT (window), 0); } for (l = window->details->original_files; l != NULL; l = l->next) { g_signal_connect_object (NEMO_FILE (l->data), "changed", G_CALLBACK (file_changed_callback), G_OBJECT (window), 0); } /* Create the stack and the stack switcher. */ GtkWidget *toolbar = gtk_toolbar_new (); gtk_style_context_add_class (gtk_widget_get_style_context (toolbar), "primary-toolbar"); gtk_widget_show (toolbar); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area(GTK_DIALOG (window))), toolbar, FALSE, FALSE, 0); GtkToolItem * tool_item = gtk_tool_item_new (); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tool_item)), "raised"); gtk_tool_item_set_expand (tool_item, 1); gtk_widget_show (GTK_WIDGET (tool_item)); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, 0); window->details->stack = GTK_STACK (gtk_stack_new ()); GtkStackSwitcher *stack_switcher; stack_switcher = GTK_STACK_SWITCHER (gtk_stack_switcher_new ()); gtk_stack_switcher_set_stack (stack_switcher, window->details->stack); gtk_stack_set_transition_type (window->details->stack, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); gtk_widget_set_halign (GTK_WIDGET (stack_switcher), GTK_ALIGN_CENTER); gtk_widget_show (GTK_WIDGET (window->details->stack)); gtk_widget_show (GTK_WIDGET (stack_switcher)); gtk_container_add(GTK_CONTAINER (tool_item), GTK_WIDGET (stack_switcher)); GtkWidget * frame = gtk_frame_new (NULL); gtk_widget_show (frame); gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view"); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))), GTK_WIDGET (frame), TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (window->details->stack)); /* Create the pages. */ create_basic_page (window); if (should_show_permissions (window)) { create_permissions_page (window); } if (should_show_open_with (window)) { create_open_with_page (window); } /* append pages from available views */ append_extension_pages (window); gtk_dialog_add_buttons (GTK_DIALOG (window), _("Help"), GTK_RESPONSE_HELP, _("Close"), GTK_RESPONSE_CLOSE, NULL); /* FIXME - HIGificiation, should be done inside GTK+ */ gtk_widget_set_margin_left (frame, 6); gtk_widget_set_margin_right (frame, 6); gtk_widget_set_margin_top (frame, 8); gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (window))), 0); gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (window))), 5); /* Update from initial state */ properties_window_update (window, NULL); return window; } static GList * get_target_file_list (GList *original_files) { GList *ret; GList *l; ret = NULL; for (l = original_files; l != NULL; l = l->next) { NemoFile *target; target = get_target_file_for_original_file (NEMO_FILE (l->data)); ret = g_list_prepend (ret, target); } ret = g_list_reverse (ret); return ret; } static void add_window (NemoPropertiesWindow *window) { if (!is_multi_file_window (window)) { g_hash_table_insert (windows, get_original_file (window), window); g_object_set_data (G_OBJECT (window), "window_key", get_original_file (window)); } } static void remove_window (NemoPropertiesWindow *window) { gpointer key; key = g_object_get_data (G_OBJECT (window), "window_key"); if (key) { g_hash_table_remove (windows, key); } } static GtkWindow * get_existing_window (GList *file_list) { if (!file_list->next) { return g_hash_table_lookup (windows, file_list->data); } return NULL; } static void cancel_create_properties_window_callback (gpointer callback_data) { remove_pending ((StartupData *)callback_data, TRUE, FALSE, TRUE); } static void parent_widget_destroyed_callback (GtkWidget *widget, gpointer callback_data) { g_assert (widget == ((StartupData *)callback_data)->parent_widget); remove_pending ((StartupData *)callback_data, TRUE, TRUE, FALSE); } static void cancel_call_when_ready_callback (gpointer key, gpointer value, gpointer user_data) { nemo_file_cancel_call_when_ready (NEMO_FILE (key), is_directory_ready_callback, user_data); } static void remove_pending (StartupData *startup_data, gboolean cancel_call_when_ready, gboolean cancel_timed_wait, gboolean cancel_destroy_handler) { if (cancel_call_when_ready) { g_hash_table_foreach (startup_data->pending_files, cancel_call_when_ready_callback, startup_data); } if (cancel_timed_wait) { eel_timed_wait_stop (cancel_create_properties_window_callback, startup_data); } if (cancel_destroy_handler && startup_data->parent_widget) { g_signal_handlers_disconnect_by_func (startup_data->parent_widget, G_CALLBACK (parent_widget_destroyed_callback), startup_data); } g_hash_table_remove (pending_lists, startup_data->pending_key); startup_data_free (startup_data); } static void is_directory_ready_callback (NemoFile *file, gpointer data) { StartupData *startup_data; startup_data = data; g_hash_table_remove (startup_data->pending_files, file); if (g_hash_table_size (startup_data->pending_files) == 0) { NemoPropertiesWindow *new_window; new_window = create_properties_window (startup_data); add_window (new_window); remove_pending (startup_data, FALSE, TRUE, TRUE); gtk_window_present (GTK_WINDOW (new_window)); } } void nemo_properties_window_present (GList *original_files, GtkWidget *parent_widget, const gchar *startup_id) { GList *l, *next; GtkWidget *parent_window; StartupData *startup_data; GList *target_files; GtkWindow *existing_window; char *pending_key; g_return_if_fail (original_files != NULL); g_return_if_fail (parent_widget == NULL || GTK_IS_WIDGET (parent_widget)); /* Create the hash tables first time through. */ if (windows == NULL) { windows = g_hash_table_new (NULL, NULL); } if (pending_lists == NULL) { pending_lists = g_hash_table_new (g_str_hash, g_str_equal); } /* Look to see if there's already a window for this file. */ existing_window = get_existing_window (original_files); if (existing_window != NULL) { if (parent_widget) gtk_window_set_screen (existing_window, gtk_widget_get_screen (parent_widget)); else if (startup_id) gtk_window_set_startup_id (existing_window, startup_id); gtk_window_present (existing_window); return; } pending_key = get_pending_key (original_files); /* Look to see if we're already waiting for a window for this file. */ if (g_hash_table_lookup (pending_lists, pending_key) != NULL) { return; } target_files = get_target_file_list (original_files); startup_data = startup_data_new (original_files, target_files, pending_key, parent_widget, startup_id); nemo_file_list_free (target_files); g_free(pending_key); /* Wait until we can tell whether it's a directory before showing, since * some one-time layout decisions depend on that info. */ g_hash_table_insert (pending_lists, startup_data->pending_key, startup_data->pending_key); if (parent_widget) { g_signal_connect (parent_widget, "destroy", G_CALLBACK (parent_widget_destroyed_callback), startup_data); parent_window = gtk_widget_get_ancestor (parent_widget, GTK_TYPE_WINDOW); } else parent_window = NULL; eel_timed_wait_start (cancel_create_properties_window_callback, startup_data, _("Creating Properties window."), parent_window == NULL ? NULL : GTK_WINDOW (parent_window)); for (l = startup_data->target_files; l != NULL; l = next) { next = l->next; nemo_file_call_when_ready (NEMO_FILE (l->data), NEMO_FILE_ATTRIBUTE_INFO, is_directory_ready_callback, startup_data); } } static void real_response (GtkDialog *dialog, int response) { GError *error = NULL; NemoPropertiesWindow *window = NEMO_PROPERTIES_WINDOW (dialog); GtkWidget *curpage; const char *helpuri; switch (response) { case GTK_RESPONSE_HELP: curpage = gtk_stack_get_visible_child (window->details->stack); helpuri = g_object_get_data (G_OBJECT (curpage), "help-uri"); gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (dialog)), helpuri ? helpuri : "help:gnome-help/files", gtk_get_current_event_time (), &error); if (error != NULL) { eel_show_error_dialog (_("There was an error displaying help."), error->message, GTK_WINDOW (dialog)); g_error_free (error); } break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_CLOSE: case GTK_RESPONSE_DELETE_EVENT: gtk_widget_destroy (GTK_WIDGET (dialog)); break; default: g_assert_not_reached (); break; } } static void real_destroy (GtkWidget *object) { NemoPropertiesWindow *window; GList *l; window = NEMO_PROPERTIES_WINDOW (object); remove_window (window); for (l = window->details->original_files; l != NULL; l = l->next) { nemo_file_monitor_remove (NEMO_FILE (l->data), &window->details->original_files); } nemo_file_list_free (window->details->original_files); window->details->original_files = NULL; for (l = window->details->target_files; l != NULL; l = l->next) { nemo_file_monitor_remove (NEMO_FILE (l->data), &window->details->target_files); } nemo_file_list_free (window->details->target_files); window->details->target_files = NULL; nemo_file_list_free (window->details->changed_files); window->details->changed_files = NULL; window->details->name_field = NULL; g_list_free (window->details->permission_buttons); window->details->permission_buttons = NULL; g_list_free (window->details->permission_combos); window->details->permission_combos = NULL; if (window->details->initial_permissions) { g_hash_table_destroy (window->details->initial_permissions); window->details->initial_permissions = NULL; } g_list_free (window->details->value_fields); window->details->value_fields = NULL; if (window->details->update_directory_contents_timeout_id != 0) { g_source_remove (window->details->update_directory_contents_timeout_id); window->details->update_directory_contents_timeout_id = 0; } if (window->details->update_files_timeout_id != 0) { g_source_remove (window->details->update_files_timeout_id); window->details->update_files_timeout_id = 0; } window->details->icon_chooser = NULL; GTK_WIDGET_CLASS (nemo_properties_window_parent_class)->destroy (object); } static void real_finalize (GObject *object) { NemoPropertiesWindow *window; window = NEMO_PROPERTIES_WINDOW (object); g_list_free_full (window->details->mime_list, g_free); g_free (window->details->pending_name); G_OBJECT_CLASS (nemo_properties_window_parent_class)->finalize (object); } /* converts * file://foo/foobar/foofoo/bar * to * foofoo/bar * if * file://foo/foobar * is the parent * * It does not resolve any symlinks. * */ static char * make_relative_uri_from_full (const char *uri, const char *base_uri) { g_assert (uri != NULL); g_assert (base_uri != NULL); if (g_str_has_prefix (uri, base_uri)) { uri += strlen (base_uri); if (*uri != '/') { return NULL; } while (*uri == '/') { uri++; } if (*uri != '\0') { return g_strdup (uri); } } return NULL; } /* icon selection callback to set the image of the file object to the selected file */ static void set_icon (const char* icon_string, NemoPropertiesWindow *properties_window) { NemoFile *file; char *file_uri; GList *l; g_assert (icon_string != NULL); g_assert (NEMO_IS_PROPERTIES_WINDOW (properties_window)); if (g_path_is_absolute (icon_string)) { GFile *icon_file; char *icon_path; char *icon_uri; char *real_icon_uri; icon_file = g_file_new_for_path (icon_string); if (!g_file_is_native (icon_file)) { g_object_unref (icon_file); return; } icon_path = g_strdup (icon_string); icon_uri = g_file_get_uri (icon_file); g_object_unref (icon_file); for (l = properties_window->details->original_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); file_uri = nemo_file_get_uri (file); if (nemo_file_is_mime_type (file, "application/x-desktop")) { if (nemo_link_local_set_icon (file_uri, icon_path)) { nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO); } } else { real_icon_uri = make_relative_uri_from_full (icon_uri, file_uri); if (real_icon_uri == NULL) { real_icon_uri = g_strdup (icon_uri); } nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL, real_icon_uri); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_SCALE, NULL, NULL); g_free (real_icon_uri); } g_free (file_uri); } g_free (icon_path); g_free (icon_uri); } else { for (l = properties_window->details->original_files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); file_uri = nemo_file_get_uri (file); if (nemo_file_is_mime_type (file, "application/x-desktop")) { if (nemo_link_local_set_icon (file_uri, icon_string)) { nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO); } } else { nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL, NULL); nemo_file_set_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL, icon_string); nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_SCALE, NULL, NULL); } g_free (file_uri); } } } static void select_image_button_callback (GtkWidget *widget, NemoPropertiesWindow *window) { GtkWidget *dialog; gchar *image_uri, *icon_name; char *return_string; gint response; g_assert (NEMO_IS_PROPERTIES_WINDOW (window)); dialog = window->details->icon_chooser; image_uri = icon_name = NULL; if (dialog == NULL) { GtkWidget *revert_button; GList *l; gboolean revert_is_sensitive; dialog = GTK_WIDGET (xapp_icon_chooser_dialog_new ()); g_object_set (G_OBJECT (dialog), "allow-paths", TRUE, NULL); revert_button = gtk_button_new_with_label (_("Revert")); gtk_widget_show (revert_button); revert_is_sensitive = FALSE; for (l = window->details->original_files; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (l->data); image_uri = nemo_file_get_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL); icon_name = nemo_file_get_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL); revert_is_sensitive = (image_uri != NULL || icon_name != NULL); if (revert_is_sensitive) { break; } g_free (image_uri); g_free (icon_name); } gtk_widget_set_sensitive (GTK_WIDGET (revert_button), revert_is_sensitive); xapp_icon_chooser_dialog_add_button (XAPP_ICON_CHOOSER_DIALOG (dialog), revert_button, GTK_PACK_START, NEMO_RESPONSE_REVERT); window->details->icon_chooser = dialog; gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window)); g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &window->details->icon_chooser); } if (image_uri == NULL && icon_name == NULL) { response = xapp_icon_chooser_dialog_run (XAPP_ICON_CHOOSER_DIALOG (dialog)); } else { if (image_uri) { GFile *icon_location; gchar *path; icon_location = g_file_new_for_uri (image_uri); path = g_file_get_path (icon_location); g_object_unref (icon_location); response = xapp_icon_chooser_dialog_run_with_icon (XAPP_ICON_CHOOSER_DIALOG (dialog), path); g_free (path); } else { response = xapp_icon_chooser_dialog_run_with_icon (XAPP_ICON_CHOOSER_DIALOG (dialog), icon_name); } } switch (response) { case NEMO_RESPONSE_REVERT: reset_icon (window); break; case GTK_RESPONSE_OK: return_string = xapp_icon_chooser_dialog_get_icon_string (XAPP_ICON_CHOOSER_DIALOG (dialog)); set_icon (return_string, window); g_free (return_string); break; default: break; } g_free (image_uri); g_free (icon_name); gtk_widget_destroy (GTK_WIDGET (dialog)); } static void nemo_properties_window_class_init (NemoPropertiesWindowClass *class) { GtkBindingSet *binding_set; G_OBJECT_CLASS (class)->finalize = real_finalize; GTK_WIDGET_CLASS (class)->destroy = real_destroy; GTK_DIALOG_CLASS (class)->response = real_response; binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0); g_type_class_add_private (class, sizeof (NemoPropertiesWindowDetails)); } static void nemo_properties_window_init (NemoPropertiesWindow *window) { window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_PROPERTIES_WINDOW, NemoPropertiesWindowDetails); } nemo-4.4.2/src/nemo-properties-window.h000066400000000000000000000050071357442400300200600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* fm-properties-window.h - interface for window that lets user modify icon properties Copyright (C) 2000 Eazel, Inc. The Gnome 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. The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. Authors: Darin Adler */ #ifndef NEMO_PROPERTIES_WINDOW_H #define NEMO_PROPERTIES_WINDOW_H #include #include typedef struct NemoPropertiesWindow NemoPropertiesWindow; #define NEMO_TYPE_PROPERTIES_WINDOW nemo_properties_window_get_type() #define NEMO_PROPERTIES_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_PROPERTIES_WINDOW, NemoPropertiesWindow)) #define NEMO_PROPERTIES_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_PROPERTIES_WINDOW, NemoPropertiesWindowClass)) #define NEMO_IS_PROPERTIES_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_PROPERTIES_WINDOW)) #define NEMO_IS_PROPERTIES_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_PROPERTIES_WINDOW)) #define NEMO_PROPERTIES_WINDOW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_PROPERTIES_WINDOW, NemoPropertiesWindowClass)) typedef struct NemoPropertiesWindowDetails NemoPropertiesWindowDetails; struct NemoPropertiesWindow { GtkDialog window; NemoPropertiesWindowDetails *details; }; struct NemoPropertiesWindowClass { GtkDialogClass parent_class; /* Keybinding signals */ void (* close) (NemoPropertiesWindow *window); }; typedef struct NemoPropertiesWindowClass NemoPropertiesWindowClass; GType nemo_properties_window_get_type (void); void nemo_properties_window_present (GList *files, GtkWidget *parent_widget, const gchar *startup_id); #endif /* NEMO_PROPERTIES_WINDOW_H */ nemo-4.4.2/src/nemo-query-editor.c000066400000000000000000000631621357442400300170110ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* * Copyright (C) 2005 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #include #include "nemo-query-editor.h" #include "nemo-file-utilities.h" #include #include #include #include #include #include #include typedef struct { GtkWidget *infobar; GtkWidget *entry; GtkWidget *menu; gboolean change_frozen; guint typing_timeout_id; gboolean is_visible; GtkWidget *vbox; gchar **faves; char *current_uri; char *base_uri; char *last_set_query_text; } NemoQueryEditorPrivate; struct _NemoQueryEditor { GtkBox parent_object; NemoQueryEditorPrivate *priv; }; G_DEFINE_TYPE_WITH_PRIVATE (NemoQueryEditor, nemo_query_editor, GTK_TYPE_BOX) enum { CHANGED, CANCEL, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void entry_activate_cb (GtkWidget *entry, NemoQueryEditor *editor); static void entry_changed_cb (GtkWidget *entry, NemoQueryEditor *editor); static void nemo_query_editor_changed_force (NemoQueryEditor *editor, gboolean force); static void nemo_query_editor_changed (NemoQueryEditor *editor); static void on_saved_searches_setting_changed (GSettings *settings, gchar *key, gpointer user_data); static gchar * get_sanitized_query_string (NemoQueryEditor *editor) { const gchar *entry_text; gchar *ret; entry_text = gtk_entry_get_text (GTK_ENTRY (editor->priv->entry)); ret = g_strdup (entry_text); ret = g_strstrip (ret); return ret; } static void nemo_query_editor_dispose (GObject *object) { NemoQueryEditor *editor; editor = NEMO_QUERY_EDITOR (object); g_clear_pointer (&editor->priv->base_uri, g_free); if (editor->priv->typing_timeout_id > 0) { g_source_remove (editor->priv->typing_timeout_id); editor->priv->typing_timeout_id = 0; } g_clear_object (&editor->priv->menu); g_signal_handlers_disconnect_by_func (nemo_preferences, on_saved_searches_setting_changed, editor); G_OBJECT_CLASS (nemo_query_editor_parent_class)->dispose (object); } static void nemo_query_editor_grab_focus (GtkWidget *widget) { NemoQueryEditor *editor = NEMO_QUERY_EDITOR (widget); if (gtk_widget_get_visible (widget)) { gtk_entry_grab_focus_without_selecting (GTK_ENTRY (editor->priv->entry)); } } static void nemo_query_editor_class_init (NemoQueryEditorClass *class) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkBindingSet *binding_set; gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = nemo_query_editor_dispose; widget_class = GTK_WIDGET_CLASS (class); widget_class->grab_focus = nemo_query_editor_grab_focus; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, NEMO_TYPE_QUERY, G_TYPE_BOOLEAN); signals[CANCEL] = g_signal_new ("cancel", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "cancel", 0); } GFile * nemo_query_editor_get_location (NemoQueryEditor *editor) { GFile *file = NULL; if (editor->priv->current_uri != NULL) file = g_file_new_for_uri (editor->priv->current_uri); return file; } static void entry_activate_cb (GtkWidget *entry, NemoQueryEditor *editor) { g_autofree gchar *text = NULL; if (editor->priv->typing_timeout_id > 0) { g_source_remove (editor->priv->typing_timeout_id); editor->priv->typing_timeout_id = 0; } text = get_sanitized_query_string (editor); if (strlen (text) > 2) { nemo_query_editor_changed_force (editor, TRUE); } } static gboolean typing_timeout_cb (gpointer user_data) { NemoQueryEditor *editor; editor = NEMO_QUERY_EDITOR (user_data); editor->priv->typing_timeout_id = 0; nemo_query_editor_changed (editor); return FALSE; } #define TYPING_TIMEOUT 250 static gchar * construct_favorite_entry (const gchar *uri, const gchar *key) { return g_strdup_printf ("%s::%s", uri, key); } static gboolean parse_favorite_entry (const gchar *favorite_entry, gchar **uri, gchar **key) { gchar **split; split = g_strsplit (favorite_entry, "::", 2); if (split == NULL || g_strv_length (split) < 2) { *key = NULL; *uri = NULL; return FALSE; } *uri = g_strdup (split[0]); *key = g_strdup (split[1]); g_strfreev (split); return TRUE; } static gboolean is_search_criteria_in_faves (NemoQueryEditor *editor, const gchar *key) { gint i, length; gboolean ret; length = g_strv_length (editor->priv->faves); if (length == 0) { return FALSE; } ret = FALSE; for (i = 0; i < length; i++) { gchar *favorite_uri, *favorite_key; if (parse_favorite_entry (editor->priv->faves[i], &favorite_uri, &favorite_key)) { if (g_strcmp0 (editor->priv->current_uri, favorite_uri) == 0) { if (g_strcmp0 (key, favorite_key) == 0) { ret = TRUE; } } g_clear_pointer (&favorite_uri, g_free); g_clear_pointer (&favorite_key, g_free); } if (ret) { break; } } return ret; } static void add_key_to_faves (NemoQueryEditor *editor, const gchar *entry) { gint i; GPtrArray *array; array = g_ptr_array_new (); g_ptr_array_add (array, g_strdup (entry)); if (editor->priv->faves != NULL) { for (i = 0; i < g_strv_length (editor->priv->faves); i++) { g_ptr_array_add (array, g_strdup (editor->priv->faves[i])); } } g_ptr_array_add (array, NULL); g_signal_handlers_block_by_func (nemo_preferences, on_saved_searches_setting_changed, editor); g_settings_set_strv (nemo_preferences, NEMO_PREFERENCES_SAVED_SEARCHES, (const gchar * const *) array->pdata); g_signal_handlers_unblock_by_func (nemo_preferences, on_saved_searches_setting_changed, editor); editor->priv->faves = (gchar **) g_ptr_array_free (array, FALSE); } static void remove_key_from_faves (NemoQueryEditor *editor, const gchar *entry) { gint i; gchar *key, *uri; GPtrArray *array; if (!parse_favorite_entry (entry, &uri, &key)) { return; } array = g_ptr_array_new (); if (editor->priv->faves != NULL) { for (i = 0; i < g_strv_length (editor->priv->faves); i++) { gchar *favorite_key, *favorite_uri; if (parse_favorite_entry (editor->priv->faves[i], &favorite_uri, &favorite_key)) { if (g_strcmp0 (key, favorite_key) != 0 || g_strcmp0 (uri, favorite_uri) != 0) { g_ptr_array_add (array, g_strdup (editor->priv->faves[i])); } g_free (favorite_key); g_free (favorite_uri); } } } g_ptr_array_add (array, NULL); g_signal_handlers_block_by_func (nemo_preferences, on_saved_searches_setting_changed, editor); g_settings_set_strv (nemo_preferences, NEMO_PREFERENCES_SAVED_SEARCHES, (const gchar * const *) array->pdata); g_signal_handlers_unblock_by_func (nemo_preferences, on_saved_searches_setting_changed, editor); g_free (key); g_free (uri); editor->priv->faves = (gchar **) g_ptr_array_free (array, FALSE); } static void update_fav_icon (NemoQueryEditor *editor) { g_autofree gchar *current_key = NULL; current_key = get_sanitized_query_string (editor); if (is_search_criteria_in_faves (editor, current_key)) { gtk_entry_set_icon_from_icon_name (GTK_ENTRY (editor->priv->entry), GTK_ENTRY_ICON_SECONDARY, "starred-symbolic"); return; } gtk_entry_set_icon_from_icon_name (GTK_ENTRY (editor->priv->entry), GTK_ENTRY_ICON_SECONDARY, "non-starred-symbolic"); } static void entry_changed_cb (GtkWidget *entry, NemoQueryEditor *editor) { g_autofree gchar *text = NULL; if (editor->priv->change_frozen) { return; } if (editor->priv->typing_timeout_id > 0) { g_source_remove (editor->priv->typing_timeout_id); editor->priv->typing_timeout_id = 0; } update_fav_icon (editor); text = get_sanitized_query_string (editor); if (strlen (text) > 2) { editor->priv->typing_timeout_id = g_timeout_add (TYPING_TIMEOUT, typing_timeout_cb, editor); } } static void get_markup_for_fave (NemoQueryEditor *editor, const gchar *favorite, gchar **loc_markup, gchar **key_markup) { GFile *location; gchar *favorite_key, *favorite_location; gchar *location_string, *mnemonic_key; if (!parse_favorite_entry (favorite, &favorite_location, &favorite_key)) { *loc_markup = NULL; *key_markup = NULL; return; } location = g_file_new_for_uri (favorite_location); location_string = nemo_compute_search_title_for_location (location); mnemonic_key = g_strdup_printf ("_%s", favorite_key); *loc_markup = g_strdup_printf (_("in %s"), location_string); *key_markup = g_strdup_printf (_("Search for %s"), mnemonic_key); g_free (favorite_location); g_free (favorite_key); g_free (location_string); g_free (mnemonic_key); g_object_unref (location); } static void on_menu_item_activated (GtkMenuItem *item, gpointer user_data) { NemoQueryEditor *editor; NemoQuery *query; const gchar *fave_entry; gchar *favorite_key, *favorite_location; editor = NEMO_QUERY_EDITOR (user_data); fave_entry = g_object_get_data (G_OBJECT (item), "fave-entry"); if (parse_favorite_entry (fave_entry, &favorite_location, &favorite_key)) { query = nemo_query_new (); nemo_query_set_location (query, favorite_location); nemo_query_set_text (query, favorite_key); nemo_query_editor_set_query (editor, query); nemo_query_editor_changed (editor); update_fav_icon (editor); g_free (favorite_location); g_free (favorite_key); } } static gboolean on_menu_item_key_press (GtkWidget *widget, GdkEvent *event, gpointer user_data) { if (event->key.state == 0 && event->key.keyval == GDK_KEY_Delete) { NemoQueryEditor *editor; GtkWidget *item; const gchar *fave_entry; editor = NEMO_QUERY_EDITOR (user_data); item = gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (widget)); if (item == NULL) { return GDK_EVENT_PROPAGATE; } fave_entry = g_object_get_data (G_OBJECT (item), "fave-entry"); remove_key_from_faves (editor, fave_entry); gtk_widget_set_sensitive (item, FALSE); update_fav_icon (editor); return GDK_EVENT_STOP; } return GDK_EVENT_PROPAGATE; } #if !GTK_CHECK_VERSION (3, 22, 0) static void menu_position_function (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) { NemoQueryEditor *editor; GtkWidget *parent; GtkAllocation menu_allocation; gint window_x, window_y, translated_x, translated_y; g_return_if_fail (NEMO_IS_QUERY_EDITOR (user_data)); editor = NEMO_QUERY_EDITOR (user_data); parent = gtk_widget_get_toplevel (GTK_WIDGET (editor)); gtk_widget_translate_coordinates (editor->priv->entry, parent, 0, 0, &translated_x, &translated_y); gdk_window_get_position (gtk_widget_get_window (parent), &window_x, &window_y); gtk_widget_get_allocation (GTK_WIDGET (menu), &menu_allocation); *x = translated_x + window_x; *y = translated_y + window_y - menu_allocation.height; *push_in = TRUE; } #endif static void popup_favorites (NemoQueryEditor *editor, GdkEvent *event, gboolean use_pointer_location) { GtkWidget *menu, *item, *item_child; GtkSizeGroup *group; gchar **faves; gint i; if (g_strv_length (editor->priv->faves) == 0) { return; } g_clear_object (&editor->priv->menu); editor->priv->menu = menu = g_object_ref_sink (gtk_menu_new ()); group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); faves = editor->priv->faves; for (i = 0; i < g_strv_length (faves); i++) { GtkWidget *label; gchar *loc_markup, *key_markup; get_markup_for_fave (editor, faves[i], &loc_markup, &key_markup); if (loc_markup == NULL || key_markup == NULL) { continue; } item = gtk_menu_item_new(); item_child = gtk_bin_get_child (GTK_BIN (item)); if (item_child != NULL) { gtk_widget_destroy (item_child); } item_child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); gtk_container_add (GTK_CONTAINER (item), item_child); label = gtk_label_new (NULL); gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), key_markup); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (item_child), label, FALSE, FALSE, 0); gtk_size_group_add_widget (group, label); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), loc_markup); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (item_child), label, FALSE, FALSE, 0); g_object_set_data_full (G_OBJECT (item), "fave-entry", g_strdup (faves[i]), (GDestroyNotify) g_free); g_free (loc_markup); g_free (key_markup); gtk_widget_show_all (GTK_WIDGET (item)); gtk_menu_attach (GTK_MENU (menu), item, 0, 1, i, i + 1); g_signal_connect (item, "activate", G_CALLBACK (on_menu_item_activated), editor); } g_object_unref (group); g_signal_connect (menu, "key-press-event", G_CALLBACK (on_menu_item_key_press), editor); #if GTK_CHECK_VERSION (3, 22, 0) if (use_pointer_location) { gtk_menu_popup_at_pointer (GTK_MENU (menu), event); } else { gtk_menu_popup_at_widget (GTK_MENU (menu), editor->priv->entry, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_SOUTH_WEST, event); } #else if (use_pointer_location) { gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time ()); } else { gtk_menu_popup (GTK_MENU (menu), NULL, NULL, (GtkMenuPositionFunc) menu_position_function, editor, 0, gtk_get_current_event_time ()); } #endif } static gboolean on_key_press_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { if ((event->key.state & gtk_accelerator_get_default_mod_mask ()) == 0 && event->key.keyval == GDK_KEY_Up) { popup_favorites (NEMO_QUERY_EDITOR (user_data), event, FALSE); return GDK_EVENT_STOP; } return GDK_EVENT_PROPAGATE; } static void fave_icon_clicked_cb (GtkWidget *widget, GtkEntryIconPosition position, GdkEvent *event, gpointer user_data) { NemoQueryEditor *editor; g_autofree gchar *current_key = NULL; if (position == GTK_ENTRY_ICON_PRIMARY) { return; } editor = NEMO_QUERY_EDITOR (user_data); current_key = get_sanitized_query_string (editor); if ((event->button.state & gtk_accelerator_get_default_mod_mask ()) == 0 && event->button.button == 1) { gchar *entry; if (strlen (current_key) < 3) { return; } entry = construct_favorite_entry (editor->priv->current_uri, current_key); if (is_search_criteria_in_faves (editor, current_key)) { remove_key_from_faves (editor, entry); } else { add_key_to_faves (editor, entry); } g_free (entry); update_fav_icon (editor); } else { popup_favorites (editor, event, TRUE); } } static void on_saved_searches_setting_changed (GSettings *settings, gchar *key, gpointer user_data) { NemoQueryEditor *editor; g_return_if_fail (NEMO_IS_QUERY_EDITOR (user_data)); editor = NEMO_QUERY_EDITOR (user_data); editor->priv->faves = g_settings_get_strv (settings, key); } static void nemo_query_editor_init (NemoQueryEditor *editor) { NemoQueryEditorPrivate *priv; GtkWidget *separator; editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor, NEMO_TYPE_QUERY_EDITOR, NemoQueryEditorPrivate); priv = editor->priv; priv->base_uri = NULL; priv->menu = NULL; priv->faves = g_settings_get_strv (nemo_preferences, NEMO_PREFERENCES_SAVED_SEARCHES); gtk_orientable_set_orientation (GTK_ORIENTABLE (editor), GTK_ORIENTATION_VERTICAL); priv->infobar = gtk_info_bar_new (); gtk_box_pack_start (GTK_BOX (editor), priv->infobar, TRUE, TRUE, 0); gtk_widget_set_no_show_all (priv->infobar, TRUE); gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar), GTK_MESSAGE_OTHER); priv->entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (priv->infobar))), priv->entry, TRUE, TRUE, 0); gtk_widget_show (priv->entry); gtk_entry_set_placeholder_text (GTK_ENTRY (priv->entry), _("Type to search or arrow-up to select a favorite")); g_signal_connect (priv->entry, "activate", G_CALLBACK (entry_activate_cb), editor); g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed_cb), editor); gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry), GTK_ENTRY_ICON_PRIMARY, "edit-find-symbolic"); gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry), GTK_ENTRY_ICON_SECONDARY, "non-starred-symbolic"); gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv->entry), GTK_ENTRY_ICON_SECONDARY, _("Click to save or forget a favorite search. " "Right-click to display favorites.")); g_signal_connect (priv->entry, "icon-press", G_CALLBACK (fave_icon_clicked_cb), editor); separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL); gtk_box_pack_start (GTK_BOX (editor), separator, TRUE, TRUE, 0); g_object_bind_property (priv->infobar, "visible", separator, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); g_signal_connect (nemo_preferences, "changed::" NEMO_PREFERENCES_SAVED_SEARCHES, G_CALLBACK (on_saved_searches_setting_changed), editor); gtk_widget_show (GTK_WIDGET (editor)); } static void nemo_query_editor_changed_force (NemoQueryEditor *editor, gboolean force_reload) { NemoQuery *query; if (editor->priv->change_frozen) { return; } query = nemo_query_editor_get_query (editor); g_signal_emit (editor, signals[CHANGED], 0, query, force_reload); g_clear_object (&query); } static void nemo_query_editor_changed (NemoQueryEditor *editor) { nemo_query_editor_changed_force (editor, TRUE); } static void add_location_to_query (NemoQueryEditor *editor, NemoQuery *query) { char *uri; uri = g_strdup (editor->priv->current_uri); nemo_query_set_location (query, uri); g_free (uri); } NemoQuery * nemo_query_editor_get_query (NemoQueryEditor *editor) { NemoQuery *query; g_autofree gchar *query_text = NULL; if (editor == NULL || editor->priv == NULL || editor->priv->entry == NULL) { return NULL; } query_text = get_sanitized_query_string (editor); if (g_strcmp0 (query_text, "") == 0) { return NULL; } query = nemo_query_new (); nemo_query_set_text (query, query_text); add_location_to_query (editor, query); return query; } GtkWidget * nemo_query_editor_new (void) { return g_object_new (NEMO_TYPE_QUERY_EDITOR, NULL); } void nemo_query_editor_set_location (NemoQueryEditor *editor, GFile *location) { g_free (editor->priv->current_uri); editor->priv->current_uri = g_file_get_uri (location); } void nemo_query_editor_set_query (NemoQueryEditor *editor, NemoQuery *query) { char *text = NULL; if (query != NULL) { text = nemo_query_get_text (query); } if (!text) { text = g_strdup (""); } editor->priv->change_frozen = TRUE; gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), text); gtk_widget_grab_focus (editor->priv->entry); g_free (editor->priv->current_uri); editor->priv->current_uri = NULL; if (query != NULL) { editor->priv->current_uri = nemo_query_get_location (query); } g_free (editor->priv->last_set_query_text); editor->priv->last_set_query_text = text; editor->priv->change_frozen = FALSE; } void nemo_query_editor_set_active (NemoQueryEditor *editor, gchar *base_uri, gboolean active) { g_return_if_fail (NEMO_IS_QUERY_EDITOR (editor)); if (active) { gtk_widget_show (editor->priv->infobar); gtk_widget_queue_resize (GTK_WIDGET (editor->priv->infobar)); g_clear_pointer (&editor->priv->base_uri, g_free); editor->priv->base_uri = base_uri; g_signal_connect (editor->priv->entry, "key-press-event", G_CALLBACK (on_key_press_event), editor); update_fav_icon (editor); } else { g_signal_handlers_disconnect_by_func (editor->priv->entry, on_key_press_event, editor); gtk_widget_hide (editor->priv->infobar); } } gboolean nemo_query_editor_get_active (NemoQueryEditor *editor) { g_return_val_if_fail (NEMO_IS_QUERY_EDITOR (editor), FALSE); return gtk_widget_get_visible (editor->priv->infobar); } const gchar * nemo_query_editor_get_base_uri (NemoQueryEditor *editor) { g_return_val_if_fail (NEMO_IS_QUERY_EDITOR (editor), NULL); return editor->priv->base_uri; } nemo-4.4.2/src/nemo-query-editor.h000066400000000000000000000041341357442400300170100ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Red Hat, Inc. * * Nemo 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. * * Nemo 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; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Alexander Larsson * */ #ifndef NEMO_QUERY_EDITOR_H #define NEMO_QUERY_EDITOR_H #include #include G_BEGIN_DECLS #define NEMO_TYPE_QUERY_EDITOR (nemo_query_editor_get_type ()) G_DECLARE_FINAL_TYPE (NemoQueryEditor, nemo_query_editor, NEMO, QUERY_EDITOR, GtkBox) GtkWidget* nemo_query_editor_new (void); NemoQuery *nemo_query_editor_get_query (NemoQueryEditor *editor); void nemo_query_editor_set_query (NemoQueryEditor *editor, NemoQuery *query); GFile *nemo_query_editor_get_location (NemoQueryEditor *editor); void nemo_query_editor_set_location (NemoQueryEditor *editor, GFile *location); void nemo_query_editor_set_active (NemoQueryEditor *editor, gchar *base_uri, gboolean active); gboolean nemo_query_editor_get_active (NemoQueryEditor *editor); const gchar *nemo_query_editor_get_base_uri (NemoQueryEditor *editor); G_END_DECLS #endif /* NEMO_QUERY_EDITOR_H */ nemo-4.4.2/src/nemo-script-config-widget.c000066400000000000000000000262211357442400300204030ustar00rootroot00000000000000/* nemo-script-config-widget.h */ /* A widget that displays a list of scripts to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #include #include "nemo-script-config-widget.h" #include "nemo-application.h" #include "nemo-view.h" #include "nemo-file.h" #include "nemo-global-preferences.h" #include #include G_DEFINE_TYPE (NemoScriptConfigWidget, nemo_script_config_widget, NEMO_TYPE_CONFIG_BASE_WIDGET); typedef struct { NemoScriptConfigWidget *widget; gchar *name; } ScriptProxy; static void script_proxy_free (ScriptProxy *proxy) { g_clear_pointer (&proxy->name, g_free); } static GtkWidget * get_button_for_row (GtkWidget *row) { GtkWidget *ret; GtkWidget *box = gtk_bin_get_child (GTK_BIN (row)); GList *clist = gtk_container_get_children (GTK_CONTAINER (box)); ret = clist->data; g_list_free (clist); return ret; } static void on_row_activated (GtkWidget *box, GtkWidget *row, GtkWidget *widget) { GtkWidget *button = get_button_for_row (row); gtk_button_clicked (GTK_BUTTON (button)); } static void on_check_toggled(GtkWidget *button, ScriptProxy *proxy) { gboolean enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS); GPtrArray *new_list = g_ptr_array_new (); guint i; if (enabled) { for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->name) == 0) continue; g_ptr_array_add (new_list, g_strdup (blacklist[i])); } } else { for (i = 0; i < g_strv_length (blacklist); i++) { g_ptr_array_add (new_list, g_strdup (blacklist[i])); } g_ptr_array_add (new_list, g_strdup (proxy->name)); } g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_signal_handler_block (nemo_plugin_preferences, proxy->widget->bl_handler); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS, (const gchar * const *) new_list_ptr); g_signal_handler_unblock (nemo_plugin_preferences, proxy->widget->bl_handler); g_strfreev (blacklist); g_strfreev (new_list_ptr); } static void populate_from_directory (NemoScriptConfigWidget *widget, const gchar *path) { GDir *dir; dir = g_dir_open (path, 0, NULL); if (dir) { const char *name; while ((name = g_dir_read_name (dir))) { char *filename; filename = g_build_filename (path, name, NULL); if (g_file_test (filename, G_FILE_TEST_IS_DIR)) { populate_from_directory (widget, filename); g_free (filename); continue; } ScriptProxy *p = g_slice_new0 (ScriptProxy); p->name = g_strdup (name); p->widget = widget; widget->scripts = g_list_append (widget->scripts, p); g_free (filename); } g_dir_close (dir); } } static void refresh_widget (NemoScriptConfigWidget *widget) { if (widget->scripts != NULL) { g_list_free_full (widget->scripts, (GDestroyNotify) script_proxy_free); widget->scripts = NULL; } nemo_config_base_widget_clear_list (NEMO_CONFIG_BASE_WIDGET (widget)); gchar *path = NULL; path = nemo_get_scripts_directory_path (); populate_from_directory (widget, path); g_clear_pointer (&path, g_free); if (widget->scripts == NULL) { GtkWidget *empty_label = gtk_label_new (NULL); gchar *markup = NULL; markup = g_strdup_printf ("%s", _("No scripts found")); gtk_label_set_markup (GTK_LABEL (empty_label), markup); g_free (markup); GtkWidget *empty_row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (empty_row), empty_label); gtk_widget_show_all (empty_row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), empty_row); gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), FALSE); } else { GList *l; gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS); for (l = widget->scripts; l != NULL; l=l->next) { ScriptProxy *proxy = l->data; gboolean active = TRUE; guint i = 0; for (i = 0; i < g_strv_length (blacklist); i++) { if (g_strcmp0 (blacklist[i], proxy->name) == 0) { active = FALSE; break; } } GtkWidget *w; GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); GtkWidget *button = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active); g_signal_connect (button, "toggled", G_CALLBACK (on_check_toggled), proxy); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2); w = gtk_label_new (proxy->name); gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 2); GtkWidget *row = gtk_list_box_row_new (); gtk_container_add (GTK_CONTAINER (row), box); gtk_widget_show_all (row); gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), row); } gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), TRUE); g_strfreev (blacklist); } nemo_config_base_widget_set_default_buttons_sensitive (NEMO_CONFIG_BASE_WIDGET (widget), widget->scripts != NULL); } static void on_settings_changed (GSettings *settings, gchar *key, gpointer user_data) { NemoScriptConfigWidget *w = NEMO_SCRIPT_CONFIG_WIDGET (user_data); refresh_widget (w); } static void on_enable_clicked (GtkWidget *button, NemoScriptConfigWidget *widget) { g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS, NULL); } static void on_disable_clicked (GtkWidget *button, NemoScriptConfigWidget *widget) { GPtrArray *new_list = g_ptr_array_new (); GList *l; for (l = widget->scripts; l != NULL; l = l->next) g_ptr_array_add (new_list, g_strdup (((ScriptProxy *) l->data)->name)); g_ptr_array_add (new_list, NULL); gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE); g_settings_set_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS, (const gchar * const *) new_list_ptr); g_strfreev (new_list_ptr); } static void on_open_folder_clicked (GtkWidget *button, NemoScriptConfigWidget *widget) { gchar *path = NULL; path = nemo_get_scripts_directory_path (); GFile *location = g_file_new_for_path (path); nemo_application_open_location (nemo_application_get_singleton (), location, NULL, "nemo", FALSE); g_free (path); g_object_unref (location); } static void on_dir_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { NemoScriptConfigWidget *widget = NEMO_SCRIPT_CONFIG_WIDGET (user_data); refresh_widget (widget); } static void try_monitor_path (NemoScriptConfigWidget *widget, const gchar *path) { GFile *dir = g_file_new_for_path (path); GFileMonitor *mon = g_file_monitor_directory (dir, G_FILE_MONITOR_SEND_MOVED, NULL, NULL); g_object_unref (dir); if (mon != NULL) { g_signal_connect (mon, "changed", G_CALLBACK (on_dir_changed), widget); widget->dir_monitors = g_list_append (widget->dir_monitors, mon); } } static void setup_dir_monitors (NemoScriptConfigWidget *widget) { widget->dir_monitors = NULL; gchar **data_dirs = (gchar **) g_get_system_data_dirs (); guint i; for (i = 0; i < g_strv_length (data_dirs); i++) { gchar *path = g_build_filename (data_dirs[i], "nemo", "actions", NULL); try_monitor_path (widget, path); g_free (path); } gchar *path = g_build_filename (g_get_user_data_dir (), "nemo", "actions", NULL); try_monitor_path (widget, path); g_free (path); } static void nemo_script_config_widget_finalize (GObject *object) { NemoScriptConfigWidget *widget = NEMO_SCRIPT_CONFIG_WIDGET (object); if (widget->scripts != NULL) { g_list_free_full (widget->scripts, (GDestroyNotify) script_proxy_free); widget->scripts = NULL; } GList *l; for (l = widget->dir_monitors; l != NULL; l = l->next) { g_file_monitor_cancel (l->data); g_object_unref (l->data); } g_list_free (widget->dir_monitors); g_signal_handler_disconnect (nemo_plugin_preferences, widget->bl_handler); G_OBJECT_CLASS (nemo_script_config_widget_parent_class)->finalize (object); } static void nemo_script_config_widget_class_init (NemoScriptConfigWidgetClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_script_config_widget_finalize; } static void nemo_script_config_widget_init (NemoScriptConfigWidget *self) { self->scripts = NULL; self->bl_handler = g_signal_connect (nemo_plugin_preferences, "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS, G_CALLBACK (on_settings_changed), self); GtkWidget *label = nemo_config_base_widget_get_label (NEMO_CONFIG_BASE_WIDGET (self)); gchar *title = g_strdup (_("Scripts")); gchar *markup = g_strdup_printf ("%s", title); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (title); g_free (markup); GtkWidget *widget = gtk_button_new_from_icon_name ("folder", GTK_ICON_SIZE_BUTTON); GtkWidget *bb = nemo_config_base_widget_get_buttonbox (NEMO_CONFIG_BASE_WIDGET (self)); gtk_box_pack_end (GTK_BOX (bb), widget, FALSE, FALSE, 0); gtk_widget_show (widget); g_signal_connect (widget, "clicked", G_CALLBACK (on_open_folder_clicked), self); g_signal_connect (nemo_config_base_widget_get_enable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_enable_clicked), self); g_signal_connect (nemo_config_base_widget_get_disable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked", G_CALLBACK (on_disable_clicked), self); g_signal_connect (NEMO_CONFIG_BASE_WIDGET (self)->listbox, "row-activated", G_CALLBACK (on_row_activated), self); refresh_widget (self); setup_dir_monitors (self); } GtkWidget * nemo_script_config_widget_new (void) { return g_object_new (NEMO_TYPE_SCRIPT_CONFIG_WIDGET, NULL); } nemo-4.4.2/src/nemo-script-config-widget.h000066400000000000000000000031331357442400300204050ustar00rootroot00000000000000/* nemo-script-config-widget.h */ /* A widget that displays a list of scripts to enable or disable. * This is usually part of a NemoPluginManagerWidget */ #ifndef __NEMO_SCRIPT_CONFIG_WIDGET_H__ #define __NEMO_SCRIPT_CONFIG_WIDGET_H__ #include #include #include #include "nemo-config-base-widget.h" G_BEGIN_DECLS #define NEMO_TYPE_SCRIPT_CONFIG_WIDGET (nemo_script_config_widget_get_type()) #define NEMO_SCRIPT_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_SCRIPT_CONFIG_WIDGET, NemoScriptConfigWidget)) #define NEMO_SCRIPT_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_SCRIPT_CONFIG_WIDGET, NemoScriptConfigWidgetClass)) #define NEMO_IS_SCRIPT_CONFIG_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_SCRIPT_CONFIG_WIDGET)) #define NEMO_IS_SCRIPT_CONFIG_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_SCRIPT_CONFIG_WIDGET)) #define NEMO_SCRIPT_CONFIG_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_SCRIPT_CONFIG_WIDGET, NemoScriptConfigWidgetClass)) typedef struct _NemoScriptConfigWidget NemoScriptConfigWidget; typedef struct _NemoScriptConfigWidgetClass NemoScriptConfigWidgetClass; struct _NemoScriptConfigWidget { NemoConfigBaseWidget parent; GList *scripts; GList *dir_monitors; gulong bl_handler; }; struct _NemoScriptConfigWidgetClass { NemoConfigBaseWidgetClass parent_class; }; GType nemo_script_config_widget_get_type (void); GtkWidget *nemo_script_config_widget_new (void); G_END_DECLS #endif /* __NEMO_SCRIPT_CONFIG_WIDGET_H__ */ nemo-4.4.2/src/nemo-self-check-functions.c000066400000000000000000000022761357442400300203710ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Darin Adler */ /* nemo-self-check-functions.c: Wrapper for all self check functions * in Nemo proper. */ #include #if ! defined (NEMO_OMIT_SELF_CHECK) #include "nemo-self-check-functions.h" void nemo_run_self_checks(void) { NEMO_FOR_EACH_SELF_CHECK_FUNCTION (NEMO_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NEMO_OMIT_SELF_CHECK */ nemo-4.4.2/src/nemo-self-check-functions.h000066400000000000000000000032221357442400300203660ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Darin Adler */ /* nemo-self-check-functions.h: Wrapper and prototypes for all self * check functions in Nemo proper. */ void nemo_run_self_checks (void); /* Putting the prototypes for these self-check functions in each header file for the files they are defined in would make compiling the self-check framework take way too long (since one file would have to include everything). So we put the list of functions here instead. Instead of just putting prototypes here, we put this macro that can be used to do operations on the whole list of functions. */ #define NEMO_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ /* Add new self-check functions to the list above this line. */ /* Generate prototypes for all the functions. */ NEMO_FOR_EACH_SELF_CHECK_FUNCTION (NEMO_SELF_CHECK_FUNCTION_PROTOTYPE) nemo-4.4.2/src/nemo-statusbar.c000066400000000000000000000276561357442400300164000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-statusbar.c * * * 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 - Suite 500, * Boston, MA 02110-1335, USA. */ #include "nemo-statusbar.h" #include "nemo-actions.h" #include #include enum { LAST_SIGNAL }; enum { PROP_WINDOW = 1, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoStatusBar, nemo_status_bar, GTK_TYPE_BOX); static void nemo_status_bar_init (NemoStatusBar *bar) { bar->window = NULL; } static void nemo_status_bar_set_property (GObject *object, guint arg_id, const GValue *value, GParamSpec *pspec) { NemoStatusBar *self = NEMO_STATUS_BAR (object); switch (arg_id) { case PROP_WINDOW: self->window = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec); break; } } static void nemo_status_bar_get_property (GObject *object, guint arg_id, GValue *value, GParamSpec *pspec) { NemoStatusBar *self = NEMO_STATUS_BAR (object); switch (arg_id) { case PROP_WINDOW: g_value_set_object (value, self->window); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec); break; } } static void nemo_status_bar_dispose (GObject *object) { NemoStatusBar *bar = NEMO_STATUS_BAR (object); bar->window = NULL; G_OBJECT_CLASS (nemo_status_bar_parent_class)->dispose (object); } static void action_places_toggle_callback (GtkButton *button, NemoStatusBar *bar) { nemo_window_set_sidebar_id (NEMO_WINDOW (bar->window), NEMO_WINDOW_SIDEBAR_PLACES); nemo_status_bar_sync_button_states (bar); } static void action_treeview_toggle_callback (GtkButton *button, NemoStatusBar *bar) { nemo_window_set_sidebar_id (NEMO_WINDOW (bar->window), NEMO_WINDOW_SIDEBAR_TREE); nemo_status_bar_sync_button_states (bar); } static void action_show_sidebar_callback (GtkButton *button, NemoStatusBar *bar) { nemo_window_show_sidebar (bar->window); } static void action_hide_sidebar_callback (GtkButton *button, NemoStatusBar *bar) { nemo_window_hide_sidebar (bar->window); } static void sidebar_state_changed_cb (gpointer pointer, gboolean state, gpointer user_data) { nemo_status_bar_sync_button_states (NEMO_STATUS_BAR (user_data)); } static void sidebar_type_changed_cb (gpointer pointer, const gchar *sidebar_id, gpointer user_data) { nemo_status_bar_sync_button_states (NEMO_STATUS_BAR (user_data)); } static void on_slider_changed_cb (GtkWidget *zoom_slider, gpointer user_data) { NemoStatusBar *bar = NEMO_STATUS_BAR (user_data); gdouble val = gtk_range_get_value (GTK_RANGE (zoom_slider)); NemoWindowSlot *slot = nemo_window_get_active_slot (bar->window); if (!NEMO_IS_WINDOW_SLOT (slot)) return; NemoView *view = slot->content_view; if (!NEMO_IS_VIEW (view)) return; nemo_view_zoom_to_level (view, (int) val); } #define SLIDER_WIDTH 100 static void nemo_status_bar_constructed (GObject *object) { NemoStatusBar *bar = NEMO_STATUS_BAR (object); G_OBJECT_CLASS (nemo_status_bar_parent_class)->constructed (object); GtkWidget *statusbar = gtk_statusbar_new (); GtkStyleContext *context; bar->real_statusbar = statusbar; GtkIconSize size = gtk_icon_size_from_name (NEMO_STATUSBAR_ICON_SIZE_NAME); context = gtk_widget_get_style_context (GTK_WIDGET (bar)); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLBAR); gtk_container_set_border_width (GTK_CONTAINER (bar), 2); GtkWidget *button, *icon; button = gtk_toggle_button_new (); icon = gtk_image_new_from_icon_name ("sidebar-places-symbolic", size); gtk_button_set_image (GTK_BUTTON (button), icon); gtk_widget_set_tooltip_text (GTK_WIDGET (button), _("Show Places")); bar->places_button = button; gtk_box_pack_start (GTK_BOX (bar), button, FALSE, FALSE, 2); g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (action_places_toggle_callback), bar); button = gtk_toggle_button_new (); icon = gtk_image_new_from_icon_name ("sidebar-tree-symbolic", size); gtk_button_set_image (GTK_BUTTON (button), icon); gtk_widget_set_tooltip_text (GTK_WIDGET (button), _("Show Treeview")); bar->tree_button = button; gtk_box_pack_start (GTK_BOX (bar), button, FALSE, FALSE, 2); g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (action_treeview_toggle_callback), bar); GtkWidget *sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL); gtk_box_pack_start (GTK_BOX (bar), sep, FALSE, FALSE, 6); gtk_widget_show (sep); bar->separator = sep; button = gtk_button_new (); icon = gtk_image_new_from_icon_name ("sidebar-hide-symbolic", size); gtk_button_set_image (GTK_BUTTON (button), icon); gtk_widget_set_tooltip_text (GTK_WIDGET (button), _("Hide the Sidebar (F9)")); bar->hide_button = button; gtk_box_pack_start (GTK_BOX (bar), button, FALSE, FALSE, 2); g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (action_hide_sidebar_callback), bar); button = gtk_button_new (); icon = gtk_image_new_from_icon_name ("sidebar-show-symbolic", size); gtk_button_set_image (GTK_BUTTON (button), icon); gtk_widget_set_tooltip_text (GTK_WIDGET (button), _("Show the Sidebar (F9)")); bar->show_button = button; gtk_box_pack_start (GTK_BOX (bar), button, FALSE, FALSE, 2); g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (action_show_sidebar_callback), bar); gtk_box_pack_start (GTK_BOX (bar), statusbar, TRUE, TRUE, 10); gtk_widget_set_margin_top (GTK_WIDGET (statusbar), 0); gtk_widget_set_margin_bottom (GTK_WIDGET (statusbar), 0); GtkWidget *zoom_slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, (gdouble) NEMO_ZOOM_LEVEL_SMALLEST, (gdouble) NEMO_ZOOM_LEVEL_LARGEST, 1.0); gtk_widget_set_tooltip_text (GTK_WIDGET (zoom_slider), _("Adjust zoom level")); bar->zoom_slider = zoom_slider; gtk_box_pack_start (GTK_BOX (bar), zoom_slider, FALSE, FALSE, 2); gtk_widget_set_size_request (GTK_WIDGET (zoom_slider), SLIDER_WIDTH, 0); gtk_scale_set_draw_value (GTK_SCALE (zoom_slider), FALSE); gtk_range_set_increments (GTK_RANGE (zoom_slider), 1.0, 1.0); gtk_range_set_round_digits (GTK_RANGE (zoom_slider), 0); gtk_widget_show_all (GTK_WIDGET (bar)); g_signal_connect_object (NEMO_WINDOW (bar->window), "notify::show-sidebar", G_CALLBACK (sidebar_state_changed_cb), bar, G_CONNECT_AFTER); g_signal_connect_object (NEMO_WINDOW (bar->window), "notify::sidebar-view-id", G_CALLBACK (sidebar_type_changed_cb), bar, G_CONNECT_AFTER); g_signal_connect (GTK_RANGE (zoom_slider), "value-changed", G_CALLBACK (on_slider_changed_cb), bar); GtkWidget *cont = gtk_statusbar_get_message_area (GTK_STATUSBAR (statusbar)); GList *children = gtk_container_get_children (GTK_CONTAINER (cont)); gtk_box_set_child_packing (GTK_BOX (cont), GTK_WIDGET (children->data), TRUE, FALSE, 10, GTK_PACK_START); g_list_free (children); nemo_status_bar_sync_button_states (bar); } static void nemo_status_bar_class_init (NemoStatusBarClass *status_bar_class) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (status_bar_class); oclass->set_property = nemo_status_bar_set_property; oclass->get_property = nemo_status_bar_get_property; oclass->dispose = nemo_status_bar_dispose; oclass->constructed = nemo_status_bar_constructed; properties[PROP_WINDOW] = g_param_spec_object ("window", "The NemoWindow", "The parent NemoWindow", NEMO_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } GtkWidget * nemo_status_bar_new (NemoWindow *window) { return g_object_new (NEMO_TYPE_STATUS_BAR, "orientation", GTK_ORIENTATION_HORIZONTAL, "spacing", 0, "window", window, NULL); } GtkWidget * nemo_status_bar_get_real_statusbar (NemoStatusBar *bar) { return bar->real_statusbar; } void nemo_status_bar_sync_button_states (NemoStatusBar *bar) { const gchar *sidebar_id = nemo_window_get_sidebar_id (NEMO_WINDOW (bar->window)); gboolean sidebar_visible = nemo_window_get_show_sidebar (NEMO_WINDOW (bar->window)); if (sidebar_visible) { gtk_widget_show (bar->tree_button); gtk_widget_show (bar->places_button); gtk_widget_show (bar->separator); gtk_widget_show (bar->hide_button); gtk_widget_hide (bar->show_button); } else { gtk_widget_hide (bar->tree_button); gtk_widget_hide (bar->places_button); gtk_widget_hide (bar->hide_button); gtk_widget_hide (bar->separator); gtk_widget_show (bar->show_button); } g_signal_handlers_block_by_func (GTK_BUTTON (bar->tree_button), action_treeview_toggle_callback, bar); if (g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->tree_button), TRUE); } else { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->tree_button), FALSE); } g_signal_handlers_unblock_by_func (GTK_BUTTON (bar->tree_button), action_treeview_toggle_callback, bar); g_signal_handlers_block_by_func (GTK_BUTTON (bar->places_button), action_places_toggle_callback, bar); if (g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_PLACES) == 0) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->places_button), TRUE); } else { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->places_button), FALSE); } g_signal_handlers_unblock_by_func (GTK_BUTTON (bar->places_button), action_places_toggle_callback, bar); } void nemo_status_bar_sync_zoom_widgets (NemoStatusBar *bar) { NemoWindowSlot *slot = nemo_window_get_active_slot (bar->window); if (!NEMO_IS_WINDOW_SLOT (slot)) return; NemoView *view = slot->content_view; if (!NEMO_IS_VIEW (view)) return; NemoZoomLevel zoom_level = nemo_view_get_zoom_level (NEMO_VIEW (view)); g_signal_handlers_block_by_func (GTK_RANGE (bar->zoom_slider), on_slider_changed_cb, bar); gtk_range_set_value (GTK_RANGE (bar->zoom_slider), (double) zoom_level); g_signal_handlers_unblock_by_func (GTK_RANGE (bar->zoom_slider), on_slider_changed_cb, bar); } nemo-4.4.2/src/nemo-statusbar.h000066400000000000000000000046571357442400300164010ustar00rootroot00000000000000/* nemo-statusbar.h * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * */ #ifndef NEMO_STATUSBAR_H #define NEMO_STATUSBAR_H #include #include #include "nemo-window.h" #include "nemo-window-slot.h" #include "nemo-view.h" typedef struct _NemoStatusBar NemoStatusBar; typedef struct _NemoStatusBarClass NemoStatusBarClass; #define NEMO_TYPE_STATUS_BAR (nemo_status_bar_get_type ()) #define NEMO_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_STATUS_BAR, NemoStatusBar)) #define NEMO_STATUS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_STATUS_BAR, NemoStatusBarClass)) #define NEMO_IS_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_STATUS_BAR)) #define NEMO_IS_STATUS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_STATUS_BAR)) #define NEMO_STATUS_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_STATUS_BAR, NemoStatusBarClass)) #define NEMO_STATUSBAR_ICON_SIZE_NAME "statusbar-icon" #define NEMO_STATUSBAR_ICON_SIZE 11 struct _NemoStatusBar { GtkBox parent; NemoWindow *window; GtkWidget *real_statusbar; GtkWidget *zoom_slider; GtkWidget *tree_button; GtkWidget *places_button; GtkWidget *show_button; GtkWidget *hide_button; GtkWidget *separator; }; struct _NemoStatusBarClass { GtkBoxClass parent_class; }; GType nemo_status_bar_get_type (void) G_GNUC_CONST; GtkWidget *nemo_status_bar_new (NemoWindow *window); GtkWidget *nemo_status_bar_get_real_statusbar (NemoStatusBar *bar); void nemo_status_bar_sync_button_states (NemoStatusBar *bar); void nemo_status_bar_sync_zoom_widgets (NemoStatusBar *bar); #endif /* NEMO_STATUSBAR_H */ nemo-4.4.2/src/nemo-thumbnail-problem-bar.c000066400000000000000000000124331357442400300205360ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include "nemo-thumbnail-problem-bar.h" #include "nemo-application.h" #include "nemo-view.h" #include #define NEMO_THUMBNAIL_PROBLEM_BAR_GET_PRIVATE(o)\ (G_TYPE_INSTANCE_GET_PRIVATE ((o), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR, NemoThumbnailProblemBarPrivate)) enum { PROP_VIEW = 1, NUM_PROPERTIES }; enum { FIX_CACHE = 1, DISMISS }; struct NemoThumbnailProblemBarPrivate { NemoView *view; gulong selection_handler_id; }; G_DEFINE_TYPE (NemoThumbnailProblemBar, nemo_thumbnail_problem_bar, GTK_TYPE_INFO_BAR); static void thumbnail_problem_bar_response_cb (GtkInfoBar *infobar, gint response_id, gpointer user_data) { NemoThumbnailProblemBar *bar; bar = NEMO_THUMBNAIL_PROBLEM_BAR (infobar); switch (response_id) { case FIX_CACHE: g_spawn_command_line_sync ("sh -c \"pkexec nemo --fix-cache\"", NULL, NULL, NULL, NULL); nemo_application_check_thumbnail_cache (nemo_application_get_singleton ()); nemo_window_slot_queue_reload (nemo_view_get_nemo_window_slot (bar->priv->view), FALSE); nemo_window_slot_check_bad_cache_bar (nemo_view_get_nemo_window_slot (bar->priv->view)); break; case DISMISS: nemo_application_clear_cache_flag (nemo_application_get_singleton ()); nemo_application_ignore_cache_problem (nemo_application_get_singleton ()); gtk_widget_hide (GTK_WIDGET (infobar)); break; default: break; } } static void nemo_thumbnail_problem_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoThumbnailProblemBar *bar; bar = NEMO_THUMBNAIL_PROBLEM_BAR (object); switch (prop_id) { case PROP_VIEW: bar->priv->view = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_thumbnail_problem_bar_constructed (GObject *obj) { G_OBJECT_CLASS (nemo_thumbnail_problem_bar_parent_class)->constructed (obj); NemoThumbnailProblemBar *bar = NEMO_THUMBNAIL_PROBLEM_BAR (obj); GtkWidget *content_area, *action_area; G_GNUC_UNUSED GtkWidget *w; GtkWidget *label; content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar)); action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (bar)); gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL); label = gtk_label_new (_("A problem has been detected with your thumbnail cache. Fixing it will require administrative privileges.")); /* w is useless - this method creates the widget and adds/refs it to the info bar at the same time */ w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("Fix now"), FIX_CACHE); w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("Dismiss"), DISMISS); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (label), "nemo-cluebar-label"); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (content_area), label); g_signal_connect (bar, "response", G_CALLBACK (thumbnail_problem_bar_response_cb), bar); } static void nemo_thumbnail_problem_bar_class_init (NemoThumbnailProblemBarClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = nemo_thumbnail_problem_bar_set_property; object_class->constructed = nemo_thumbnail_problem_bar_constructed; g_object_class_install_property (object_class, PROP_VIEW, g_param_spec_object ("view", "view", "the NemoView", NEMO_TYPE_VIEW, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (klass, sizeof (NemoThumbnailProblemBarPrivate)); } static void nemo_thumbnail_problem_bar_init (NemoThumbnailProblemBar *bar) { bar->priv = NEMO_THUMBNAIL_PROBLEM_BAR_GET_PRIVATE (bar); } GtkWidget * nemo_thumbnail_problem_bar_new (NemoView *view) { return g_object_new (NEMO_TYPE_THUMBNAIL_PROBLEM_BAR, "view", view, NULL); } nemo-4.4.2/src/nemo-thumbnail-problem-bar.h000066400000000000000000000041511357442400300205410ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * 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 - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __NEMO_THUMBNAIL_PROBLEM_BAR_H #define __NEMO_THUMBNAIL_PROBLEM_BAR_H #include "nemo-view.h" #include G_BEGIN_DECLS #define NEMO_TYPE_THUMBNAIL_PROBLEM_BAR (nemo_thumbnail_problem_bar_get_type ()) #define NEMO_THUMBNAIL_PROBLEM_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR, NemoThumbnailProblemBar)) #define NEMO_THUMBNAIL_PROBLEM_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR, NemoThumbnailProblemBarClass)) #define NEMO_IS_THUMBNAIL_PROBLEM_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR)) #define NEMO_IS_THUMBNAIL_PROBLEM_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR)) #define NEMO_THUMBNAIL_PROBLEM_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_THUMBNAIL_PROBLEM_BAR, NemoThumbnailProblemBarClass)) typedef struct NemoThumbnailProblemBarPrivate NemoThumbnailProblemBarPrivate; typedef struct { GtkInfoBar parent; NemoThumbnailProblemBarPrivate *priv; } NemoThumbnailProblemBar; typedef struct { GtkInfoBarClass parent_class; } NemoThumbnailProblemBarClass; GType nemo_thumbnail_problem_bar_get_type (void) G_GNUC_CONST; GtkWidget *nemo_thumbnail_problem_bar_new (NemoView *view); G_END_DECLS #endif /* __NEMO_THUMBNAIL_PROBLEM_BAR_H */ nemo-4.4.2/src/nemo-toolbar.c000066400000000000000000000605011357442400300160140ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #include #include "nemo-toolbar.h" #include "nemo-location-bar.h" #include "nemo-pathbar.h" #include "nemo-window-private.h" #include "nemo-actions.h" #include #include #include struct _NemoToolbarPriv { GtkWidget *toolbar; GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkWidget *previous_button; GtkWidget *next_button; GtkWidget *up_button; GtkWidget *refresh_button; GtkWidget *home_button; GtkWidget *computer_button; GtkWidget *toggle_location_button; GtkWidget *open_terminal_button; GtkWidget *new_folder_button; GtkWidget *search_button; GtkWidget *icon_view_button; GtkWidget *list_view_button; GtkWidget *compact_view_button; GtkWidget *show_thumbnails_button; GtkToolItem *navigation_box; GtkToolItem *refresh_box; GtkToolItem *location_box; GtkToolItem *tools_box; GtkToolItem *view_box; GtkWidget *path_bar; GtkWidget *location_bar; GtkWidget *root_bar; GtkWidget *stack; gboolean show_main_bar; gboolean show_location_entry; gboolean show_root_bar; }; enum { PROP_ACTION_GROUP = 1, PROP_SHOW_LOCATION_ENTRY, PROP_SHOW_MAIN_BAR, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoToolbar, nemo_toolbar, GTK_TYPE_BOX); static void nemo_toolbar_update_root_state (NemoToolbar *self) { if (geteuid() == 0 && g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_ROOT_WARNING)) { if (self->priv->show_root_bar != TRUE) { self->priv->show_root_bar = TRUE; } } else { self->priv->show_root_bar = FALSE; } } static void toolbar_update_appearance (NemoToolbar *self) { GtkWidget *widgetitem; gboolean icon_toolbar; gboolean show_location_entry; nemo_toolbar_update_root_state (self); show_location_entry = self->priv->show_location_entry; gtk_widget_set_visible (GTK_WIDGET(self->priv->toolbar), self->priv->show_main_bar); if (show_location_entry) { gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), "location_bar"); } else { gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), "path_bar"); } gtk_widget_set_visible (self->priv->root_bar, self->priv->show_root_bar); /* Please refer to the element name, not the action name after the forward slash, otherwise the prefs will not work*/ widgetitem = self->priv->previous_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_PREVIOUS_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->next_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_NEXT_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->up_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_UP_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->refresh_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_RELOAD_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->home_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HOME_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->computer_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_COMPUTER_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->search_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_SEARCH_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->new_folder_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_NEW_FOLDER_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->open_terminal_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_OPEN_IN_TERMINAL_TOOLBAR); if (icon_toolbar == FALSE ) {gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->toggle_location_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_EDIT_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->icon_view_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_ICON_VIEW_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->list_view_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_LIST_VIEW_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->compact_view_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_COMPACT_VIEW_ICON_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} widgetitem = self->priv->show_thumbnails_button; icon_toolbar = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_SHOW_THUMBNAILS_TOOLBAR); if ( icon_toolbar == FALSE ) { gtk_widget_hide (widgetitem); } else {gtk_widget_show (GTK_WIDGET(widgetitem));} if (gtk_widget_get_visible(self->priv->previous_button) == FALSE && gtk_widget_get_visible(self->priv->next_button) == FALSE && gtk_widget_get_visible(self->priv->up_button) == FALSE) { gtk_widget_hide(GTK_WIDGET (self->priv->navigation_box)); } else { gtk_widget_show(GTK_WIDGET (self->priv->navigation_box)); } if (gtk_widget_get_visible(self->priv->home_button) == FALSE && gtk_widget_get_visible(self->priv->computer_button) == FALSE) { gtk_widget_hide(GTK_WIDGET (self->priv->location_box)); } else { gtk_widget_show(GTK_WIDGET (self->priv->location_box)); } if (gtk_widget_get_visible(self->priv->refresh_button) == FALSE) { gtk_widget_hide(GTK_WIDGET (self->priv->refresh_box)); } else { gtk_widget_show(GTK_WIDGET (self->priv->refresh_box)); } if (gtk_widget_get_visible(self->priv->search_button) == FALSE && gtk_widget_get_visible(self->priv->new_folder_button) == FALSE && gtk_widget_get_visible(self->priv->open_terminal_button) == FALSE && gtk_widget_get_visible(self->priv->toggle_location_button) == FALSE && gtk_widget_get_visible(self->priv->show_thumbnails_button) == FALSE) { gtk_widget_hide(GTK_WIDGET (self->priv->tools_box)); } else { gtk_widget_show(GTK_WIDGET (self->priv->tools_box)); } if (gtk_widget_get_visible(self->priv->icon_view_button) == FALSE && gtk_widget_get_visible(self->priv->list_view_button) == FALSE && gtk_widget_get_visible(self->priv->compact_view_button) == FALSE) { gtk_widget_hide(GTK_WIDGET (self->priv->view_box)); } else { gtk_widget_show(GTK_WIDGET (self->priv->view_box)); } } static void setup_root_info_bar (NemoToolbar *self) { GtkWidget *root_bar = gtk_info_bar_new (); gtk_info_bar_set_message_type (GTK_INFO_BAR (root_bar), GTK_MESSAGE_ERROR); GtkWidget *content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (root_bar)); GtkWidget *label = gtk_label_new (_("Elevated Privileges")); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (content_area), label); self->priv->root_bar = root_bar; gtk_box_pack_start (GTK_BOX (self), self->priv->root_bar, TRUE, TRUE, 0); } static GtkWidget * toolbar_create_toolbutton (NemoToolbar *self, gboolean create_toggle, const gchar *name) { GtkWidget *button; GtkWidget *image; GtkAction *action; if (create_toggle) { button = gtk_toggle_button_new (); } else { button = gtk_button_new (); } image = gtk_image_new (); gtk_button_set_image (GTK_BUTTON (button), image); action = gtk_action_group_get_action (self->priv->action_group, name); gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action); gtk_button_set_label (GTK_BUTTON (button), NULL); gtk_widget_set_tooltip_text (button, gtk_action_get_tooltip (action)); return button; } static void nemo_toolbar_constructed (GObject *obj) { NemoToolbar *self = NEMO_TOOLBAR (obj); GtkWidget *toolbar; GtkWidget *hbox; GtkToolItem *tool_box; GtkWidget *box; GtkStyleContext *context; G_OBJECT_CLASS (nemo_toolbar_parent_class)->constructed (obj); gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (self)), GTK_JUNCTION_BOTTOM); self->priv->show_location_entry = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_LOCATION_ENTRY); /* add the UI */ self->priv->ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (self->priv->ui_manager, self->priv->action_group, 0); toolbar = gtk_toolbar_new (); self->priv->toolbar = toolbar; gtk_box_pack_start (GTK_BOX (self), self->priv->toolbar, TRUE, TRUE, 0); context = gtk_widget_get_style_context (GTK_WIDGET(toolbar)); gtk_style_context_add_class (context, GTK_STYLE_CLASS_PRIMARY_TOOLBAR); /* Back/Forward/Up */ self->priv->navigation_box = gtk_tool_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); self->priv->previous_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_BACK); gtk_container_add (GTK_CONTAINER (box), self->priv->previous_button); self->priv->next_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_FORWARD); gtk_container_add (GTK_CONTAINER (box), self->priv->next_button); self->priv->up_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_UP); gtk_container_add (GTK_CONTAINER (box), self->priv->up_button); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RAISED); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_LINKED); gtk_container_add (GTK_CONTAINER (self->priv->navigation_box), GTK_WIDGET (box)); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (self->priv->navigation_box)); gtk_widget_show_all (GTK_WIDGET (self->priv->navigation_box)); gtk_widget_set_margin_right (GTK_WIDGET (self->priv->navigation_box), 6); /* Refresh */ self->priv->refresh_box = gtk_tool_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); self->priv->refresh_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_RELOAD); gtk_container_add (GTK_CONTAINER (box), self->priv->refresh_button); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RAISED); gtk_container_add (GTK_CONTAINER (self->priv->refresh_box), GTK_WIDGET (box)); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (self->priv->refresh_box)); gtk_widget_show_all (GTK_WIDGET (self->priv->refresh_box)); gtk_widget_set_margin_right (GTK_WIDGET (self->priv->refresh_box), 6); /* Home/Computer */ self->priv->location_box = gtk_tool_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); self->priv->home_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_HOME); gtk_container_add (GTK_CONTAINER (box), self->priv->home_button); self->priv->computer_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_COMPUTER); gtk_container_add (GTK_CONTAINER (box), self->priv->computer_button); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RAISED); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_LINKED); gtk_container_add (GTK_CONTAINER (self->priv->location_box), GTK_WIDGET (box)); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (self->priv->location_box)); gtk_widget_show_all (GTK_WIDGET (self->priv->location_box)); gtk_widget_set_margin_right (GTK_WIDGET (self->priv->location_box), 6); /* Container to hold the location and pathbars */ self->priv->stack = gtk_stack_new(); gtk_stack_set_transition_type (GTK_STACK (self->priv->stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE); gtk_stack_set_transition_duration (GTK_STACK (self->priv->stack), 150); /* Regular Path Bar */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (self->priv->stack), TRUE, TRUE, 0); self->priv->path_bar = g_object_new (NEMO_TYPE_PATH_BAR, NULL); gtk_stack_add_named(GTK_STACK (self->priv->stack), GTK_WIDGET (self->priv->path_bar), "path_bar"); /* Entry-Like Location Bar */ self->priv->location_bar = nemo_location_bar_new (); gtk_stack_add_named(GTK_STACK (self->priv->stack), GTK_WIDGET (self->priv->location_bar), "location_bar"); gtk_widget_show_all (hbox); tool_box = gtk_tool_item_new (); gtk_tool_item_set_expand (tool_box, TRUE); gtk_container_add (GTK_CONTAINER (tool_box), hbox); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (tool_box)); gtk_widget_show (GTK_WIDGET (tool_box)); /* Search/Open in Terminal/New Folder/Toggle Location */ self->priv->tools_box = gtk_tool_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); self->priv->toggle_location_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_TOGGLE_LOCATION); gtk_container_add (GTK_CONTAINER (box), self->priv->toggle_location_button); self->priv->open_terminal_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_OPEN_IN_TERMINAL); gtk_container_add (GTK_CONTAINER (box), self->priv->open_terminal_button); self->priv->new_folder_button = toolbar_create_toolbutton (self, FALSE, NEMO_ACTION_NEW_FOLDER); gtk_container_add (GTK_CONTAINER (box), self->priv->new_folder_button); self->priv->search_button = toolbar_create_toolbutton (self, TRUE, NEMO_ACTION_SEARCH); gtk_container_add (GTK_CONTAINER (box), self->priv->search_button); self->priv->show_thumbnails_button = toolbar_create_toolbutton (self, TRUE, NEMO_ACTION_SHOW_THUMBNAILS); gtk_container_add (GTK_CONTAINER (box), self->priv->show_thumbnails_button); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RAISED); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_LINKED); gtk_container_add (GTK_CONTAINER (self->priv->tools_box), GTK_WIDGET (box)); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (self->priv->tools_box)); gtk_widget_show_all (GTK_WIDGET (self->priv->tools_box)); gtk_widget_set_margin_left (GTK_WIDGET (self->priv->tools_box), 6); setup_root_info_bar (self); /* View Select */ self->priv->view_box = gtk_tool_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); self->priv->icon_view_button = toolbar_create_toolbutton (self, TRUE, NEMO_ACTION_ICON_VIEW); gtk_container_add (GTK_CONTAINER (box), self->priv->icon_view_button); self->priv->list_view_button = toolbar_create_toolbutton (self, TRUE, NEMO_ACTION_LIST_VIEW); gtk_container_add (GTK_CONTAINER (box), self->priv->list_view_button); self->priv->compact_view_button = toolbar_create_toolbutton (self, TRUE, NEMO_ACTION_COMPACT_VIEW); gtk_container_add (GTK_CONTAINER (box), self->priv->compact_view_button); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_RAISED); gtk_style_context_add_class (gtk_widget_get_style_context (box), GTK_STYLE_CLASS_LINKED); gtk_container_add (GTK_CONTAINER (self->priv->view_box), GTK_WIDGET (box)); gtk_container_add (GTK_CONTAINER (self->priv->toolbar), GTK_WIDGET (self->priv->view_box)); gtk_widget_show_all (GTK_WIDGET (self->priv->view_box)); gtk_widget_set_margin_left (GTK_WIDGET (self->priv->view_box), 6); /* nemo patch */ g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_PREVIOUS_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_NEXT_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_UP_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_EDIT_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_RELOAD_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_HOME_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_COMPUTER_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_SEARCH_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_NEW_FOLDER_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_OPEN_IN_TERMINAL_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_ICON_VIEW_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_LIST_VIEW_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_COMPACT_VIEW_ICON_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_SHOW_THUMBNAILS_TOOLBAR, G_CALLBACK (toolbar_update_appearance), self); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, G_CALLBACK (toolbar_update_appearance), self); toolbar_update_appearance (self); } static void nemo_toolbar_init (NemoToolbar *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NEMO_TYPE_TOOLBAR, NemoToolbarPriv); self->priv->show_main_bar = TRUE; } static void nemo_toolbar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { NemoToolbar *self = NEMO_TOOLBAR (object); switch (property_id) { case PROP_SHOW_LOCATION_ENTRY: g_value_set_boolean (value, self->priv->show_location_entry); break; case PROP_SHOW_MAIN_BAR: g_value_set_boolean (value, self->priv->show_main_bar); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_toolbar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { NemoToolbar *self = NEMO_TOOLBAR (object); switch (property_id) { case PROP_ACTION_GROUP: self->priv->action_group = g_value_dup_object (value); break; case PROP_SHOW_LOCATION_ENTRY: nemo_toolbar_set_show_location_entry (self, g_value_get_boolean (value)); break; case PROP_SHOW_MAIN_BAR: nemo_toolbar_set_show_main_bar (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void nemo_toolbar_dispose (GObject *obj) { NemoToolbar *self = NEMO_TOOLBAR (obj); g_clear_object (&self->priv->action_group); g_signal_handlers_disconnect_by_func (nemo_preferences, toolbar_update_appearance, self); G_OBJECT_CLASS (nemo_toolbar_parent_class)->dispose (obj); } static void nemo_toolbar_class_init (NemoToolbarClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->get_property = nemo_toolbar_get_property; oclass->set_property = nemo_toolbar_set_property; oclass->constructed = nemo_toolbar_constructed; oclass->dispose = nemo_toolbar_dispose; properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", "The action group", "The action group to get actions from", GTK_TYPE_ACTION_GROUP, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_SHOW_LOCATION_ENTRY] = g_param_spec_boolean ("show-location-entry", "Whether to show the location entry", "Whether to show the location entry instead of the pathbar", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_SHOW_MAIN_BAR] = g_param_spec_boolean ("show-main-bar", "Whether to show the main bar", "Whether to show the main toolbar", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_type_class_add_private (klass, sizeof (NemoToolbarClass)); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } GtkWidget * nemo_toolbar_new (GtkActionGroup *action_group) { return g_object_new (NEMO_TYPE_TOOLBAR, "action-group", action_group, "orientation", GTK_ORIENTATION_VERTICAL, NULL); } GtkWidget * nemo_toolbar_get_path_bar (NemoToolbar *self) { return self->priv->path_bar; } GtkWidget * nemo_toolbar_get_location_bar (NemoToolbar *self) { return self->priv->location_bar; } gboolean nemo_toolbar_get_show_location_entry (NemoToolbar *self) { return self->priv->show_location_entry; } void nemo_toolbar_set_show_main_bar (NemoToolbar *self, gboolean show_main_bar) { if (show_main_bar != self->priv->show_main_bar) { self->priv->show_main_bar = show_main_bar; toolbar_update_appearance (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_MAIN_BAR]); } } void nemo_toolbar_set_show_location_entry (NemoToolbar *self, gboolean show_location_entry) { if (show_location_entry != self->priv->show_location_entry) { self->priv->show_location_entry = show_location_entry; toolbar_update_appearance (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_LOCATION_ENTRY]); } } nemo-4.4.2/src/nemo-toolbar.h000066400000000000000000000045421357442400300160240ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2011, Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Cosimo Cecchi * */ #ifndef __NEMO_TOOLBAR_H__ #define __NEMO_TOOLBAR_H__ #include #define NEMO_TYPE_TOOLBAR nemo_toolbar_get_type() #define NEMO_TOOLBAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_TOOLBAR, NemoToolbar)) #define NEMO_TOOLBAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_TOOLBAR, NemoToolbarClass)) #define NEMO_IS_TOOLBAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_TOOLBAR)) #define NEMO_IS_TOOLBAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_TOOLBAR)) #define NEMO_TOOLBAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_TOOLBAR, NemoToolbarClass)) typedef struct _NemoToolbar NemoToolbar; typedef struct _NemoToolbarPriv NemoToolbarPriv; typedef struct _NemoToolbarClass NemoToolbarClass; typedef enum { NEMO_TOOLBAR_MODE_PATH_BAR, NEMO_TOOLBAR_MODE_LOCATION_BAR, } NemoToolbarMode; struct _NemoToolbar { GtkBox parent; /* private */ NemoToolbarPriv *priv; }; struct _NemoToolbarClass { GtkBoxClass parent_class; }; GType nemo_toolbar_get_type (void); GtkWidget *nemo_toolbar_new (GtkActionGroup *action_group); gboolean nemo_toolbar_get_show_location_entry (NemoToolbar *self); GtkWidget *nemo_toolbar_get_path_bar (NemoToolbar *self); GtkWidget *nemo_toolbar_get_location_bar (NemoToolbar *self); void nemo_toolbar_set_show_main_bar (NemoToolbar *self, gboolean show_main_bar); void nemo_toolbar_set_show_location_entry (NemoToolbar *self, gboolean show_location_entry); #endif /* __NEMO_TOOLBAR_H__ */ nemo-4.4.2/src/nemo-trash-bar.c000066400000000000000000000146421357442400300162420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006 Paolo Borelli * * 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 - Suite 500, Boston, MA 02110-1335, USA. * * Authors: Paolo Borelli * */ #include "config.h" #include #include #include "nemo-trash-bar.h" #include "nemo-view.h" #include #include #include #include #define NEMO_TRASH_BAR_GET_PRIVATE(o)\ (G_TYPE_INSTANCE_GET_PRIVATE ((o), NEMO_TYPE_TRASH_BAR, NemoTrashBarPrivate)) enum { PROP_VIEW = 1, NUM_PROPERTIES }; enum { TRASH_BAR_RESPONSE_EMPTY = 1, TRASH_BAR_RESPONSE_RESTORE }; struct NemoTrashBarPrivate { NemoView *view; gulong selection_handler_id; }; G_DEFINE_TYPE (NemoTrashBar, nemo_trash_bar, GTK_TYPE_INFO_BAR); static void selection_changed_cb (NemoView *view, NemoTrashBar *bar) { int count; gchar *uri; uri = nemo_view_get_uri (view); count = nemo_view_get_selection_count (view); /* You can't currently restore individual files that aren't in the trash:/// root, * so make the button insensitive if that's the case. We should allow it (along with * deleting individual files permanently) but it's not trivial. */ gtk_info_bar_set_response_sensitive (GTK_INFO_BAR (bar), TRASH_BAR_RESPONSE_RESTORE, (count > 0 && g_strcmp0 (uri, "trash:///") == 0)); g_free (uri); } static void disconnect_view (NemoTrashBar *bar) { if (bar->priv->selection_handler_id != 0) { g_signal_handler_disconnect (bar->priv->view, bar->priv->selection_handler_id); bar->priv->selection_handler_id = 0; } } static void connect_view_and_update_button (NemoTrashBar *bar) { bar->priv->selection_handler_id = g_signal_connect (bar->priv->view, "selection-changed", G_CALLBACK (selection_changed_cb), bar); g_signal_connect_object (bar->priv->view, "destroy", G_CALLBACK (disconnect_view), bar, G_CONNECT_SWAPPED); selection_changed_cb (bar->priv->view, bar); } static void nemo_trash_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoTrashBar *bar; bar = NEMO_TRASH_BAR (object); switch (prop_id) { case PROP_VIEW: bar->priv->view = g_value_get_object (value); connect_view_and_update_button (bar); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_trash_bar_dispose (GObject *obj) { NemoTrashBar *bar; bar = NEMO_TRASH_BAR (obj); disconnect_view (bar); G_OBJECT_CLASS (nemo_trash_bar_parent_class)->dispose (obj); } static void nemo_trash_bar_trash_state_changed (NemoTrashMonitor *trash_monitor, gboolean state, gpointer data) { NemoTrashBar *bar; bar = NEMO_TRASH_BAR (data); gtk_info_bar_set_response_sensitive (GTK_INFO_BAR (bar), TRASH_BAR_RESPONSE_EMPTY, !nemo_trash_monitor_is_empty ()); } static void nemo_trash_bar_class_init (NemoTrashBarClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = nemo_trash_bar_set_property; object_class->dispose = nemo_trash_bar_dispose; g_object_class_install_property (object_class, PROP_VIEW, g_param_spec_object ("view", "view", "the NemoView", NEMO_TYPE_VIEW, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (klass, sizeof (NemoTrashBarPrivate)); } static void trash_bar_response_cb (GtkInfoBar *infobar, gint response_id, gpointer user_data) { NemoTrashBar *bar; GtkWidget *window; GList *files; bar = NEMO_TRASH_BAR (infobar); window = gtk_widget_get_toplevel (GTK_WIDGET (bar)); switch (response_id) { case TRASH_BAR_RESPONSE_EMPTY: nemo_file_operations_empty_trash (window); break; case TRASH_BAR_RESPONSE_RESTORE: files = nemo_view_get_selection (bar->priv->view); nemo_restore_files_from_trash (files, GTK_WINDOW (window)); nemo_file_list_free (files); break; default: break; } } static void nemo_trash_bar_init (NemoTrashBar *bar) { GtkWidget *content_area, *action_area, *w; GtkWidget *label; bar->priv = NEMO_TRASH_BAR_GET_PRIVATE (bar); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar)); action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (bar)); gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL); label = gtk_label_new (_("Trash")); gtk_style_context_add_class (gtk_widget_get_style_context (label), "nemo-cluebar-label"); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (content_area), label); w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("Restore Selected Items"), TRASH_BAR_RESPONSE_RESTORE); gtk_widget_set_tooltip_text (w, _("Restore selected items to their original position")); w = gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("Empty _Trash"), TRASH_BAR_RESPONSE_EMPTY); gtk_widget_set_tooltip_text (w, _("Delete all items in the Trash")); g_signal_connect_object (nemo_trash_monitor_get (), "trash_state_changed", G_CALLBACK (nemo_trash_bar_trash_state_changed), bar, 0); nemo_trash_bar_trash_state_changed (nemo_trash_monitor_get (), FALSE, bar); g_signal_connect (bar, "response", G_CALLBACK (trash_bar_response_cb), bar); } GtkWidget * nemo_trash_bar_new (NemoView *view) { return g_object_new (NEMO_TYPE_TRASH_BAR, "view", view, NULL); } nemo-4.4.2/src/nemo-trash-bar.h000066400000000000000000000036711357442400300162470ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006 Paolo Borelli * * 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 - Suite 500, Boston, MA 02110-1335, USA. * * Authors: Paolo Borelli * */ #ifndef __NEMO_TRASH_BAR_H #define __NEMO_TRASH_BAR_H #include "nemo-view.h" #include G_BEGIN_DECLS #define NEMO_TYPE_TRASH_BAR (nemo_trash_bar_get_type ()) #define NEMO_TRASH_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_TRASH_BAR, NemoTrashBar)) #define NEMO_TRASH_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_TRASH_BAR, NemoTrashBarClass)) #define NEMO_IS_TRASH_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_TRASH_BAR)) #define NEMO_IS_TRASH_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_TRASH_BAR)) #define NEMO_TRASH_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_TRASH_BAR, NemoTrashBarClass)) typedef struct NemoTrashBarPrivate NemoTrashBarPrivate; typedef struct { GtkInfoBar parent; NemoTrashBarPrivate *priv; } NemoTrashBar; typedef struct { GtkInfoBarClass parent_class; } NemoTrashBarClass; GType nemo_trash_bar_get_type (void) G_GNUC_CONST; GtkWidget *nemo_trash_bar_new (NemoView *view); G_END_DECLS #endif /* __GS_TRASH_BAR_H */ nemo-4.4.2/src/nemo-tree-sidebar-model.c000066400000000000000000001321711357442400300200210ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright C) 2000, 2001 Eazel, Inc * Copyright (C) 2002 Anders Carlsson * Copyright (C) 2002 Bent Spoon Software * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Anders Carlsson * Darin Adler */ /* fm-tree-model.c - model for the tree view */ #include #include "nemo-tree-sidebar-model.h" #include #include #include #include #include #include #include #include #include enum { ROW_LOADED, GET_ICON_SCALE, LAST_SIGNAL }; static guint tree_model_signals[LAST_SIGNAL] = { 0 }; typedef gboolean (* FilePredicate) (NemoFile *); /* The user_data of the GtkTreeIter is the TreeNode pointer. * It's NULL for the dummy node. If it's NULL, then user_data2 * is the TreeNode pointer to the parent. */ typedef struct TreeNode TreeNode; typedef struct FMTreeModelRoot FMTreeModelRoot; struct TreeNode { /* part of this node for the file itself */ int ref_count; NemoFile *file; char *display_name; GIcon *icon; GMount *mount; GIcon *closed_icon; GIcon *open_icon; FMTreeModelRoot *root; TreeNode *parent; TreeNode *next; TreeNode *prev; /* part of the node used only for directories */ int dummy_child_ref_count; int all_children_ref_count; guint icon_scale; NemoDirectory *directory; guint done_loading_id; guint files_added_id; guint files_changed_id; TreeNode *first_child; /* misc. flags */ guint done_loading : 1; guint force_has_dummy : 1; guint inserted : 1; guint pinned : 1; }; struct FMTreeModelDetails { int stamp; TreeNode *root_node; guint monitoring_update_idle_id; gboolean show_hidden_files; gboolean show_only_directories; GList *highlighted_files; }; struct FMTreeModelRoot { FMTreeModel *model; /* separate hash table for each root node needed */ GHashTable *file_to_node_map; guint icon_scale; TreeNode *root_node; }; typedef struct { NemoDirectory *directory; FMTreeModel *model; } DoneLoadingParameters; static void fm_tree_model_tree_model_init (GtkTreeModelIface *iface); static void schedule_monitoring_update (FMTreeModel *model); static void destroy_node_without_reporting (FMTreeModel *model, TreeNode *node); static void report_node_contents_changed (FMTreeModel *model, TreeNode *node); G_DEFINE_TYPE_WITH_CODE (FMTreeModel, fm_tree_model, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, fm_tree_model_tree_model_init)); static GtkTreeModelFlags fm_tree_model_get_flags (GtkTreeModel *tree_model) { return GTK_TREE_MODEL_ITERS_PERSIST; } static gint fm_tree_model_get_icon_scale (GtkTreeModel *model) { gint retval = -1; g_signal_emit (model, tree_model_signals[GET_ICON_SCALE], 0, &retval); if (retval == -1) { retval = gdk_screen_get_monitor_scale_factor (gdk_screen_get_default (), 0); } return retval; } static void object_unref_if_not_NULL (gpointer object) { if (object == NULL) { return; } g_object_unref (object); } static FMTreeModelRoot * tree_model_root_new (FMTreeModel *model) { FMTreeModelRoot *root; root = g_new0 (FMTreeModelRoot, 1); root->model = model; root->file_to_node_map = g_hash_table_new (NULL, NULL); root->icon_scale = fm_tree_model_get_icon_scale (GTK_TREE_MODEL (model)); return root; } static TreeNode * tree_node_new (NemoFile *file, FMTreeModelRoot *root) { TreeNode *node; node = g_new0 (TreeNode, 1); node->file = nemo_file_ref (file); node->root = root; node->icon_scale = root->icon_scale; return node; } static void tree_node_unparent (FMTreeModel *model, TreeNode *node) { TreeNode *parent, *next, *prev; parent = node->parent; next = node->next; prev = node->prev; if (parent == NULL && node == model->details->root_node) { /* it's the first root node -> if there is a next then let it be the first root node */ model->details->root_node = next; } if (next != NULL) { next->prev = prev; } if (prev == NULL && parent != NULL) { g_assert (parent->first_child == node); parent->first_child = next; } else if (prev != NULL) { prev->next = next; } node->parent = NULL; node->next = NULL; node->prev = NULL; node->root = NULL; } static void tree_node_destroy (FMTreeModel *model, TreeNode *node) { g_assert (node->first_child == NULL); g_assert (node->ref_count == 0); tree_node_unparent (model, node); g_object_unref (node->file); g_free (node->display_name); object_unref_if_not_NULL (node->icon); object_unref_if_not_NULL (node->closed_icon); object_unref_if_not_NULL (node->open_icon); g_assert (node->done_loading_id == 0); g_assert (node->files_added_id == 0); g_assert (node->files_changed_id == 0); nemo_directory_unref (node->directory); g_free (node); } static void tree_node_parent (TreeNode *node, TreeNode *parent) { TreeNode *first_child; g_assert (parent != NULL); g_assert (node->parent == NULL); g_assert (node->prev == NULL); g_assert (node->next == NULL); first_child = parent->first_child; node->parent = parent; node->root = parent->root; node->next = first_child; if (first_child != NULL) { g_assert (first_child->prev == NULL); first_child->prev = node; } parent->first_child = node; } static GIcon * get_menu_icon_for_file (TreeNode *node, NemoFile *file, NemoFileIconFlags flags) { NemoFile *parent_file; GIcon *gicon, *emblem_icon, *emblemed_icon; GEmblem *emblem; int size; GList *emblem_icons, *l; size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); gicon = G_ICON (nemo_file_get_icon_pixbuf (file, size, TRUE, node->icon_scale, flags)); parent_file = NULL; if (node->parent && node->parent->file) { parent_file = node->parent->file; } emblem_icons = nemo_file_get_emblem_icons (node->file, parent_file); /* pick only the first emblem we can render for the tree view */ for (l = emblem_icons; l != NULL; l = l->next) { emblem_icon = l->data; emblem = g_emblem_new (emblem_icon); emblemed_icon = g_emblemed_icon_new (gicon, emblem); g_object_unref (gicon); g_object_unref (emblem); gicon = emblemed_icon; break; } g_list_free_full (emblem_icons, g_object_unref); return gicon; } static GIcon * tree_node_get_icon (TreeNode *node, NemoFileIconFlags flags) { if (node->parent == NULL) { return node->icon; } return get_menu_icon_for_file (node, node->file, flags); } static gboolean tree_node_update_icon (TreeNode *node, GIcon **icon_storage, NemoFileIconFlags flags) { GIcon *icon; if (*icon_storage == NULL) { return FALSE; } icon = tree_node_get_icon (node, flags); if (icon == *icon_storage) { g_object_unref (icon); return FALSE; } g_object_unref (*icon_storage); *icon_storage = icon; return TRUE; } static gboolean tree_node_update_closed_icon (TreeNode *node) { return tree_node_update_icon (node, &node->closed_icon, 0); } static gboolean tree_node_update_open_icon (TreeNode *node) { return tree_node_update_icon (node, &node->open_icon, NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER); } static gboolean tree_node_update_display_name (TreeNode *node) { char *display_name; if (node->display_name == NULL) { return FALSE; } /* don't update root node display names */ if (node->parent == NULL) { return FALSE; } display_name = nemo_file_get_display_name (node->file); if (strcmp (display_name, node->display_name) == 0) { g_free (display_name); return FALSE; } g_free (node->display_name); node->display_name = NULL; return TRUE; } static gboolean tree_node_update_pinning (TreeNode *node) { gboolean file_value; file_value = nemo_file_get_pinning (node->file); if (file_value != node->pinned) { node->pinned = file_value; return TRUE; } return FALSE; } static GIcon * tree_node_get_closed_icon (TreeNode *node) { if (node->closed_icon == NULL) { node->closed_icon = tree_node_get_icon (node, 0); } return node->closed_icon; } static GIcon * tree_node_get_open_icon (TreeNode *node) { if (node->open_icon == NULL) { node->open_icon = tree_node_get_icon (node, NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER); } return node->open_icon; } static const char * tree_node_get_display_name (TreeNode *node) { if (node->display_name == NULL) { node->display_name = nemo_file_get_display_name (node->file); } return node->display_name; } static gboolean tree_node_has_dummy_child (TreeNode *node) { return (node->directory != NULL && (!node->done_loading || node->first_child == NULL || node->force_has_dummy)) || /* Roots always have dummy nodes if directory isn't loaded yet */ (node->directory == NULL && node->parent == NULL); } static int tree_node_get_child_index (TreeNode *parent, TreeNode *child) { int i; TreeNode *node; if (child == NULL) { g_assert (tree_node_has_dummy_child (parent)); return 0; } i = tree_node_has_dummy_child (parent) ? 1 : 0; for (node = parent->first_child; node != NULL; node = node->next, i++) { if (child == node) { return i; } } g_assert_not_reached (); return 0; } static gboolean make_iter_invalid (GtkTreeIter *iter) { iter->stamp = 0; iter->user_data = NULL; iter->user_data2 = NULL; iter->user_data3 = NULL; return FALSE; } static gboolean make_iter_for_node (TreeNode *node, GtkTreeIter *iter, int stamp) { if (node == NULL) { return make_iter_invalid (iter); } iter->stamp = stamp; iter->user_data = node; iter->user_data2 = NULL; iter->user_data3 = NULL; return TRUE; } static gboolean make_iter_for_dummy_row (TreeNode *parent, GtkTreeIter *iter, int stamp) { g_assert (tree_node_has_dummy_child (parent)); g_assert (parent != NULL); iter->stamp = stamp; iter->user_data = NULL; iter->user_data2 = parent; iter->user_data3 = NULL; return TRUE; } static TreeNode * get_node_from_file (FMTreeModelRoot *root, NemoFile *file) { return g_hash_table_lookup (root->file_to_node_map, file); } static TreeNode * get_parent_node_from_file (FMTreeModelRoot *root, NemoFile *file) { NemoFile *parent_file; TreeNode *parent_node; parent_file = nemo_file_get_parent (file); parent_node = get_node_from_file (root, parent_file); nemo_file_unref (parent_file); return parent_node; } static TreeNode * create_node_for_file (FMTreeModelRoot *root, NemoFile *file) { TreeNode *node; g_assert (get_node_from_file (root, file) == NULL); node = tree_node_new (file, root); g_hash_table_insert (root->file_to_node_map, node->file, node); return node; } #ifdef LOG_REF_COUNTS static char * get_node_uri (GtkTreeIter *iter) { TreeNode *node, *parent; char *parent_uri, *node_uri; node = iter->user_data; if (node != NULL) { return nemo_file_get_uri (node->file); } parent = iter->user_data2; parent_uri = nemo_file_get_uri (parent->file); node_uri = g_strconcat (parent_uri, " -- DUMMY", NULL); g_free (parent_uri); return node_uri; } #endif static void decrement_ref_count (FMTreeModel *model, TreeNode *node, int count) { node->all_children_ref_count -= count; if (node->all_children_ref_count == 0) { schedule_monitoring_update (model); } } static void abandon_node_ref_count (FMTreeModel *model, TreeNode *node) { if (node->parent != NULL) { decrement_ref_count (model, node->parent, node->ref_count); #ifdef LOG_REF_COUNTS if (node->ref_count != 0) { char *uri; uri = nemo_file_get_uri (node->file); g_message ("abandoning %d ref of %s, count is now %d", node->ref_count, uri, node->parent->all_children_ref_count); g_free (uri); } #endif } node->ref_count = 0; } static void abandon_dummy_row_ref_count (FMTreeModel *model, TreeNode *node) { decrement_ref_count (model, node, node->dummy_child_ref_count); if (node->dummy_child_ref_count != 0) { #ifdef LOG_REF_COUNTS char *uri; uri = nemo_file_get_uri (node->file); g_message ("abandoning %d ref of %s -- DUMMY, count is now %d", node->dummy_child_ref_count, uri, node->all_children_ref_count); g_free (uri); #endif } node->dummy_child_ref_count = 0; } static void report_row_inserted (FMTreeModel *model, GtkTreeIter *iter) { GtkTreePath *path; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter); gtk_tree_path_free (path); } static void report_row_contents_changed (FMTreeModel *model, GtkTreeIter *iter) { GtkTreePath *path; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter); gtk_tree_path_free (path); } static void report_row_has_child_toggled (FMTreeModel *model, GtkTreeIter *iter) { GtkTreePath *path; path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, iter); gtk_tree_path_free (path); } static GtkTreePath * get_node_path (FMTreeModel *model, TreeNode *node) { GtkTreeIter iter; make_iter_for_node (node, &iter, model->details->stamp); return gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } static void report_dummy_row_inserted (FMTreeModel *model, TreeNode *parent) { GtkTreeIter iter; if (!parent->inserted) { return; } make_iter_for_dummy_row (parent, &iter, model->details->stamp); report_row_inserted (model, &iter); } static void report_dummy_row_deleted (FMTreeModel *model, TreeNode *parent) { GtkTreeIter iter; GtkTreePath *path; if (parent->inserted) { make_iter_for_node (parent, &iter, model->details->stamp); path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_tree_path_append_index (path, 0); gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); } abandon_dummy_row_ref_count (model, parent); } static void report_node_inserted (FMTreeModel *model, TreeNode *node) { GtkTreeIter iter; make_iter_for_node (node, &iter, model->details->stamp); report_row_inserted (model, &iter); node->inserted = TRUE; if (tree_node_has_dummy_child (node)) { report_dummy_row_inserted (model, node); } gboolean add_child = FALSE; if (node->directory != NULL) { guint count; if (nemo_file_get_directory_item_count (node->file, &count, NULL)) { add_child = count > 0 || node->parent == NULL; } else { add_child = TRUE; } } if (add_child) report_row_has_child_toggled (model, &iter); } static void report_node_contents_changed (FMTreeModel *model, TreeNode *node) { GtkTreeIter iter; if (!node->inserted) { return; } make_iter_for_node (node, &iter, model->details->stamp); report_row_contents_changed (model, &iter); } static void report_node_has_child_toggled (FMTreeModel *model, TreeNode *node) { GtkTreeIter iter; if (!node->inserted) { return; } make_iter_for_node (node, &iter, model->details->stamp); report_row_has_child_toggled (model, &iter); } static void report_dummy_row_contents_changed (FMTreeModel *model, TreeNode *parent) { GtkTreeIter iter; if (!parent->inserted) { return; } make_iter_for_dummy_row (parent, &iter, model->details->stamp); report_row_contents_changed (model, &iter); } static void stop_monitoring_directory (FMTreeModel *model, TreeNode *node) { if (node->done_loading_id == 0) { g_assert (node->files_added_id == 0); g_assert (node->files_changed_id == 0); return; } g_signal_handler_disconnect (node->directory, node->done_loading_id); g_signal_handler_disconnect (node->directory, node->files_added_id); g_signal_handler_disconnect (node->directory, node->files_changed_id); node->done_loading_id = 0; node->files_added_id = 0; node->files_changed_id = 0; nemo_directory_file_monitor_remove (node->directory, model); } static void destroy_children_without_reporting (FMTreeModel *model, TreeNode *parent) { while (parent->first_child != NULL) { destroy_node_without_reporting (model, parent->first_child); } } static void destroy_node_without_reporting (FMTreeModel *model, TreeNode *node) { abandon_node_ref_count (model, node); stop_monitoring_directory (model, node); node->inserted = FALSE; destroy_children_without_reporting (model, node); g_hash_table_remove (node->root->file_to_node_map, node->file); tree_node_destroy (model, node); } static void destroy_node (FMTreeModel *model, TreeNode *node) { TreeNode *parent; gboolean parent_had_dummy_child; GtkTreePath *path; parent = node->parent; parent_had_dummy_child = tree_node_has_dummy_child (parent); path = get_node_path (model, node); /* Report row_deleted before actually deleting */ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); destroy_node_without_reporting (model, node); if (tree_node_has_dummy_child (parent)) { if (!parent_had_dummy_child) { report_dummy_row_inserted (model, parent); } } else { g_assert (!parent_had_dummy_child); } } static void destroy_children (FMTreeModel *model, TreeNode *parent) { while (parent->first_child != NULL) { destroy_node (model, parent->first_child); } } static void destroy_children_by_function (FMTreeModel *model, TreeNode *parent, FilePredicate f) { TreeNode *child, *next; for (child = parent->first_child; child != NULL; child = next) { next = child->next; if (f (child->file)) { destroy_node (model, child); } else { destroy_children_by_function (model, child, f); } } } static void destroy_by_function (FMTreeModel *model, FilePredicate f) { TreeNode *node; for (node = model->details->root_node; node != NULL; node = node->next) { destroy_children_by_function (model, node, f); } } static gboolean update_node_without_reporting (FMTreeModel *model, TreeNode *node) { gboolean changed; changed = FALSE; if (node->directory == NULL && (nemo_file_is_directory (node->file) || node->parent == NULL)) { node->directory = nemo_directory_get_for_file (node->file); } else if (node->directory != NULL && !(nemo_file_is_directory (node->file) || node->parent == NULL)) { stop_monitoring_directory (model, node); destroy_children (model, node); nemo_directory_unref (node->directory); node->directory = NULL; } changed |= tree_node_update_display_name (node); changed |= tree_node_update_closed_icon (node); changed |= tree_node_update_open_icon (node); changed |= tree_node_update_pinning (node); return changed; } static void insert_node (FMTreeModel *model, TreeNode *parent, TreeNode *node) { gboolean parent_empty; parent_empty = parent->first_child == NULL; if (parent_empty) { /* Make sure the dummy lives as we insert the new row */ parent->force_has_dummy = TRUE; } tree_node_parent (node, parent); update_node_without_reporting (model, node); report_node_inserted (model, node); if (parent_empty) { parent->force_has_dummy = FALSE; if (!tree_node_has_dummy_child (parent)) { /* Temporarily set this back so that row_deleted is * sent before actually removing the dummy child */ parent->force_has_dummy = TRUE; report_dummy_row_deleted (model, parent); parent->force_has_dummy = FALSE; } } } static void reparent_node (FMTreeModel *model, TreeNode *node) { GtkTreePath *path; TreeNode *new_parent; new_parent = get_parent_node_from_file (node->root, node->file); if (new_parent == NULL || new_parent->directory == NULL) { destroy_node (model, node); return; } path = get_node_path (model, node); /* Report row_deleted before actually deleting */ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); abandon_node_ref_count (model, node); tree_node_unparent (model, node); insert_node (model, new_parent, node); } static gboolean should_show_file (FMTreeModel *model, NemoFile *file) { gboolean should; TreeNode *node; should = nemo_file_should_show (file, model->details->show_hidden_files, TRUE); if (should && model->details->show_only_directories &&! nemo_file_is_directory (file)) { should = FALSE; } if (should && nemo_file_is_gone (file)) { should = FALSE; } for (node = model->details->root_node; node != NULL; node = node->next) { if (!should && node != NULL && file == node->file) { should = TRUE; } } return should; } static void update_node (FMTreeModel *model, TreeNode *node) { gboolean had_dummy_child, has_dummy_child; gboolean had_directory, has_directory; gboolean changed; if (!should_show_file (model, node->file)) { destroy_node (model, node); return; } if (node->parent != NULL && node->parent->directory != NULL && !nemo_directory_contains_file (node->parent->directory, node->file)) { reparent_node (model, node); return; } had_dummy_child = tree_node_has_dummy_child (node); had_directory = node->directory != NULL; changed = update_node_without_reporting (model, node); has_dummy_child = tree_node_has_dummy_child (node); has_directory = node->directory != NULL; if (had_dummy_child != has_dummy_child) { if (has_dummy_child) { report_dummy_row_inserted (model, node); } else { /* Temporarily set this back so that row_deleted is * sent before actually removing the dummy child */ node->force_has_dummy = TRUE; report_dummy_row_deleted (model, node); node->force_has_dummy = FALSE; } } if (had_directory != has_directory) { report_node_has_child_toggled (model, node); } if (changed) { report_node_contents_changed (model, node); } } static void process_file_change (FMTreeModelRoot *root, NemoFile *file) { TreeNode *node, *parent; node = get_node_from_file (root, file); if (node != NULL) { update_node (root->model, node); return; } if (!should_show_file (root->model, file)) { return; } parent = get_parent_node_from_file (root, file); if (parent == NULL) { return; } insert_node (root->model, parent, create_node_for_file (root, file)); } static void files_changed_callback (NemoDirectory *directory, GList *changed_files, gpointer callback_data) { FMTreeModelRoot *root; GList *node; root = (FMTreeModelRoot *) (callback_data); for (node = changed_files; node != NULL; node = node->next) { process_file_change (root, NEMO_FILE (node->data)); } } static void set_done_loading (FMTreeModel *model, TreeNode *node, gboolean done_loading) { gboolean had_dummy; if (node == NULL || node->done_loading == done_loading) { return; } had_dummy = tree_node_has_dummy_child (node); node->done_loading = done_loading; if (tree_node_has_dummy_child (node)) { if (had_dummy) { report_dummy_row_contents_changed (model, node); } else { report_dummy_row_inserted (model, node); } } else { if (had_dummy) { /* Temporarily set this back so that row_deleted is * sent before actually removing the dummy child */ node->force_has_dummy = TRUE; report_dummy_row_deleted (model, node); node->force_has_dummy = FALSE; } else { g_assert_not_reached (); } } } static void done_loading_callback (NemoDirectory *directory, FMTreeModelRoot *root) { NemoFile *file; TreeNode *node; GtkTreeIter iter; file = nemo_directory_get_corresponding_file (directory); node = get_node_from_file (root, file); if (node == NULL) { /* This can happen for non-existing files as tree roots, * since the directory <-> file object relation gets * broken due to nemo_directory_remove_file() * getting called when i/o fails. */ return; } set_done_loading (root->model, node, TRUE); nemo_file_unref (file); make_iter_for_node (node, &iter, root->model->details->stamp); g_signal_emit (root->model, tree_model_signals[ROW_LOADED], 0, &iter); } static NemoFileAttributes get_tree_monitor_attributes (void) { NemoFileAttributes attributes; attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; return attributes; } static void start_monitoring_directory (FMTreeModel *model, TreeNode *node) { NemoDirectory *directory; NemoFileAttributes attributes; if (node->done_loading_id != 0) { return; } g_assert (node->files_added_id == 0); g_assert (node->files_changed_id == 0); directory = node->directory; node->done_loading_id = g_signal_connect (directory, "done_loading", G_CALLBACK (done_loading_callback), node->root); node->files_added_id = g_signal_connect (directory, "files_added", G_CALLBACK (files_changed_callback), node->root); node->files_changed_id = g_signal_connect (directory, "files_changed", G_CALLBACK (files_changed_callback), node->root); set_done_loading (model, node, nemo_directory_are_all_files_seen (directory)); attributes = get_tree_monitor_attributes (); nemo_directory_file_monitor_add (directory, model, model->details->show_hidden_files, attributes, files_changed_callback, node->root); } static int fm_tree_model_get_n_columns (GtkTreeModel *model) { return FM_TREE_MODEL_NUM_COLUMNS; } static GType fm_tree_model_get_column_type (GtkTreeModel *model, int index) { switch (index) { case FM_TREE_MODEL_DISPLAY_NAME_COLUMN: return G_TYPE_STRING; case FM_TREE_MODEL_CLOSED_ICON_COLUMN: return G_TYPE_ICON; case FM_TREE_MODEL_OPEN_ICON_COLUMN: return G_TYPE_ICON; case FM_TREE_MODEL_FONT_STYLE_COLUMN: return PANGO_TYPE_STYLE; case FM_TREE_MODEL_TEXT_WEIGHT_COLUMN: return G_TYPE_INT; default: g_assert_not_reached (); } return G_TYPE_INVALID; } static gboolean iter_is_valid (FMTreeModel *model, const GtkTreeIter *iter) { TreeNode *node, *parent; if (iter->stamp != model->details->stamp) { return FALSE; } node = iter->user_data; parent = iter->user_data2; if (node == NULL) { if (parent != NULL) { if (!NEMO_IS_FILE (parent->file)) { return FALSE; } if (!tree_node_has_dummy_child (parent)) { return FALSE; } } } else { if (!NEMO_IS_FILE (node->file)) { return FALSE; } if (parent != NULL) { return FALSE; } } if (iter->user_data3 != NULL) { return FALSE; } return TRUE; } static gboolean fm_tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) { int *indices; GtkTreeIter parent; int depth, i; indices = gtk_tree_path_get_indices (path); depth = gtk_tree_path_get_depth (path); if (! gtk_tree_model_iter_nth_child (model, iter, NULL, indices[0])) { return FALSE; } for (i = 1; i < depth; i++) { parent = *iter; if (! gtk_tree_model_iter_nth_child (model, iter, &parent, indices[i])) { return FALSE; } } return TRUE; } static GtkTreePath * fm_tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter) { FMTreeModel *tree_model; TreeNode *node, *parent, *cnode; GtkTreePath *path; GtkTreeIter parent_iter; int i; g_return_val_if_fail (FM_IS_TREE_MODEL (model), NULL); tree_model = FM_TREE_MODEL (model); g_return_val_if_fail (iter_is_valid (tree_model, iter), NULL); node = iter->user_data; if (node == NULL) { parent = iter->user_data2; if (parent == NULL) { return gtk_tree_path_new (); } } else { parent = node->parent; if (parent == NULL) { i = 0; for (cnode = tree_model->details->root_node; cnode != node; cnode = cnode->next) { i++; } path = gtk_tree_path_new (); gtk_tree_path_append_index (path, i); return path; } } parent_iter.stamp = iter->stamp; parent_iter.user_data = parent; parent_iter.user_data2 = NULL; parent_iter.user_data3 = NULL; path = fm_tree_model_get_path (model, &parent_iter); gtk_tree_path_append_index (path, tree_node_get_child_index (parent, node)); return path; } static void fm_tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter, int column, GValue *value) { TreeNode *node, *parent; g_return_if_fail (FM_IS_TREE_MODEL (model)); g_return_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter)); node = iter->user_data; switch (column) { case FM_TREE_MODEL_DISPLAY_NAME_COLUMN: g_value_init (value, G_TYPE_STRING); if (node == NULL) { parent = iter->user_data2; g_value_set_static_string (value, parent->done_loading ? _("(Empty)") : _("Loading...")); } else { g_value_set_string (value, tree_node_get_display_name (node)); } break; case FM_TREE_MODEL_CLOSED_ICON_COLUMN: g_value_init (value, G_TYPE_ICON); g_value_set_object (value, node == NULL ? NULL : tree_node_get_closed_icon (node)); break; case FM_TREE_MODEL_OPEN_ICON_COLUMN: g_value_init (value, G_TYPE_ICON); g_value_set_object (value, node == NULL ? NULL : tree_node_get_open_icon (node)); break; case FM_TREE_MODEL_FONT_STYLE_COLUMN: g_value_init (value, PANGO_TYPE_STYLE); if (node == NULL) { g_value_set_enum (value, PANGO_STYLE_ITALIC); } else { g_value_set_enum (value, PANGO_STYLE_NORMAL); } break; case FM_TREE_MODEL_TEXT_WEIGHT_COLUMN: g_value_init (value, G_TYPE_INT); if (node != NULL) { g_value_set_int (value, node->pinned ? PINNED_TEXT_WEIGHT : UNPINNED_TEXT_WEIGHT); } else { g_value_set_int (value, UNPINNED_TEXT_WEIGHT); } break; default: g_assert_not_reached (); } } static gboolean fm_tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter) { TreeNode *node, *parent, *next; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter), FALSE); node = iter->user_data; if (node == NULL) { parent = iter->user_data2; next = parent->first_child; } else { next = node->next; } return make_iter_for_node (next, iter, iter->stamp); } static gboolean fm_tree_model_iter_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent_iter) { TreeNode *parent; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (iter_is_valid (FM_TREE_MODEL (model), parent_iter), FALSE); parent = parent_iter->user_data; if (parent == NULL) { return make_iter_invalid (iter); } if (tree_node_has_dummy_child (parent)) { return make_iter_for_dummy_row (parent, iter, parent_iter->stamp); } return make_iter_for_node (parent->first_child, iter, parent_iter->stamp); } static gboolean fm_tree_model_iter_parent (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *child_iter) { TreeNode *child, *parent; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (iter_is_valid (FM_TREE_MODEL (model), child_iter), FALSE); child = child_iter->user_data; if (child == NULL) { parent = child_iter->user_data2; } else { parent = child->parent; } return make_iter_for_node (parent, iter, child_iter->stamp); } static gboolean fm_tree_model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter) { gboolean has_child; TreeNode *node; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter), FALSE); node = iter->user_data; has_child = node != NULL && (node->directory != NULL || node->parent == NULL); #if 0 g_warning ("Node '%s' %s", node && node->file ? nemo_file_get_uri (node->file) : "no name", has_child ? "has child" : "no child"); #endif return has_child; } static int fm_tree_model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter) { TreeNode *parent, *node; int n; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (iter == NULL || iter_is_valid (FM_TREE_MODEL (model), iter), FALSE); if (iter == NULL) { return 1; } parent = iter->user_data; if (parent == NULL) { return 0; } n = tree_node_has_dummy_child (parent) ? 1 : 0; for (node = parent->first_child; node != NULL; node = node->next) { n++; } return n; } static gboolean fm_tree_model_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent_iter, int n) { FMTreeModel *tree_model; TreeNode *parent, *node; int i; g_return_val_if_fail (FM_IS_TREE_MODEL (model), FALSE); g_return_val_if_fail (parent_iter == NULL || iter_is_valid (FM_TREE_MODEL (model), parent_iter), FALSE); tree_model = FM_TREE_MODEL (model); if (parent_iter == NULL) { node = tree_model->details->root_node; for (i = 0; i < n && node != NULL; i++, node = node->next); return make_iter_for_node (node, iter, tree_model->details->stamp); } parent = parent_iter->user_data; if (parent == NULL) { return make_iter_invalid (iter); } i = tree_node_has_dummy_child (parent) ? 1 : 0; if (n == 0 && i == 1) { return make_iter_for_dummy_row (parent, iter, parent_iter->stamp); } for (node = parent->first_child; i != n; i++, node = node->next) { if (node == NULL) { return make_iter_invalid (iter); } } return make_iter_for_node (node, iter, parent_iter->stamp); } static void update_monitoring (FMTreeModel *model, TreeNode *node) { TreeNode *child; if (node->all_children_ref_count == 0) { stop_monitoring_directory (model, node); destroy_children (model, node); } else { for (child = node->first_child; child != NULL; child = child->next) { update_monitoring (model, child); } start_monitoring_directory (model, node); } } static gboolean update_monitoring_idle_callback (gpointer callback_data) { FMTreeModel *model; TreeNode *node; model = FM_TREE_MODEL (callback_data); model->details->monitoring_update_idle_id = 0; for (node = model->details->root_node; node != NULL; node = node->next) { update_monitoring (model, node); } return FALSE; } static void schedule_monitoring_update (FMTreeModel *model) { if (model->details->monitoring_update_idle_id == 0) { model->details->monitoring_update_idle_id = g_idle_add (update_monitoring_idle_callback, model); } } static void stop_monitoring_directory_and_children (FMTreeModel *model, TreeNode *node) { TreeNode *child; stop_monitoring_directory (model, node); for (child = node->first_child; child != NULL; child = child->next) { stop_monitoring_directory_and_children (model, child); } } static void stop_monitoring (FMTreeModel *model) { TreeNode *node; for (node = model->details->root_node; node != NULL; node = node->next) { stop_monitoring_directory_and_children (model, node); } } static void fm_tree_model_ref_node (GtkTreeModel *model, GtkTreeIter *iter) { TreeNode *node, *parent; #ifdef LOG_REF_COUNTS char *uri; #endif g_return_if_fail (FM_IS_TREE_MODEL (model)); g_return_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter)); node = iter->user_data; if (node == NULL) { parent = iter->user_data2; g_assert (parent->dummy_child_ref_count >= 0); ++parent->dummy_child_ref_count; } else { parent = node->parent; g_assert (node->ref_count >= 0); ++node->ref_count; } if (parent != NULL) { g_assert (parent->all_children_ref_count >= 0); if (++parent->all_children_ref_count == 1) { if (parent->first_child == NULL) { parent->done_loading = FALSE; } schedule_monitoring_update (FM_TREE_MODEL (model)); } #ifdef LOG_REF_COUNTS uri = get_node_uri (iter); g_message ("ref of %s, count is now %d", uri, parent->all_children_ref_count); g_free (uri); #endif } } static void fm_tree_model_unref_node (GtkTreeModel *model, GtkTreeIter *iter) { TreeNode *node, *parent; #ifdef LOG_REF_COUNTS char *uri; #endif g_return_if_fail (FM_IS_TREE_MODEL (model)); g_return_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter)); node = iter->user_data; if (node == NULL) { parent = iter->user_data2; g_assert (parent->dummy_child_ref_count > 0); --parent->dummy_child_ref_count; } else { parent = node->parent; g_assert (node->ref_count > 0); --node->ref_count; } if (parent != NULL) { g_assert (parent->all_children_ref_count > 0); #ifdef LOG_REF_COUNTS uri = get_node_uri (iter); g_message ("unref of %s, count is now %d", uri, parent->all_children_ref_count - 1); g_free (uri); #endif if (--parent->all_children_ref_count == 0) { schedule_monitoring_update (FM_TREE_MODEL (model)); } } } void fm_tree_model_add_root_uri (FMTreeModel *model, const char *root_uri, const char *display_name, GIcon *icon, GMount *mount) { NemoFile *file; TreeNode *node, *cnode; FMTreeModelRoot *newroot; file = nemo_file_get_by_uri (root_uri); newroot = tree_model_root_new (model); node = create_node_for_file (newroot, file); node->display_name = g_strdup (display_name); node->icon = g_object_ref (icon); if (mount) { node->mount = g_object_ref (mount); } newroot->root_node = node; node->parent = NULL; if (model->details->root_node == NULL) { model->details->root_node = node; } else { /* append it */ for (cnode = model->details->root_node; cnode->next != NULL; cnode = cnode->next); cnode->next = node; node->prev = cnode; } nemo_file_unref (file); update_node_without_reporting (model, node); report_node_inserted (model, node); } GMount * fm_tree_model_get_mount_for_root_node_file (FMTreeModel *model, NemoFile *file) { TreeNode *node; for (node = model->details->root_node; node != NULL; node = node->next) { if (file == node->file) { break; } } if (node) { return node->mount; } return NULL; } void fm_tree_model_remove_root_uri (FMTreeModel *model, const char *uri) { TreeNode *node; GtkTreePath *path; FMTreeModelRoot *root; NemoFile *file; file = nemo_file_get_by_uri (uri); for (node = model->details->root_node; node != NULL; node = node->next) { if (file == node->file) { break; } } nemo_file_unref (file); if (node) { /* remove the node */ if (node->mount) { g_object_unref (node->mount); node->mount = NULL; } nemo_file_monitor_remove (node->file, model); path = get_node_path (model, node); /* Report row_deleted before actually deleting */ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); gtk_tree_path_free (path); if (node->prev) { node->prev->next = node->next; } if (node->next) { node->next->prev = node->prev; } if (node == model->details->root_node) { model->details->root_node = node->next; } /* destroy the root identifier */ root = node->root; destroy_node_without_reporting (model, node); g_hash_table_destroy (root->file_to_node_map); g_free (root); } } FMTreeModel * fm_tree_model_new (void) { FMTreeModel *model; model = g_object_new (FM_TYPE_TREE_MODEL, NULL); return model; } void fm_tree_model_set_show_hidden_files (FMTreeModel *model, gboolean show_hidden_files) { g_return_if_fail (FM_IS_TREE_MODEL (model)); g_return_if_fail (show_hidden_files == FALSE || show_hidden_files == TRUE); show_hidden_files = show_hidden_files != FALSE; if (model->details->show_hidden_files == show_hidden_files) { return; } model->details->show_hidden_files = show_hidden_files; stop_monitoring (model); if (!show_hidden_files) { destroy_by_function (model, nemo_file_is_hidden_file); } schedule_monitoring_update (model); } static gboolean file_is_not_directory (NemoFile *file) { return !nemo_file_is_directory (file); } void fm_tree_model_set_show_only_directories (FMTreeModel *model, gboolean show_only_directories) { g_return_if_fail (FM_IS_TREE_MODEL (model)); g_return_if_fail (show_only_directories == FALSE || show_only_directories == TRUE); show_only_directories = show_only_directories != FALSE; if (model->details->show_only_directories == show_only_directories) { return; } model->details->show_only_directories = show_only_directories; stop_monitoring (model); if (show_only_directories) { destroy_by_function (model, file_is_not_directory); } schedule_monitoring_update (model); } NemoFile * fm_tree_model_iter_get_file (FMTreeModel *model, GtkTreeIter *iter) { TreeNode *node; g_return_val_if_fail (FM_IS_TREE_MODEL (model), NULL); g_return_val_if_fail (iter_is_valid (FM_TREE_MODEL (model), iter), NULL); node = iter->user_data; return node == NULL ? NULL : nemo_file_ref (node->file); } /* This is used to work around some sort order stability problems with gtktreemodelsort */ int fm_tree_model_iter_compare_roots (FMTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b) { TreeNode *a, *b, *n; g_return_val_if_fail (FM_IS_TREE_MODEL (model), 0); g_return_val_if_fail (iter_is_valid (model, iter_a), 0); g_return_val_if_fail (iter_is_valid (model, iter_b), 0); a = iter_a->user_data; b = iter_b->user_data; g_assert (a != NULL && a->parent == NULL); g_assert (b != NULL && b->parent == NULL); if (a == b) { return 0; } for (n = model->details->root_node; n != NULL; n = n->next) { if (n == a) { return -1; } if (n == b) { return 1; } } g_assert_not_reached (); } gboolean fm_tree_model_iter_is_root (FMTreeModel *model, GtkTreeIter *iter) { TreeNode *node; g_return_val_if_fail (FM_IS_TREE_MODEL (model), 0); g_return_val_if_fail (iter_is_valid (model, iter), 0); node = iter->user_data; if (node == NULL) { return FALSE; } else { return (node->parent == NULL); } } gboolean fm_tree_model_file_get_iter (FMTreeModel *model, GtkTreeIter *iter, NemoFile *file, GtkTreeIter *current_iter) { TreeNode *node, *root_node; if (current_iter != NULL && current_iter->user_data != NULL) { node = get_node_from_file (((TreeNode *) current_iter->user_data)->root, file); return make_iter_for_node (node, iter, model->details->stamp); } for (root_node = model->details->root_node; root_node != NULL; root_node = root_node->next) { node = get_node_from_file (root_node->root, file); if (node != NULL) { return make_iter_for_node (node, iter, model->details->stamp); } } return FALSE; } static void do_update_node (NemoFile *file, FMTreeModel *model) { TreeNode *root, *node = NULL; for (root = model->details->root_node; root != NULL; root = root->next) { node = get_node_from_file (root->root, file); if (node != NULL) { break; } } if (node == NULL) { return; } update_node (model, node); } void fm_tree_model_set_highlight_for_files (FMTreeModel *model, GList *files) { GList *old_files; if (model->details->highlighted_files != NULL) { old_files = model->details->highlighted_files; model->details->highlighted_files = NULL; g_list_foreach (old_files, (GFunc) do_update_node, model); nemo_file_list_free (old_files); } if (files != NULL) { model->details->highlighted_files = nemo_file_list_copy (files); g_list_foreach (model->details->highlighted_files, (GFunc) do_update_node, model); } } static void fm_tree_model_init (FMTreeModel *model) { model->details = g_new0 (FMTreeModelDetails, 1); do { model->details->stamp = g_random_int (); } while (model->details->stamp == 0); } static void fm_tree_model_finalize (GObject *object) { FMTreeModel *model; TreeNode *root_node, *next_root; FMTreeModelRoot *root; model = FM_TREE_MODEL (object); for (root_node = model->details->root_node; root_node != NULL; root_node = next_root) { next_root = root_node->next; root = root_node->root; destroy_node_without_reporting (model, root_node); g_hash_table_destroy (root->file_to_node_map); g_free (root); } if (model->details->monitoring_update_idle_id != 0) { g_source_remove (model->details->monitoring_update_idle_id); } if (model->details->highlighted_files != NULL) { nemo_file_list_free (model->details->highlighted_files); } g_free (model->details); G_OBJECT_CLASS (fm_tree_model_parent_class)->finalize (object); } static void fm_tree_model_class_init (FMTreeModelClass *class) { G_OBJECT_CLASS (class)->finalize = fm_tree_model_finalize; tree_model_signals[ROW_LOADED] = g_signal_new ("row_loaded", FM_TYPE_TREE_MODEL, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FMTreeModelClass, row_loaded), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); tree_model_signals[GET_ICON_SCALE] = g_signal_new ("get-icon-scale", FM_TYPE_TREE_MODEL, G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_INT, 0); } static void fm_tree_model_tree_model_init (GtkTreeModelIface *iface) { iface->get_flags = fm_tree_model_get_flags; iface->get_n_columns = fm_tree_model_get_n_columns; iface->get_column_type = fm_tree_model_get_column_type; iface->get_iter = fm_tree_model_get_iter; iface->get_path = fm_tree_model_get_path; iface->get_value = fm_tree_model_get_value; iface->iter_next = fm_tree_model_iter_next; iface->iter_children = fm_tree_model_iter_children; iface->iter_has_child = fm_tree_model_iter_has_child; iface->iter_n_children = fm_tree_model_iter_n_children; iface->iter_nth_child = fm_tree_model_iter_nth_child; iface->iter_parent = fm_tree_model_iter_parent; iface->ref_node = fm_tree_model_ref_node; iface->unref_node = fm_tree_model_unref_node; } nemo-4.4.2/src/nemo-tree-sidebar-model.h000066400000000000000000000075311357442400300200270ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2002 Anders Carlsson * Copyright (C) 2002 Bent Spoon Software * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Author: Anders Carlsson */ /* fm-tree-model.h - Model for the tree view */ #ifndef FM_TREE_MODEL_H #define FM_TREE_MODEL_H #include #include #include #include #define FM_TYPE_TREE_MODEL fm_tree_model_get_type() #define FM_TREE_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FM_TYPE_TREE_MODEL, FMTreeModel)) #define FM_TREE_MODEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), FM_TYPE_TREE_MODEL, FMTreeModelClass)) #define FM_IS_TREE_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FM_TYPE_TREE_MODEL)) #define FM_IS_TREE_MODEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), FM_TYPE_TREE_MODEL)) #define FM_TREE_MODEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), FM_TYPE_TREE_MODEL, FMTreeModelClass)) enum { FM_TREE_MODEL_DISPLAY_NAME_COLUMN, FM_TREE_MODEL_CLOSED_ICON_COLUMN, FM_TREE_MODEL_OPEN_ICON_COLUMN, FM_TREE_MODEL_FONT_STYLE_COLUMN, FM_TREE_MODEL_TEXT_WEIGHT_COLUMN, FM_TREE_MODEL_NUM_COLUMNS }; typedef struct FMTreeModelDetails FMTreeModelDetails; typedef struct { GObject parent; FMTreeModelDetails *details; } FMTreeModel; typedef struct { GObjectClass parent_class; void (* row_loaded) (FMTreeModel *tree_model, GtkTreeIter *iter); } FMTreeModelClass; GType fm_tree_model_get_type (void); FMTreeModel *fm_tree_model_new (void); void fm_tree_model_set_show_hidden_files (FMTreeModel *model, gboolean show_hidden_files); void fm_tree_model_set_show_only_directories (FMTreeModel *model, gboolean show_only_directories); NemoFile * fm_tree_model_iter_get_file (FMTreeModel *model, GtkTreeIter *iter); void fm_tree_model_add_root_uri (FMTreeModel *model, const char *root_uri, const char *display_name, GIcon *icon, GMount *mount); void fm_tree_model_remove_root_uri (FMTreeModel *model, const char *root_uri); gboolean fm_tree_model_iter_is_root (FMTreeModel *model, GtkTreeIter *iter); int fm_tree_model_iter_compare_roots (FMTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b); gboolean fm_tree_model_file_get_iter (FMTreeModel *model, GtkTreeIter *iter, NemoFile *file, GtkTreeIter *currentIter); GMount * fm_tree_model_get_mount_for_root_node_file (FMTreeModel *model, NemoFile *file); void fm_tree_model_set_highlight_for_files (FMTreeModel *model, GList *files); #endif /* FM_TREE_MODEL_H */nemo-4.4.2/src/nemo-tree-sidebar.c000066400000000000000000001550271357442400300167300ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2000, 2001 Eazel, Inc * Copyright (C) 2002 Anders Carlsson * Copyright (C) 2002 Darin Adler * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: * Maciej Stachowiak * Anders Carlsson * Darin Adler */ /* fm-tree-view.c - tree sidebar panel */ #include #include "nemo-tree-sidebar.h" #include "nemo-tree-sidebar-model.h" #include "nemo-properties-window.h" #include "nemo-window-slot.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_LIST_VIEW #include typedef struct { GObject parent; } FMTreeViewProvider; typedef struct { GObjectClass parent; } FMTreeViewProviderClass; struct FMTreeViewDetails { NemoWindow *window; GtkTreeView *tree_widget; GtkTreeModelSort *sort_model; FMTreeModel *child_model; GVolumeMonitor *volume_monitor; NemoFile *activation_file; NemoWindowOpenFlags activation_flags; NemoTreeViewDragDest *drag_dest; char *selection_location; gboolean selecting; guint show_selection_idle_id; gulong clipboard_handler_id; GtkWidget *popup; GtkWidget *popup_open; GtkWidget *popup_open_in_new_window; GtkWidget *popup_open_in_new_tab; GtkWidget *popup_create_folder; GtkWidget *popup_cut; GtkWidget *popup_copy; GtkWidget *popup_paste; GtkWidget *popup_rename; GtkWidget *popup_pin; GtkWidget *popup_trash; GtkWidget *popup_delete; GtkWidget *popup_properties; GtkWidget *popup_unmount_separator; GtkWidget *popup_unmount; GtkWidget *popup_eject; GtkWidget *popup_action_separator; NemoFile *popup_file; guint popup_file_idle_handler; guint selection_changed_timer; NemoActionManager *action_manager; guint action_manager_changed_id; GList *action_items; guint hidden_files_changed_id; guint sort_directories_first : 1; }; typedef struct { GList *uris; FMTreeView *view; } PrependURIParameters; typedef struct { NemoAction *action; FMTreeView *view; GtkWidget *item; } ActionPayload; static GdkAtom copied_files_atom; static void fm_tree_view_activate_file (FMTreeView *view, NemoFile *file, NemoWindowOpenFlags flags); static void create_popup_menu (FMTreeView *view); static void add_action_popup_items (FMTreeView *view); G_DEFINE_TYPE (FMTreeView, fm_tree_view, GTK_TYPE_SCROLLED_WINDOW) #define parent_class fm_tree_view_parent_class static void notify_clipboard_info (NemoClipboardMonitor *monitor, NemoClipboardInfo *info, FMTreeView *view) { if (info != NULL && info->cut) { fm_tree_model_set_highlight_for_files (view->details->child_model, info->files); } else { fm_tree_model_set_highlight_for_files (view->details->child_model, NULL); } } static gboolean show_iter_for_file (FMTreeView *view, NemoFile *file, GtkTreeIter *iter) { GtkTreeModel *model; NemoFile *parent_file; GtkTreeIter parent_iter; GtkTreePath *path, *sort_path; GtkTreeIter cur_iter; if (view->details->child_model == NULL) { return FALSE; } model = GTK_TREE_MODEL (view->details->child_model); /* check if file is visible in the same root as the currently selected folder is */ gtk_tree_view_get_cursor (view->details->tree_widget, &path, NULL); if (path != NULL) { if (gtk_tree_model_get_iter (model, &cur_iter, path) && fm_tree_model_file_get_iter (view->details->child_model, iter, file, &cur_iter)) { gtk_tree_path_free (path); return TRUE; } gtk_tree_path_free (path); } /* check if file is visible at all */ if (fm_tree_model_file_get_iter (view->details->child_model, iter, file, NULL)) { return TRUE; } parent_file = nemo_file_get_parent (file); if (parent_file == NULL) { return FALSE; } if (!show_iter_for_file (view, parent_file, &parent_iter)) { nemo_file_unref (parent_file); return FALSE; } nemo_file_unref (parent_file); if (parent_iter.user_data == NULL || parent_iter.stamp == 0) { return FALSE; } path = gtk_tree_model_get_path (model, &parent_iter); sort_path = gtk_tree_model_sort_convert_child_path_to_path (view->details->sort_model, path); gtk_tree_path_free (path); gtk_tree_view_expand_row (view->details->tree_widget, sort_path, FALSE); gtk_tree_path_free (sort_path); return FALSE; } static void refresh_highlight (FMTreeView *view) { NemoClipboardMonitor *monitor; NemoClipboardInfo *info; monitor = nemo_clipboard_monitor_get (); info = nemo_clipboard_monitor_get_clipboard_info (monitor); notify_clipboard_info (monitor, info, view); } static gboolean show_selection_idle_callback (gpointer callback_data) { FMTreeView *view; NemoFile *file, *old_file; GtkTreeIter iter; GtkTreePath *path, *sort_path; view = FM_TREE_VIEW (callback_data); view->details->show_selection_idle_id = 0; file = nemo_file_get_by_uri (view->details->selection_location); if (file == NULL) { return FALSE; } if (!nemo_file_is_directory (file)) { old_file = file; file = nemo_file_get_parent (file); nemo_file_unref (old_file); if (file == NULL) { return FALSE; } } view->details->selecting = TRUE; if (!show_iter_for_file (view, file, &iter)) { nemo_file_unref (file); return FALSE; } view->details->selecting = FALSE; path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->child_model), &iter); sort_path = gtk_tree_model_sort_convert_child_path_to_path (view->details->sort_model, path); gtk_tree_path_free (path); gtk_tree_view_set_cursor (view->details->tree_widget, sort_path, NULL, FALSE); if (gtk_widget_get_realized (GTK_WIDGET (view->details->tree_widget))) { gtk_tree_view_scroll_to_cell (view->details->tree_widget, sort_path, NULL, FALSE, 0, 0); } gtk_tree_path_free (sort_path); nemo_file_unref (file); refresh_highlight (view); return FALSE; } static void schedule_show_selection (FMTreeView *view) { if (view->details->show_selection_idle_id == 0) { view->details->show_selection_idle_id = g_idle_add (show_selection_idle_callback, view); } } static void schedule_select_and_show_location (FMTreeView *view, char *location) { if (view->details->selection_location != NULL) { g_free (view->details->selection_location); } view->details->selection_location = g_strdup (location); schedule_show_selection (view); } static void row_loaded_callback (GtkTreeModel *tree_model, GtkTreeIter *iter, FMTreeView *view) { NemoFile *file, *tmp_file, *selection_file; if (view->details->selection_location == NULL || !view->details->selecting || iter->user_data == NULL || iter->stamp == 0) { return; } file = fm_tree_model_iter_get_file (view->details->child_model, iter); if (file == NULL) { return; } if (!nemo_file_is_directory (file)) { nemo_file_unref(file); return; } /* if iter is ancestor of wanted selection_location then update selection */ selection_file = nemo_file_get_by_uri (view->details->selection_location); while (selection_file != NULL) { if (file == selection_file) { nemo_file_unref (file); nemo_file_unref (selection_file); schedule_show_selection (view); return; } tmp_file = nemo_file_get_parent (selection_file); nemo_file_unref (selection_file); selection_file = tmp_file; } nemo_file_unref (file); } static NemoFile * sort_model_iter_to_file (FMTreeView *view, GtkTreeIter *iter) { GtkTreeIter child_iter; gtk_tree_model_sort_convert_iter_to_child_iter (view->details->sort_model, &child_iter, iter); return fm_tree_model_iter_get_file (view->details->child_model, &child_iter); } static NemoFile * sort_model_path_to_file (FMTreeView *view, GtkTreePath *path) { GtkTreeIter iter; if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->sort_model), &iter, path)) { return NULL; } return sort_model_iter_to_file (view, &iter); } static void got_activation_uri_callback (NemoFile *file, gpointer callback_data) { char *uri, *file_uri; FMTreeView *view; GdkScreen *screen; GFile *location; NemoWindowSlot *slot; gboolean open_in_same_slot; view = FM_TREE_VIEW (callback_data); screen = gtk_widget_get_screen (GTK_WIDGET (view->details->tree_widget)); g_assert (file == view->details->activation_file); open_in_same_slot = (view->details->activation_flags & (NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW | NEMO_WINDOW_OPEN_FLAG_NEW_TAB)) == 0; slot = nemo_window_get_active_slot (view->details->window); uri = nemo_file_get_activation_uri (file); if (nemo_file_is_launcher (file)) { file_uri = nemo_file_get_uri (file); DEBUG ("Tree sidebar, launching %s", file_uri); nemo_launch_desktop_file (screen, file_uri, NULL, NULL); g_free (file_uri); } else if (uri != NULL && nemo_file_is_executable (file) && nemo_file_can_execute (file) && !nemo_file_is_directory (file)) { file_uri = g_filename_from_uri (uri, NULL, NULL); /* Non-local executables don't get launched. They act like non-executables. */ if (file_uri == NULL) { DEBUG ("Tree sidebar, opening location %s", uri); location = g_file_new_for_uri (uri); nemo_window_slot_open_location (slot, location, view->details->activation_flags); g_object_unref (location); } else { DEBUG ("Tree sidebar, launching application for %s", file_uri); nemo_launch_application_from_command (screen, file_uri, FALSE, NULL); g_free (file_uri); } } else if (uri != NULL) { if (!open_in_same_slot || view->details->selection_location == NULL || strcmp (uri, view->details->selection_location) != 0) { if (open_in_same_slot) { if (view->details->selection_location != NULL) { g_free (view->details->selection_location); } view->details->selection_location = g_strdup (uri); } DEBUG ("Tree sidebar, opening location %s", uri); location = g_file_new_for_uri (uri); nemo_window_slot_open_location (slot, location, view->details->activation_flags); g_object_unref (location); } } g_free (uri); nemo_file_unref (view->details->activation_file); view->details->activation_file = NULL; } static void cancel_activation (FMTreeView *view) { if (view->details->activation_file == NULL) { return; } nemo_file_cancel_call_when_ready (view->details->activation_file, got_activation_uri_callback, view); nemo_file_unref (view->details->activation_file); view->details->activation_file = NULL; } static void row_activated_callback (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, FMTreeView *view) { if (gtk_tree_view_row_expanded (view->details->tree_widget, path)) { gtk_tree_view_collapse_row (view->details->tree_widget, path); } else { gtk_tree_view_expand_row (view->details->tree_widget, path, FALSE); } } static gboolean selection_changed_timer_callback(FMTreeView *view) { NemoFileAttributes attributes; GtkTreeIter iter; GtkTreeSelection *selection; /* no activation if popup menu is open */ if (view->details->popup_file != NULL) { return FALSE; } selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget)); cancel_activation (view); if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { return FALSE; } view->details->activation_file = sort_model_iter_to_file (view, &iter); if (view->details->activation_file == NULL) { return FALSE; } view->details->activation_flags = 0; attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; nemo_file_call_when_ready (view->details->activation_file, attributes, got_activation_uri_callback, view); return FALSE; /* remove timeout */ } static void selection_changed_callback (GtkTreeSelection *selection, FMTreeView *view) { GdkEvent *event; gboolean is_keyboard; if (view->details->selection_changed_timer) { g_source_remove (view->details->selection_changed_timer); view->details->selection_changed_timer = 0; } event = gtk_get_current_event (); if (event) { is_keyboard = (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE); gdk_event_free (event); if (is_keyboard) { /* on keyboard event: delay the change */ /* TODO: make dependent on keyboard repeat rate as per Markus Bertheau ? */ view->details->selection_changed_timer = g_timeout_add (300, (GSourceFunc) selection_changed_timer_callback, view); } else { /* on mouse event: show the change immediately */ selection_changed_timer_callback (view); } } } static int compare_rows (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer callback_data) { NemoFile *file_a, *file_b; int result; /* Dummy rows are always first */ if (a->user_data == NULL) { return -1; } else if (b->user_data == NULL) { return 1; } /* don't sort root nodes */ if (fm_tree_model_iter_is_root (FM_TREE_MODEL (model), a) && fm_tree_model_iter_is_root (FM_TREE_MODEL (model), b)) { return fm_tree_model_iter_compare_roots (FM_TREE_MODEL (model), a, b); } file_a = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), a); file_b = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), b); if (file_a == file_b) { result = 0; } else if (file_a == NULL) { result = -1; } else if (file_b == NULL) { result = +1; } else { result = nemo_file_compare_for_sort (file_a, file_b, NEMO_FILE_SORT_BY_DISPLAY_NAME, FM_TREE_VIEW (callback_data)->details->sort_directories_first, FALSE); } nemo_file_unref (file_a); nemo_file_unref (file_b); return result; } static char * get_root_uri_callback (NemoTreeViewDragDest *dest, gpointer user_data) { /* Don't allow drops on background */ return NULL; } static NemoFile * get_file_for_path_callback (NemoTreeViewDragDest *dest, GtkTreePath *path, gpointer user_data) { FMTreeView *view; view = FM_TREE_VIEW (user_data); return sort_model_path_to_file (view, path); } static void move_copy_items_callback (NemoTreeViewDragDest *dest, const GList *item_uris, const char *target_uri, GdkDragAction action, int x, int y, gpointer user_data) { FMTreeView *view; view = FM_TREE_VIEW (user_data); nemo_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), item_uris, copied_files_atom); nemo_file_operations_copy_move (item_uris, NULL, target_uri, action, GTK_WIDGET (view->details->tree_widget), NULL, NULL); } static void add_root_for_mount (FMTreeView *view, GMount *mount) { char *mount_uri, *name; GFile *root; GIcon *icon; if (g_mount_is_shadowed (mount)) return; icon = g_mount_get_icon (mount); root = g_mount_get_root (mount); mount_uri = g_file_get_uri (root); g_object_unref (root); name = g_mount_get_name (mount); fm_tree_model_add_root_uri(view->details->child_model, mount_uri, name, icon, mount); g_object_unref (icon); g_free (name); g_free (mount_uri); } static void mount_added_callback (GVolumeMonitor *volume_monitor, GMount *mount, FMTreeView *view) { add_root_for_mount (view, mount); } static void mount_removed_callback (GVolumeMonitor *volume_monitor, GMount *mount, FMTreeView *view) { GFile *root; char *mount_uri; root = g_mount_get_root (mount); mount_uri = g_file_get_uri (root); g_object_unref (root); fm_tree_model_remove_root_uri (view->details->child_model, mount_uri); g_free (mount_uri); } static void clipboard_contents_received_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) { FMTreeView *view; view = FM_TREE_VIEW (data); if (gtk_selection_data_get_data_type (selection_data) == copied_files_atom && gtk_selection_data_get_length (selection_data) > 0 && view->details->popup != NULL) { gtk_widget_set_sensitive (view->details->popup_paste, TRUE); } g_object_unref (view); } static gboolean is_parent_writable (NemoFile *file) { NemoFile *parent; gboolean result; parent = nemo_file_get_parent (file); /* No parent directory, return FALSE */ if (parent == NULL) { return FALSE; } result = nemo_file_can_write (parent); nemo_file_unref (parent); return result; } static gboolean button_pressed_callback (GtkTreeView *treeview, GdkEventButton *event, FMTreeView *view) { GtkTreePath *path, *cursor_path; gboolean parent_file_is_writable; gboolean file_is_home_or_desktop; gboolean file_is_special_link; gboolean can_move_file_to_trash; gboolean can_delete_file; gboolean using_browser; using_browser = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); if (event->button == 3) { gboolean show_unmount = FALSE; gboolean show_eject = FALSE; GMount *mount = NULL; if (view->details->popup_file != NULL) { return FALSE; /* Already up, ignore */ } if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL)) { return FALSE; } view->details->popup_file = sort_model_path_to_file (view, path); if (view->details->popup_file == NULL) { gtk_tree_path_free (path); return FALSE; } gtk_tree_view_get_cursor (view->details->tree_widget, &cursor_path, NULL); gtk_tree_path_free (path); create_popup_menu (view); if (using_browser) { gtk_widget_set_sensitive (view->details->popup_open_in_new_window, nemo_file_is_directory (view->details->popup_file)); gtk_widget_set_sensitive (view->details->popup_open_in_new_tab, nemo_file_is_directory (view->details->popup_file)); } gtk_widget_set_sensitive (view->details->popup_create_folder, nemo_file_is_directory (view->details->popup_file) && nemo_file_can_write (view->details->popup_file)); gtk_widget_set_sensitive (view->details->popup_paste, FALSE); if (nemo_file_is_directory (view->details->popup_file) && nemo_file_can_write (view->details->popup_file)) { gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)), copied_files_atom, clipboard_contents_received_callback, g_object_ref (view)); } can_move_file_to_trash = nemo_file_can_trash (view->details->popup_file); gtk_widget_set_sensitive (view->details->popup_trash, can_move_file_to_trash); if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE)) { parent_file_is_writable = is_parent_writable (view->details->popup_file); file_is_home_or_desktop = nemo_file_is_home (view->details->popup_file) || nemo_file_is_desktop_directory (view->details->popup_file); file_is_special_link = NEMO_IS_DESKTOP_ICON_FILE (view->details->popup_file); can_delete_file = parent_file_is_writable && !file_is_home_or_desktop && !file_is_special_link; gtk_widget_show (view->details->popup_delete); gtk_widget_set_sensitive (view->details->popup_delete, can_delete_file); } else { gtk_widget_hide (view->details->popup_delete); } mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, view->details->popup_file); if (mount) { show_unmount = g_mount_can_unmount (mount); show_eject = g_mount_can_eject (mount); } if (show_unmount) { gtk_widget_show (view->details->popup_unmount); } else { gtk_widget_hide (view->details->popup_unmount); } if (show_eject) { gtk_widget_show (view->details->popup_eject); } else { gtk_widget_hide (view->details->popup_eject); } if (show_unmount || show_eject) { gtk_widget_show (view->details->popup_unmount_separator); } else { gtk_widget_hide (view->details->popup_unmount_separator); } if (nemo_file_get_pinning (view->details->popup_file)) { gtk_menu_item_set_label (GTK_MENU_ITEM (view->details->popup_pin), _("Unp_in")); } else { gtk_menu_item_set_label (GTK_MENU_ITEM (view->details->popup_pin), _("P_in")); } gboolean actions_visible = FALSE; GList *l; NemoFile *file = view->details->popup_file; NemoFile *parent = nemo_file_get_parent (file); GList *tmp = NULL; tmp = g_list_append (tmp, file); ActionPayload *p; for (l = view->details->action_items; l != NULL; l = l->next) { p = l->data; if (nemo_action_get_visibility (p->action, tmp, parent, FALSE)) { gchar *action_label; action_label = nemo_action_get_label (p->action, tmp, parent); gtk_menu_item_set_label (GTK_MENU_ITEM (p->item), action_label); g_free (action_label); gtk_widget_set_visible (p->item, TRUE); actions_visible = TRUE; } else { gtk_widget_set_visible (p->item, FALSE); } } gtk_widget_set_visible (view->details->popup_action_separator, actions_visible); g_list_free (tmp); // Don't free the file, just the list, the file is owned by the model. gtk_menu_popup (GTK_MENU (view->details->popup), NULL, NULL, NULL, NULL, event->button, event->time); gtk_tree_view_set_cursor (view->details->tree_widget, cursor_path, NULL, FALSE); gtk_tree_path_free (cursor_path); return FALSE; } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { NemoFile *file; NemoWindowOpenFlags flags = 0; if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL)) { return FALSE; } file = sort_model_path_to_file (view, path); if (using_browser) { flags = (event->state & GDK_CONTROL_MASK) ? NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW : NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else { flags = NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND; } if (file) { fm_tree_view_activate_file (view, file, flags); nemo_file_unref (file); } gtk_tree_path_free (path); return TRUE; } return FALSE; } static void fm_tree_view_activate_file (FMTreeView *view, NemoFile *file, NemoWindowOpenFlags flags) { NemoFileAttributes attributes; cancel_activation (view); view->details->activation_file = nemo_file_ref (file); view->details->activation_flags = flags; attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; nemo_file_call_when_ready (view->details->activation_file, attributes, got_activation_uri_callback, view); } static void fm_tree_view_open_cb (GtkWidget *menu_item, FMTreeView *view) { fm_tree_view_activate_file (view, view->details->popup_file, 0); } static void fm_tree_view_open_in_new_tab_cb (GtkWidget *menu_item, FMTreeView *view) { fm_tree_view_activate_file (view, view->details->popup_file, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); } static void fm_tree_view_open_in_new_window_cb (GtkWidget *menu_item, FMTreeView *view) { fm_tree_view_activate_file (view, view->details->popup_file, NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); } static void new_folder_done (GFile *new_folder, gboolean success, gpointer data) { GList *list; /* show the properties window for the newly created * folder so the user can change its name */ list = g_list_prepend (NULL, nemo_file_get (new_folder)); nemo_properties_window_present (list, GTK_WIDGET (data), NULL); nemo_file_list_free (list); } static void fm_tree_view_create_folder_cb (GtkWidget *menu_item, FMTreeView *view) { char *parent_uri; parent_uri = nemo_file_get_uri (view->details->popup_file); nemo_file_operations_new_folder (GTK_WIDGET (view->details->tree_widget), NULL, parent_uri, new_folder_done, view->details->tree_widget); g_free (parent_uri); } static void copy_or_cut_files (FMTreeView *view, gboolean cut) { char *status_string, *name; NemoClipboardInfo info; GtkTargetList *target_list; GtkTargetEntry *targets; int n_targets; info.cut = cut; info.files = g_list_prepend (NULL, view->details->popup_file); target_list = gtk_target_list_new (NULL, 0); gtk_target_list_add (target_list, copied_files_atom, 0, 0); gtk_target_list_add_uri_targets (target_list, 0); gtk_target_list_add_text_targets (target_list, 0); targets = gtk_target_table_new_from_list (target_list, &n_targets); gtk_target_list_unref (target_list); gtk_clipboard_set_with_data (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)), targets, n_targets, nemo_get_clipboard_callback, nemo_clear_clipboard_callback, NULL); gtk_target_table_free (targets, n_targets); nemo_clipboard_monitor_set_clipboard_info (nemo_clipboard_monitor_get (), &info); g_list_free (info.files); name = nemo_file_get_display_name (view->details->popup_file); if (cut) { status_string = g_strdup_printf (_("\"%s\" will be moved " "if you select the Paste command"), name); } else { status_string = g_strdup_printf (_("\"%s\" will be copied " "if you select the Paste command"), name); } g_free (name); nemo_window_push_status (view->details->window, status_string); g_free (status_string); } static void fm_tree_view_cut_cb (GtkWidget *menu_item, FMTreeView *view) { copy_or_cut_files (view, TRUE); } static void fm_tree_view_copy_cb (GtkWidget *menu_item, FMTreeView *view) { copy_or_cut_files (view, FALSE); } static void paste_clipboard_data (FMTreeView *view, GtkSelectionData *selection_data, char *destination_uri) { gboolean cut; GList *item_uris; cut = FALSE; item_uris = nemo_clipboard_get_uri_list_from_selection_data (selection_data, &cut, copied_files_atom); if (item_uris == NULL|| destination_uri == NULL) { nemo_window_push_status (view->details->window, _("There is nothing on the clipboard to paste.")); } else { nemo_file_operations_copy_move (item_uris, NULL, destination_uri, cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY, GTK_WIDGET (view->details->tree_widget), NULL, NULL); /* If items are cut then remove from clipboard */ if (cut) { gtk_clipboard_clear (nemo_clipboard_get (GTK_WIDGET (view))); } g_list_free_full (item_uris, g_free); } } static void paste_into_clipboard_received_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) { FMTreeView *view; char *directory_uri; view = FM_TREE_VIEW (data); directory_uri = nemo_file_get_uri (view->details->popup_file); paste_clipboard_data (view, selection_data, directory_uri); g_free (directory_uri); } static void fm_tree_view_paste_cb (GtkWidget *menu_item, FMTreeView *view) { gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)), copied_files_atom, paste_into_clipboard_received_callback, view); } static GtkWindow * fm_tree_view_get_containing_window (FMTreeView *view) { GtkWidget *window; g_assert (FM_IS_TREE_VIEW (view)); window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW); if (window == NULL) { return NULL; } return GTK_WINDOW (window); } static void fm_tree_view_pin_unpin_cb (GtkWidget *menu_item, FMTreeView *view) { nemo_file_set_pinning (view->details->popup_file, !nemo_file_get_pinning (view->details->popup_file)); } static void fm_tree_view_trash_cb (GtkWidget *menu_item, FMTreeView *view) { GList *list; if (!nemo_file_can_trash (view->details->popup_file)) { return; } list = g_list_prepend (NULL, nemo_file_get_location (view->details->popup_file)); nemo_file_operations_trash_or_delete (list, fm_tree_view_get_containing_window (view), NULL, NULL); g_list_free_full (list, g_object_unref); } static void fm_tree_view_delete_cb (GtkWidget *menu_item, FMTreeView *view) { GList *location_list; if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE)) { return; } location_list = g_list_prepend (NULL, nemo_file_get_location (view->details->popup_file)); nemo_file_operations_delete (location_list, fm_tree_view_get_containing_window (view), NULL, NULL); g_list_free_full (location_list, g_object_unref); } static void fm_tree_view_properties_cb (GtkWidget *menu_item, FMTreeView *view) { GList *list; list = g_list_prepend (NULL, nemo_file_ref (view->details->popup_file)); nemo_properties_window_present (list, GTK_WIDGET (view->details->tree_widget), NULL); nemo_file_list_free (list); } static void fm_tree_view_unmount_cb (GtkWidget *menu_item, FMTreeView *view) { NemoFile *file = view->details->popup_file; GMount *mount; if (file == NULL) { return; } mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file); if (mount != NULL) { nemo_file_operations_unmount_mount (fm_tree_view_get_containing_window (view), mount, FALSE, TRUE); } } static void fm_tree_view_eject_cb (GtkWidget *menu_item, FMTreeView *view) { NemoFile *file = view->details->popup_file; GMount *mount; if (file == NULL) { return; } mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file); if (mount != NULL) { nemo_file_operations_unmount_mount (fm_tree_view_get_containing_window (view), mount, TRUE, TRUE); } } static gboolean free_popup_file_in_idle_cb (gpointer data) { FMTreeView *view; view = FM_TREE_VIEW (data); if (view->details->popup_file != NULL) { nemo_file_unref (view->details->popup_file); view->details->popup_file = NULL; } view->details->popup_file_idle_handler = 0; return FALSE; } static void popup_menu_deactivated (GtkMenuShell *menu_shell, gpointer data) { FMTreeView *view; view = FM_TREE_VIEW (data); /* The popup menu is deactivated. (I.E. hidden) We want to free popup_file, but can't right away as it might immediately get used if we're deactivation due to activating a menu item. So, we free it in idle */ if (view->details->popup_file != NULL && view->details->popup_file_idle_handler == 0) { view->details->popup_file_idle_handler = g_idle_add (free_popup_file_in_idle_cb, view); } } static void action_activated_callback (GtkMenuItem *item, ActionPayload *payload) { gchar *uri = NULL; FMTreeView *view = payload->view; NemoFile *file = view->details->popup_file; NemoFile *parent = nemo_file_get_parent (file); GList *tmp = NULL; tmp = g_list_append (tmp, file); nemo_action_activate (NEMO_ACTION (payload->action), tmp, parent); nemo_file_list_free (tmp); g_free (uri); } static void add_action_popup_items (FMTreeView *view) { if (view->details->action_items != NULL) g_list_free_full (view->details->action_items, g_free); view->details->action_items = NULL; GList *action_list = nemo_action_manager_list_actions (view->details->action_manager); GList *l; GtkWidget *menu_item; NemoAction *action; ActionPayload *payload; gint index = 13; for (l = action_list; l != NULL; l = l->next) { action = l->data; payload = g_new0 (ActionPayload, 1); payload->action = action; payload->view = view; menu_item = gtk_menu_item_new_with_mnemonic (nemo_action_get_orig_label (action)); payload->item = menu_item; g_signal_connect (menu_item, "activate", G_CALLBACK (action_activated_callback), payload); gtk_widget_show (menu_item); gtk_menu_shell_insert (GTK_MENU_SHELL (view->details->popup), menu_item, index); view->details->action_items = g_list_append (view->details->action_items, payload); index ++; } } /* Callback used when the file list's popup menu is detached */ static void popup_menu_detach_cb (GtkWidget *attach_widget, GtkMenu *menu) { FMTreeView *view; view = FM_TREE_VIEW (attach_widget); g_assert (FM_IS_TREE_VIEW (view)); view->details->popup = NULL; view->details->popup_open = NULL; view->details->popup_open_in_new_window = NULL; view->details->popup_open_in_new_tab = NULL; view->details->popup_create_folder = NULL; view->details->popup_cut = NULL; view->details->popup_copy = NULL; view->details->popup_paste = NULL; view->details->popup_rename = NULL; view->details->popup_pin = NULL; view->details->popup_trash = NULL; view->details->popup_delete = NULL; view->details->popup_properties = NULL; view->details->popup_unmount_separator = NULL; view->details->popup_unmount = NULL; view->details->popup_eject = NULL; view->details->popup_action_separator = NULL; } static void actions_changed_callback (FMTreeView *view) { if (view->details->popup) { gtk_menu_detach (GTK_MENU (view->details->popup)); } } static void create_popup_menu (FMTreeView *view) { GtkWidget *popup, *menu_item, *menu_image; if (view->details->popup != NULL) { /* already created */ return; } popup = gtk_menu_new (); gtk_menu_attach_to_widget (GTK_MENU (popup), GTK_WIDGET (view), popup_menu_detach_cb); g_signal_connect (popup, "deactivate", G_CALLBACK (popup_menu_deactivated), view); /* add the "open" menu item */ menu_image = gtk_image_new_from_icon_name ("folder-open-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Open")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_open_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_open = menu_item; /* add the "open in new tab" menu item */ menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab")); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_open_in_new_tab_cb), view); g_settings_bind (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER, menu_item, "visible", G_SETTINGS_BIND_GET); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_open_in_new_tab = menu_item; /* add the "open in new window" menu item */ menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window")); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_open_in_new_window_cb), view); g_settings_bind (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER, menu_item, "visible", G_SETTINGS_BIND_GET); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_open_in_new_window = menu_item; eel_gtk_menu_append_separator (GTK_MENU (popup)); /* add the "create new folder" menu item */ menu_item = gtk_image_menu_item_new_with_mnemonic (_("Create New _Folder")); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_create_folder_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_create_folder = menu_item; eel_gtk_menu_append_separator (GTK_MENU (popup)); /* add the "cut folder" menu item */ menu_image = gtk_image_new_from_icon_name ("edit-cut-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("Cu_t")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_cut_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_cut = menu_item; /* add the "copy folder" menu item */ menu_image = gtk_image_new_from_icon_name ("edit-copy-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Copy")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_copy_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_copy = menu_item; /* add the "paste files into folder" menu item */ menu_image = gtk_image_new_from_icon_name ("edit-paste-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Paste Into Folder")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_paste_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_paste = menu_item; eel_gtk_menu_append_separator (GTK_MENU (popup)); menu_image = gtk_image_new_from_icon_name ("view-pin-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("P_in")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_pin_unpin_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_pin = menu_item; eel_gtk_menu_append_separator (GTK_MENU (popup)); /* add the "move to trash" menu item */ menu_image = gtk_image_new_from_icon_name (NEMO_ICON_SYMBOLIC_TRASH_FULL, GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("Mo_ve to Trash")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_trash_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_trash = menu_item; /* add the "delete" menu item */ menu_image = gtk_image_new_from_icon_name (NEMO_ICON_DELETE, GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Delete")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_delete_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_delete = menu_item; /* Nemo Actions */ view->details->popup_action_separator = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (popup))); eel_gtk_menu_append_separator (GTK_MENU (popup)); /* add the "Unmount" menu item */ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Unmount")); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_unmount_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_unmount = menu_item; /* add the "Eject" menu item */ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Eject")); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_eject_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_eject = menu_item; /* add the unmount separator menu item */ view->details->popup_unmount_separator = GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (popup))); /* add the "properties" menu item */ menu_image = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU); gtk_widget_show (menu_image); menu_item = gtk_image_menu_item_new_with_mnemonic (_("P_roperties")); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); g_signal_connect (menu_item, "activate", G_CALLBACK (fm_tree_view_properties_cb), view); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item); view->details->popup_properties = menu_item; view->details->popup = popup; add_action_popup_items (view); } static gint get_icon_scale_callback (FMTreeModel *model, FMTreeView *view) { return gtk_widget_get_scale_factor (GTK_WIDGET (view->details->tree_widget)); } static void icon_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { gboolean expanded; GIcon *icon; g_object_get (cell, "is-expanded", &expanded, NULL); gtk_tree_model_get (tree_model, iter, expanded ? FM_TREE_MODEL_OPEN_ICON_COLUMN : FM_TREE_MODEL_CLOSED_ICON_COLUMN, &icon, -1); g_object_set (cell, "gicon", icon, NULL); } static void create_tree (FMTreeView *view) { GtkCellRenderer *cell; GtkTreeViewColumn *column; GVolumeMonitor *volume_monitor; char *home_uri; GList *mounts, *l; char *location; GIcon *icon; NemoWindowSlot *slot; view->details->child_model = fm_tree_model_new (); view->details->sort_model = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (view->details->child_model))); view->details->tree_widget = GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->details->sort_model))); g_object_unref (view->details->sort_model); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (view->details->tree_widget)), "NemoSidebar"); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (view->details->sort_model), compare_rows, view, NULL); g_signal_connect_object (view->details->child_model, "row_loaded", G_CALLBACK (row_loaded_callback), view, G_CONNECT_AFTER); g_signal_connect_object (view->details->child_model, "get-icon-scale", G_CALLBACK (get_icon_scale_callback), view, 0); #ifdef NOT_YET_USABLE /* Do we really want this? */ icon = g_themed_icon_new (NEMO_ICON_COMPUTER); fm_tree_model_add_root_uri (view->details->child_model, "computer:///", _("Computer"), icon, NULL); g_object_unref (icon); #endif home_uri = nemo_get_home_directory_uri (); icon = g_themed_icon_new (NEMO_ICON_HOME); fm_tree_model_add_root_uri (view->details->child_model, home_uri, _("Home"), icon, NULL); g_object_unref (icon); g_free (home_uri); icon = g_themed_icon_new (NEMO_ICON_FILESYSTEM); fm_tree_model_add_root_uri (view->details->child_model, "file:///", _("File System"), icon, NULL); g_object_unref (icon); #ifdef NOT_YET_USABLE /* Do we really want this? */ icon = g_themed_icon_new (NEMO_ICON_NETWORK); fm_tree_model_add_root_uri (view->details->child_model, "network:///", _("Network"), icon, NULL); g_object_unref (icon); #endif volume_monitor = g_volume_monitor_get (); view->details->volume_monitor = volume_monitor; mounts = g_volume_monitor_get_mounts (volume_monitor); for (l = mounts; l != NULL; l = l->next) { add_root_for_mount (view, l->data); g_object_unref (l->data); } g_list_free (mounts); g_signal_connect_object (volume_monitor, "mount_added", G_CALLBACK (mount_added_callback), view, 0); g_signal_connect_object (volume_monitor, "mount_removed", G_CALLBACK (mount_removed_callback), view, 0); g_object_unref (view->details->child_model); gtk_tree_view_set_headers_visible (view->details->tree_widget, FALSE); view->details->drag_dest = nemo_tree_view_drag_dest_new (view->details->tree_widget); g_signal_connect_object (view->details->drag_dest, "get_root_uri", G_CALLBACK (get_root_uri_callback), view, 0); g_signal_connect_object (view->details->drag_dest, "get_file_for_path", G_CALLBACK (get_file_for_path_callback), view, 0); g_signal_connect_object (view->details->drag_dest, "move_copy_items", G_CALLBACK (move_copy_items_callback), view, 0); view->details->action_manager = nemo_action_manager_new (); view->details->action_manager_changed_id = g_signal_connect_swapped (view->details->action_manager, "changed", G_CALLBACK (actions_changed_callback), view); view->details->action_items = NULL; /* Create column */ column = gtk_tree_view_column_new (); cell = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_column_set_cell_data_func (column, cell, (GtkTreeCellDataFunc) icon_data_func, NULL, NULL); g_object_set (cell, "follow-state", TRUE, NULL); cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_set_attributes (column, cell, "text", FM_TREE_MODEL_DISPLAY_NAME_COLUMN, "style", FM_TREE_MODEL_FONT_STYLE_COLUMN, "weight", FM_TREE_MODEL_TEXT_WEIGHT_COLUMN, NULL); gtk_tree_view_append_column (view->details->tree_widget, column); gtk_widget_show (GTK_WIDGET (view->details->tree_widget)); gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_widget)); g_signal_connect_object (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget)), "changed", G_CALLBACK (selection_changed_callback), view, 0); g_signal_connect (G_OBJECT (view->details->tree_widget), "row-activated", G_CALLBACK (row_activated_callback), view); g_signal_connect (G_OBJECT (view->details->tree_widget), "button_press_event", G_CALLBACK (button_pressed_callback), view); slot = nemo_window_get_active_slot (view->details->window); location = nemo_window_slot_get_current_uri (slot); schedule_select_and_show_location (view, location); g_free (location); } static void update_filtering_from_preferences (FMTreeView *view) { NemoWindowShowHiddenFilesMode mode; if (view->details->child_model == NULL) { return; } mode = nemo_window_get_hidden_files_mode (view->details->window); fm_tree_model_set_show_hidden_files (view->details->child_model, mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE); fm_tree_model_set_show_only_directories (view->details->child_model, g_settings_get_boolean (nemo_tree_sidebar_preferences, NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES)); } static void parent_set_callback (GtkWidget *widget, GtkWidget *previous_parent, gpointer callback_data) { FMTreeView *view; view = FM_TREE_VIEW (callback_data); if (gtk_widget_get_parent (widget) != NULL && view->details->tree_widget == NULL) { create_tree (view); update_filtering_from_preferences (view); } } static void filtering_changed_callback (gpointer callback_data) { update_filtering_from_preferences (FM_TREE_VIEW (callback_data)); } static void loading_uri_callback (NemoWindow *window, char *location, gpointer callback_data) { FMTreeView *view; view = FM_TREE_VIEW (callback_data); schedule_select_and_show_location (view, location); } static void sort_directories_first_changed_callback (gpointer callback_data) { FMTreeView *view; gboolean preference_value; view = FM_TREE_VIEW (callback_data); preference_value = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST); if (preference_value != view->details->sort_directories_first) { view->details->sort_directories_first = preference_value; } gtk_tree_model_sort_reset_default_sort_func (GTK_TREE_MODEL_SORT (view->details->sort_model)); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (view->details->sort_model), compare_rows, view, NULL); } static void fm_tree_view_init (FMTreeView *view) { view->details = g_new0 (FMTreeViewDetails, 1); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL); gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_IN); gtk_widget_show (GTK_WIDGET (view)); g_signal_connect_object (view, "parent_set", G_CALLBACK (parent_set_callback), view, 0); view->details->selection_location = NULL; view->details->selecting = FALSE; g_signal_connect_swapped (nemo_tree_sidebar_preferences, "changed::" NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES, G_CALLBACK (filtering_changed_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST, G_CALLBACK (sort_directories_first_changed_callback), view); view->details->sort_directories_first = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST); view->details->popup_file = NULL; view->details->clipboard_handler_id = g_signal_connect (nemo_clipboard_monitor_get (), "clipboard_info", G_CALLBACK (notify_clipboard_info), view); } static void hidden_files_mode_changed_callback (NemoWindow *window, FMTreeView *view) { update_filtering_from_preferences (view); } static void fm_tree_view_dispose (GObject *object) { FMTreeView *view; view = FM_TREE_VIEW (object); if (view->details->selection_changed_timer) { g_source_remove (view->details->selection_changed_timer); view->details->selection_changed_timer = 0; } if (view->details->drag_dest) { g_object_unref (view->details->drag_dest); view->details->drag_dest = NULL; } if (view->details->show_selection_idle_id) { g_source_remove (view->details->show_selection_idle_id); view->details->show_selection_idle_id = 0; } if (view->details->clipboard_handler_id != 0) { g_signal_handler_disconnect (nemo_clipboard_monitor_get (), view->details->clipboard_handler_id); view->details->clipboard_handler_id = 0; } cancel_activation (view); if (view->details->popup != NULL) { gtk_widget_destroy (view->details->popup); view->details->popup = NULL; } if (view->details->popup_file_idle_handler != 0) { g_source_remove (view->details->popup_file_idle_handler); view->details->popup_file_idle_handler = 0; } if (view->details->popup_file != NULL) { nemo_file_unref (view->details->popup_file); view->details->popup_file = NULL; } if (view->details->selection_location != NULL) { g_free (view->details->selection_location); view->details->selection_location = NULL; } if (view->details->volume_monitor != NULL) { g_object_unref (view->details->volume_monitor); view->details->volume_monitor = NULL; } if (view->details->hidden_files_changed_id != 0) { g_signal_handler_disconnect (view->details->window, view->details->hidden_files_changed_id); view->details->hidden_files_changed_id = 0; } if (view->details->action_manager_changed_id != 0) { g_signal_handler_disconnect (view->details->action_manager, view->details->action_manager_changed_id); view->details->action_manager_changed_id = 0; } g_clear_object (&view->details->action_manager); g_signal_handlers_disconnect_by_func (nemo_tree_sidebar_preferences, G_CALLBACK(filtering_changed_callback), view); g_signal_handlers_disconnect_by_func (nemo_tree_sidebar_preferences, G_CALLBACK(sort_directories_first_changed_callback), view); view->details->window = NULL; G_OBJECT_CLASS (parent_class)->dispose (object); } static void fm_tree_view_finalize (GObject *object) { FMTreeView *view; view = FM_TREE_VIEW (object); g_free (view->details); G_OBJECT_CLASS (parent_class)->finalize (object); } static void fm_tree_view_class_init (FMTreeViewClass *class) { G_OBJECT_CLASS (class)->dispose = fm_tree_view_dispose; G_OBJECT_CLASS (class)->finalize = fm_tree_view_finalize; copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); } static void fm_tree_view_set_parent_window (FMTreeView *sidebar, NemoWindow *window) { char *location; NemoWindowSlot *slot; sidebar->details->window = window; slot = nemo_window_get_active_slot (window); g_signal_connect_object (window, "loading_uri", G_CALLBACK (loading_uri_callback), sidebar, 0); location = nemo_window_slot_get_current_uri (slot); loading_uri_callback (window, location, sidebar); g_free (location); sidebar->details->hidden_files_changed_id = g_signal_connect_object (window, "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed_callback), sidebar, 0); } GtkWidget * nemo_tree_sidebar_new (NemoWindow *window) { FMTreeView *sidebar; sidebar = g_object_new (fm_tree_view_get_type (), NULL); fm_tree_view_set_parent_window (sidebar, window); return GTK_WIDGET (sidebar); } nemo-4.4.2/src/nemo-tree-sidebar.h000066400000000000000000000037711357442400300167330ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2000, 2001 Eazel, Inc * Copyright (C) 2002 Anders Carlsson * * 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Maciej Stachowiak * Anders Carlsson */ /* fm-tree-view.h - tree view. */ #ifndef FM_TREE_VIEW_H #define FM_TREE_VIEW_H #include #include "nemo-window.h" #define FM_TYPE_TREE_VIEW fm_tree_view_get_type() #define FM_TREE_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FM_TYPE_TREE_VIEW, FMTreeView)) #define FM_TREE_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), FM_TYPE_TREE_VIEW, FMTreeViewClass)) #define FM_IS_TREE_VIEW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FM_TYPE_TREE_VIEW)) #define FM_IS_TREE_VIEW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), FM_TYPE_TREE_VIEW)) #define FM_TREE_VIEW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), FM_TYPE_TREE_VIEW, FMTreeViewClass)) #define TREE_SIDEBAR_ID "tree" typedef struct FMTreeViewDetails FMTreeViewDetails; typedef struct { GtkScrolledWindow parent; FMTreeViewDetails *details; } FMTreeView; typedef struct { GtkScrolledWindowClass parent_class; } FMTreeViewClass; GType fm_tree_view_get_type (void); GtkWidget *nemo_tree_sidebar_new (NemoWindow *window); #endif /* FM_TREE_VIEW_H */ nemo-4.4.2/src/nemo-view-dnd.c000066400000000000000000000272171357442400300160760ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*- */ /* * nemo-view-dnd.c: DnD helpers for NemoView * * Copyright (C) 1999, 2000 Free Software Foundaton * Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Ettore Perazzoli * Darin Adler * John Sullivan * Pavel Cisler */ #include #include "nemo-view-dnd.h" #include "nemo-desktop-icon-view.h" #include "nemo-view.h" #include "nemo-desktop-utils.h" #include #include #include #include #include #define GET_ANCESTOR(obj) \ GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (obj), GTK_TYPE_WINDOW)) static inline void view_widget_to_file_operation_position (NemoView *view, GdkPoint *position) { NemoViewClass *class = NEMO_VIEW_GET_CLASS (view); if (class->widget_to_file_operation_position != NULL) { class->widget_to_file_operation_position (view, position); } } static void view_widget_to_file_operation_position_xy (NemoView *view, int *x, int *y) { GdkPoint position; position.x = *x; position.y = *y; view_widget_to_file_operation_position (view, &position); *x = position.x; *y = position.y; } typedef struct { NemoView *view; char *link_name; char *target_uri; char *url; GdkPoint point; } NetscapeUrlDropLink; static void revert_slashes (char *string) { while (*string != 0) { if (*string == '/') { *string = '\\'; } string++; } } static void handle_netscape_url_drop_link_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NetscapeUrlDropLink *data = user_data; char *link_name = data->link_name; char *link_display_name; gint monitor_num; GFileInfo *info; char *icon_name = NULL; info = g_file_query_info_finish (G_FILE (source_object), res, NULL); if (info != NULL) { GIcon *icon; const char * const *names; icon = g_file_info_get_icon (info); if (G_IS_THEMED_ICON (icon)) { names = g_themed_icon_get_names (G_THEMED_ICON (icon)); icon_name = g_strdup (names[0]); } g_object_unref (info); } if (icon_name == NULL) { icon_name = g_strdup ("text-html"); } link_display_name = g_strdup_printf (_("Link to %s"), link_name); /* The filename can't contain slashes, strip em. (the basename of http://foo/ is http://foo/) */ revert_slashes (link_name); monitor_num = nemo_desktop_utils_get_monitor_for_widget (GTK_WIDGET (data->view)); nemo_link_local_create (data->target_uri, link_name, link_display_name, icon_name, data->url, &data->point, monitor_num, TRUE); g_free (link_display_name); g_free (icon_name); g_free (data->url); g_free (data->link_name); g_free (data->target_uri); g_object_unref (data->view); g_slice_free (NetscapeUrlDropLink, data); } void nemo_view_handle_netscape_url_drop (NemoView *view, const char *encoded_url, const char *target_uri, GdkDragAction action, int x, int y) { char *url, *title; char *link_name; GArray *points; char **bits; GList *uri_list = NULL; GFile *f; f = g_file_new_for_uri (target_uri); if (!g_file_is_native (f)) { eel_show_warning_dialog (_("Drag and drop is not supported."), _("Drag and drop is only supported on local file systems."), GET_ANCESTOR (view)); g_object_unref (f); return; } g_object_unref (f); /* _NETSCAPE_URL_ works like this: $URL\n$TITLE */ bits = g_strsplit (encoded_url, "\n", 0); switch (g_strv_length (bits)) { case 0: g_strfreev (bits); return; case 1: url = bits[0]; title = NULL; break; default: url = bits[0]; title = bits[1]; } f = g_file_new_for_uri (url); view_widget_to_file_operation_position_xy (view, &x, &y); /* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE * and we don't support combinations either. */ if ((action != GDK_ACTION_DEFAULT) && (action != GDK_ACTION_COPY) && (action != GDK_ACTION_MOVE) && (action != GDK_ACTION_LINK)) { eel_show_warning_dialog (_("Drag and drop is not supported."), _("An invalid drag type was used."), GET_ANCESTOR (view)); g_object_unref (f); g_strfreev (bits); return; } if (action == GDK_ACTION_LINK) { if (g_strcmp0 (title, NULL) == 0) { link_name = g_file_get_basename (f); } else { link_name = g_strdup (title); } if (g_strcmp0 (link_name, NULL) != 0) { NetscapeUrlDropLink *data; data = g_slice_new0 (NetscapeUrlDropLink); data->link_name = link_name; data->point.x = x; data->point.y = y; data->view = g_object_ref (view); data->target_uri = g_strdup (target_uri); data->url = g_strdup (url); g_file_query_info_async (f, G_FILE_ATTRIBUTE_STANDARD_ICON, 0, 0, NULL, handle_netscape_url_drop_link_cb, data); } } else { GdkPoint tmp_point = { 0, 0 }; /* pass in a 1-item array of icon positions, relative to x, y */ points = g_array_new (FALSE, TRUE, sizeof (GdkPoint)); g_array_append_val (points, tmp_point); uri_list = g_list_append (uri_list, url); nemo_view_move_copy_items (view, uri_list, points, target_uri, action, x, y); g_list_free (uri_list); g_array_free (points, TRUE); } g_object_unref (f); g_strfreev (bits); } void nemo_view_handle_uri_list_drop (NemoView *view, const char *item_uris, const char *target_uri, GdkDragAction action, int x, int y) { gchar **uri_list; GList *real_uri_list = NULL; char *container_uri; int n_uris, i; GArray *points; if (item_uris == NULL) { return; } container_uri = NULL; if (target_uri == NULL) { container_uri = nemo_view_get_backing_uri (view); g_assert (container_uri != NULL); } if (action == GDK_ACTION_ASK) { action = nemo_drag_drop_action_ask (GTK_WIDGET (view), GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); if (action == 0) { g_free (container_uri); return; } } /* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE * and we don't support combinations either. */ if ((action != GDK_ACTION_DEFAULT) && (action != GDK_ACTION_COPY) && (action != GDK_ACTION_MOVE) && (action != GDK_ACTION_LINK)) { eel_show_warning_dialog (_("Drag and drop is not supported."), _("An invalid drag type was used."), GET_ANCESTOR (view)); g_free (container_uri); return; } n_uris = 0; uri_list = g_uri_list_extract_uris (item_uris); for (i = 0; uri_list[i] != NULL; i++) { real_uri_list = g_list_append (real_uri_list, uri_list[i]); n_uris++; } g_free (uri_list); /* do nothing if no real uris are left */ if (n_uris == 0) { g_free (container_uri); return; } if (n_uris == 1) { GdkPoint tmp_point = { 0, 0 }; /* pass in a 1-item array of icon positions, relative to x, y */ points = g_array_new (FALSE, TRUE, sizeof (GdkPoint)); g_array_append_val (points, tmp_point); } else { points = NULL; } view_widget_to_file_operation_position_xy (view, &x, &y); nemo_view_move_copy_items (view, real_uri_list, points, target_uri != NULL ? target_uri : container_uri, action, x, y); g_list_free_full (real_uri_list, g_free); if (points != NULL) g_array_free (points, TRUE); g_free (container_uri); } void nemo_view_handle_text_drop (NemoView *view, const char *text, const char *target_uri, GdkDragAction action, int x, int y) { int length; char *container_uri; GdkPoint pos; if (text == NULL) { return; } g_return_if_fail (action == GDK_ACTION_COPY); container_uri = NULL; if (target_uri == NULL) { container_uri = nemo_view_get_backing_uri (view); g_assert (container_uri != NULL); } length = strlen (text); pos.x = x; pos.y = y; view_widget_to_file_operation_position (view, &pos); nemo_view_new_file_with_initial_contents ( view, target_uri != NULL ? target_uri : container_uri, /* Translator: This is the filename used for when you dnd text to a directory */ _("dropped text.txt"), text, length, &pos); g_free (container_uri); } void nemo_view_handle_raw_drop (NemoView *view, const char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y) { char *container_uri, *filename; GFile *direct_save_full; GdkPoint pos; if (raw_data == NULL) { return; } g_return_if_fail (action == GDK_ACTION_COPY); container_uri = NULL; if (target_uri == NULL) { container_uri = nemo_view_get_backing_uri (view); g_assert (container_uri != NULL); } pos.x = x; pos.y = y; view_widget_to_file_operation_position (view, &pos); filename = NULL; if (direct_save_uri != NULL) { direct_save_full = g_file_new_for_uri (direct_save_uri); filename = g_file_get_basename (direct_save_full); } if (filename == NULL) { /* Translator: This is the filename used for when you dnd raw * data to a directory, if the source didn't supply a name. */ filename = g_strdup (_("dropped data")); } nemo_view_new_file_with_initial_contents ( view, target_uri != NULL ? target_uri : container_uri, filename, raw_data, length, &pos); g_free (container_uri); g_free (filename); } void nemo_view_drop_proxy_received_uris (NemoView *view, const GList *source_uri_list, const char *target_uri, GdkDragAction action) { char *container_uri; container_uri = NULL; if (target_uri == NULL) { container_uri = nemo_view_get_backing_uri (view); g_assert (container_uri != NULL); } if (action == GDK_ACTION_ASK) { action = nemo_drag_drop_action_ask (GTK_WIDGET (view), GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); if (action == 0) { return; } } nemo_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), source_uri_list, nemo_view_get_copied_files_atom (view)); nemo_view_move_copy_items (view, source_uri_list, NULL, target_uri != NULL ? target_uri : container_uri, action, 0, 0); g_free (container_uri); } nemo-4.4.2/src/nemo-view-dnd.h000066400000000000000000000044531357442400300161000ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-view-dnd.h: DnD helpers for NemoView * * Copyright (C) 1999, 2000 Free Software Foundaton * Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Ettore Perazzoli * Darin Adler * John Sullivan * Pavel Cisler */ #ifndef __NEMO_VIEW_DND_H__ #define __NEMO_VIEW_DND_H__ #include "nemo-view.h" void nemo_view_handle_netscape_url_drop (NemoView *view, const char *encoded_url, const char *target_uri, GdkDragAction action, int x, int y); void nemo_view_handle_uri_list_drop (NemoView *view, const char *item_uris, const char *target_uri, GdkDragAction action, int x, int y); void nemo_view_handle_text_drop (NemoView *view, const char *text, const char *target_uri, GdkDragAction action, int x, int y); void nemo_view_handle_raw_drop (NemoView *view, const char *raw_data, int length, const char *target_uri, const char *direct_save_uri, GdkDragAction action, int x, int y); void nemo_view_drop_proxy_received_uris (NemoView *view, const GList *uris, const char *target_location, GdkDragAction action); #endif /* __NEMO_VIEW_DND_H__ */ nemo-4.4.2/src/nemo-view-factory.c000066400000000000000000000053461357442400300167770ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-view-factory.c: register and create NemoViews Copyright (C) 2004 Red Hat 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #include "nemo-view-factory.h" static GList *registered_views; void nemo_view_factory_register (NemoViewInfo *view_info) { g_return_if_fail (view_info != NULL); g_return_if_fail (view_info->id != NULL); g_return_if_fail (nemo_view_factory_lookup (view_info->id) == NULL); registered_views = g_list_append (registered_views, view_info); } const NemoViewInfo * nemo_view_factory_lookup (const char *id) { GList *l; NemoViewInfo *view_info; g_return_val_if_fail (id != NULL, NULL); for (l = registered_views; l != NULL; l = l->next) { view_info = l->data; if (strcmp (view_info->id, id) == 0) { return view_info; } } return NULL; } NemoView * nemo_view_factory_create (const char *id, NemoWindowSlot *slot) { const NemoViewInfo *view_info; NemoView *view; view_info = nemo_view_factory_lookup (id); if (view_info == NULL) { return NULL; } view = view_info->create (slot); if (g_object_is_floating (view)) { g_object_ref_sink (view); } return view; } gboolean nemo_view_factory_view_supports_uri (const char *id, GFile *location, GFileType file_type, const char *mime_type) { const NemoViewInfo *view_info; char *uri; gboolean res; view_info = nemo_view_factory_lookup (id); if (view_info == NULL) { return FALSE; } uri = g_file_get_uri (location); res = view_info->supports_uri (uri, file_type, mime_type); g_free (uri); return res; } GList * nemo_view_factory_get_views_for_uri (const char *uri, GFileType file_type, const char *mime_type) { GList *l, *res; const NemoViewInfo *view_info; res = NULL; for (l = registered_views; l != NULL; l = l->next) { view_info = l->data; if (view_info->supports_uri (uri, file_type, mime_type)) { res = g_list_prepend (res, g_strdup (view_info->id)); } } return g_list_reverse (res); } nemo-4.4.2/src/nemo-view-factory.h000066400000000000000000000047331357442400300170030ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-view-factory.h: register and create NemoViews Copyright (C) 2004 Red Hat 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Alexander Larsson */ #ifndef NEMO_VIEW_FACTORY_H #define NEMO_VIEW_FACTORY_H #include #include #include "nemo-view.h" #include "nemo-window-slot.h" G_BEGIN_DECLS typedef struct _NemoViewInfo NemoViewInfo; struct _NemoViewInfo { char *id; char *view_combo_label; /* Foo View (used in preferences dialog and navigation combo) */ char *view_menu_label_with_mnemonic; /* View -> _Foo (this is the "_Foo" part) */ char *error_label; /* The foo view encountered an error. */ char *startup_error_label; /* The foo view encountered an error while starting up. */ char *display_location_label; /* Display this location with the foo view. */ NemoView * (*create) (NemoWindowSlot *slot); /* BONOBOTODO: More args here */ gboolean (*supports_uri) (const char *uri, GFileType file_type, const char *mime_type); }; void nemo_view_factory_register (NemoViewInfo *view_info); const NemoViewInfo *nemo_view_factory_lookup (const char *id); NemoView * nemo_view_factory_create (const char *id, NemoWindowSlot *slot); gboolean nemo_view_factory_view_supports_uri (const char *id, GFile *location, GFileType file_type, const char *mime_type); GList * nemo_view_factory_get_views_for_uri (const char *uri, GFileType file_type, const char *mime_type); G_END_DECLS #endif /* NEMO_VIEW_FACTORY_H */ nemo-4.4.2/src/nemo-view.c000066400000000000000000012044641357442400300153350ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-view.c * * Copyright (C) 1999, 2000 Free Software Foundation * Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Ettore Perazzoli, * John Sullivan , * Darin Adler , * Pavel Cisler , * David Emory Watson */ #include #include "nemo-view.h" #include "nemo-actions.h" #include "nemo-desktop-icon-view.h" #include "nemo-error-reporting.h" #include "nemo-list-view.h" #include "nemo-mime-actions.h" #include "nemo-previewer.h" #include "nemo-properties-window.h" #include "nemo-bookmark-list.h" #include "nemo-directory-private.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_DIRECTORY_VIEW #include /* Minimum starting update inverval */ #define UPDATE_INTERVAL_MIN 50 /* Maximum update interval */ #define UPDATE_INTERVAL_MAX 2050 /* Amount of miliseconds the update interval is increased */ #define UPDATE_INTERVAL_INC 250 /* Interval at which the update interval is increased */ #define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250 /* Milliseconds that have to pass without a change to reset the update interval */ #define UPDATE_INTERVAL_RESET 1000 #define SILENT_WINDOW_OPEN_LIMIT 5 #define DUPLICATE_HORIZONTAL_ICON_OFFSET 70 #define DUPLICATE_VERTICAL_ICON_OFFSET 30 #define MAX_QUEUED_UPDATES 500 #define NEMO_VIEW_MENU_PATH_OPEN_PLACEHOLDER "/MenuBar/File/Open Placeholder" #define NEMO_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/MenuBar/File/Open Placeholder/Open With/Applications Placeholder" #define NEMO_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Applications Placeholder" #define NEMO_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Scripts/Scripts Placeholder" #define NEMO_VIEW_MENU_PATH_ACTIONS_PLACEHOLDER "/MenuBar/File/Open Placeholder/ActionsPlaceholder" #define NEMO_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER "/MenuBar/Edit/Extension Actions" #define NEMO_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER "/MenuBar/File/New Items Placeholder/New Documents/New Documents Placeholder" #define NEMO_VIEW_MENU_PATH_OPEN "/MenuBar/File/Open Placeholder/Open" #define NEMO_VIEW_POPUP_PATH_SELECTION "/selection" #define NEMO_VIEW_POPUP_PATH_OPEN_PLACEHOLDER "/selection/Open Placeholder" #define NEMO_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/selection/Open Placeholder/Open With/Applications Placeholder" #define NEMO_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER "/selection/Open Placeholder/Applications Placeholder" #define NEMO_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER "/selection/Open Placeholder/Scripts/Scripts Placeholder" #define NEMO_VIEW_POPUP_PATH_ACTIONS_PLACEHOLDER "/selection/Open Placeholder/ActionsPlaceholder" #define NEMO_VIEW_POPUP_PATH_EXTENSION_ACTIONS "/selection/Extension Actions" #define NEMO_VIEW_POPUP_PATH_OPEN "/selection/Open Placeholder/Open" #define NEMO_VIEW_POPUP_PATH_BACKGROUND "/background" #define NEMO_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/Scripts/Scripts Placeholder" #define NEMO_VIEW_POPUP_PATH_BACKGROUND_ACTIONS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/ActionsPlaceholder" #define NEMO_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/New Documents/New Documents Placeholder" #define NEMO_VIEW_POPUP_PATH_LOCATION "/location" #define NEMO_VIEW_POPUP_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER "/selection/File Actions/MoveToMenu/BookmarkMoveToPlaceHolder" #define NEMO_VIEW_POPUP_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER "/selection/File Actions/CopyToMenu/BookmarkCopyToPlaceHolder" #define NEMO_VIEW_MENU_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/MoveToMenu/BookmarkMoveToPlaceHolder" #define NEMO_VIEW_MENU_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/CopyToMenu/BookmarkCopyToPlaceHolder" #define NEMO_VIEW_POPUP_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER "/selection/File Actions/MoveToMenu/PlacesMoveToPlaceHolder" #define NEMO_VIEW_POPUP_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER "/selection/File Actions/CopyToMenu/PlacesCopyToPlaceHolder" #define NEMO_VIEW_MENU_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/MoveToMenu/PlacesMoveToPlaceHolder" #define NEMO_VIEW_MENU_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/CopyToMenu/PlacesCopyToPlaceHolder" #define MAX_MENU_LEVELS 5 #define TEMPLATE_LIMIT 30 enum { ADD_FILE, BEGIN_FILE_CHANGES, BEGIN_LOADING, CLEAR, END_FILE_CHANGES, END_LOADING, FILE_CHANGED, LOAD_ERROR, MOVE_COPY_ITEMS, REMOVE_FILE, ZOOM_LEVEL_CHANGED, SELECTION_CHANGED, TRASH, DELETE, LAST_SIGNAL }; enum { PROP_WINDOW_SLOT = 1, PROP_SUPPORTS_ZOOMING, NUM_PROPERTIES }; static guint signals[LAST_SIGNAL] = { 0 }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; static GdkAtom copied_files_atom; static char *scripts_directory_uri = NULL; static int scripts_directory_uri_length; struct NemoViewDetails { NemoWindow *window; NemoWindowSlot *slot; NemoDirectory *model; NemoFile *directory_as_file; NemoFile *location_popup_directory_as_file; NemoBookmarkList *bookmarks; GdkEventButton *location_popup_event; GtkActionGroup *dir_action_group; guint dir_merge_id; gboolean supports_zooming; GList *scripts_directory_list; GtkActionGroup *scripts_action_group; guint scripts_merge_id; GtkActionGroup *actions_action_group; guint actions_merge_id; guint action_manager_changed_id; NemoActionManager *action_manager; GList *templates_directory_list; GtkActionGroup *templates_action_group; guint templates_merge_id; GtkActionGroup *extensions_menu_action_group; guint extensions_menu_merge_id; guint display_selection_idle_id; guint update_menus_timeout_id; guint update_status_idle_id; guint reveal_selection_idle_id; guint display_pending_source_id; guint changes_timeout_id; guint update_interval; guint64 last_queued; guint files_added_handler_id; guint files_changed_handler_id; guint load_error_handler_id; guint done_loading_handler_id; guint file_changed_handler_id; guint delayed_rename_file_id; GList *new_added_files; GList *new_changed_files; GHashTable *non_ready_files; GList *old_added_files; GList *old_changed_files; GList *pending_selection; /* whether we are in the active slot */ gboolean active; /* loading indicates whether this view has begun loading a directory. * This flag should need not be set inside subclasses. NemoView automatically * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE * after it finishes loading the directory and its view. */ gboolean loading; gboolean menu_states_untrustworthy; gboolean scripts_invalid; gboolean templates_invalid; gboolean actions_invalid; gboolean reported_load_error; /* flag to indicate that no file updates should be dispatched to subclasses. * This is a workaround for bug #87701 that prevents the list view from * losing focus when the underlying GtkTreeView is updated. */ gboolean updates_frozen; guint updates_queued; gboolean needs_reload; gboolean is_renaming; gboolean sort_directories_first; gboolean show_foreign_files; gboolean show_hidden_files; gboolean ignore_hidden_file_preferences; gboolean batching_selection_level; gboolean selection_changed_while_batched; gboolean selection_was_removed; gboolean metadata_for_directory_as_file_pending; gboolean metadata_for_files_in_directory_pending; gboolean selection_change_is_due_to_shell; gboolean send_selection_change_to_shell; GtkActionGroup *open_with_action_group; guint open_with_merge_id; GList *subdirectory_list; guint copy_move_merge_ids[4]; GtkActionGroup *copy_move_action_groups[4]; guint bookmarks_changed_id; GdkPoint context_menu_position; gboolean showing_bookmarks_in_to_menus; gboolean showing_places_in_to_menus; GVolumeMonitor *volume_monitor; GTimer *load_timer; }; typedef struct { NemoFile *file; NemoDirectory *directory; } FileAndDirectory; /* forward declarations */ static gboolean display_selection_info_idle_callback (gpointer data); static void nemo_view_duplicate_selection (NemoView *view, GList *files, GArray *item_locations); static void nemo_view_create_links_for_files (NemoView *view, GList *files, GArray *item_locations); static void trash_or_delete_files (GtkWindow *parent_window, const GList *files, gboolean delete_if_all_already_in_trash, NemoView *view); static void load_directory (NemoView *view, NemoDirectory *directory); static void nemo_view_merge_menus (NemoView *view); static void nemo_view_unmerge_menus (NemoView *view); static void nemo_view_init_show_hidden_files (NemoView *view); static void clipboard_changed_callback (NemoClipboardMonitor *monitor, NemoView *view); static void open_one_in_new_window (gpointer data, gpointer callback_data); static void schedule_update_menus (NemoView *view); static void schedule_update_menus_callback (gpointer callback_data); static void remove_update_menus_timeout_callback (NemoView *view); static void schedule_update_status (NemoView *view); static void remove_update_status_idle_callback (NemoView *view); static void reset_update_interval (NemoView *view); static void schedule_idle_display_of_pending_files (NemoView *view); static void unschedule_display_of_pending_files (NemoView *view); static void disconnect_model_handlers (NemoView *view); static void metadata_for_directory_as_file_ready_callback (NemoFile *file, gpointer callback_data); static void metadata_for_files_in_directory_ready_callback (NemoDirectory *directory, GList *files, gpointer callback_data); static void nemo_view_trash_state_changed_callback (NemoTrashMonitor *trash, gboolean state, gpointer callback_data); static void nemo_view_select_file (NemoView *view, NemoFile *file); static void update_templates_directory (NemoView *view); static void user_dirs_changed (NemoView *view); static gboolean file_list_all_are_folders (GList *file_list); static void unschedule_pop_up_location_context_menu (NemoView *view); static void disconnect_bookmark_signals (NemoView *view); static void run_action_callback (NemoAction *action, gpointer callback_data); G_DEFINE_TYPE (NemoView, nemo_view, GTK_TYPE_SCROLLED_WINDOW); #define parent_class nemo_view_parent_class /* virtual methods (public and non-public) */ /** * nemo_view_merge_menus: * * Add this view's menus to the window's menu bar. * @view: NemoView in question. */ static void nemo_view_merge_menus (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->merge_menus (view); } static void nemo_view_unmerge_menus (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->unmerge_menus (view);} static char * real_get_backing_uri (NemoView *view) { NemoDirectory *directory; char *uri; g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); if (view->details->model == NULL) { return NULL; } directory = view->details->model; if (NEMO_IS_DESKTOP_DIRECTORY (directory)) { directory = nemo_desktop_directory_get_real_directory (NEMO_DESKTOP_DIRECTORY (directory)); } else { nemo_directory_ref (directory); } uri = nemo_directory_get_uri (directory); nemo_directory_unref (directory); return uri; } /** * * nemo_view_get_backing_uri: * * Returns the URI for the target location of new directory, new file, new * link and paste operations. */ char * nemo_view_get_backing_uri (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view); } /** * nemo_view_select_all: * * select all the items in the view * **/ static void nemo_view_select_all (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view); } static void nemo_view_call_set_selection (NemoView *view, GList *selection) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection); } static GList * nemo_view_get_selection_for_file_transfer (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view); } /** * nemo_view_get_selected_icon_locations: * * return an array of locations of selected icons if available * Return value: GArray of GdkPoints * **/ static GArray * nemo_view_get_selected_icon_locations (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selected_icon_locations (view); } static void nemo_view_invert_selection (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view); } /** * nemo_view_reveal_selection: * * Scroll as necessary to reveal the selected items. **/ static void nemo_view_reveal_selection (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view); } /** * nemo_view_reset_to_defaults: * * set sorting order, zoom level, etc. to match defaults * **/ static void nemo_view_reset_to_defaults (NemoView *view) { NemoFile *file; NemoWindow *window; g_return_if_fail (NEMO_IS_VIEW (view)); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reset_to_defaults (view); gboolean show_hidden = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES); window = view->details->window; if (show_hidden) { nemo_window_set_hidden_files_mode (window, NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE); } else { nemo_window_set_hidden_files_mode (window, NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE); } file = view->details->slot->viewed_file; nemo_file_set_metadata(file, NEMO_METADATA_KEY_SHOW_THUMBNAILS, NULL, NULL); nemo_file_set_metadata(file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL, NULL); gtk_action_activate (gtk_action_group_get_action (nemo_window_get_main_action_group (window), NEMO_ACTION_RELOAD)); } static gboolean nemo_view_using_manual_layout (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view); } static guint nemo_view_get_item_count (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), 0); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_item_count (view); } /** * nemo_view_can_rename_file * * Determine whether a file can be renamed. * @file: A NemoFile * * Return value: TRUE if @file can be renamed, FALSE otherwise. * **/ static gboolean nemo_view_can_rename_file (NemoView *view, NemoFile *file) { return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_rename_file (view, file); } static gboolean nemo_view_is_read_only (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view); } static gboolean showing_trash_directory (NemoView *view) { NemoFile *file; file = nemo_view_get_directory_as_file (view); if (file != NULL) { return nemo_file_is_in_trash (file); } return FALSE; } static gboolean showing_recent_directory (NemoView *view) { NemoFile *file; file = nemo_view_get_directory_as_file (view); if (file != NULL) { return nemo_file_is_in_recent (file); } return FALSE; } static gboolean nemo_view_supports_creating_files (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return !nemo_view_is_read_only (view) && !showing_trash_directory (view) && !showing_recent_directory (view); } static gboolean nemo_view_is_empty (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view); } /** * nemo_view_bump_zoom_level: * * bump the current zoom level by invoking the relevant subclass through the slot * **/ void nemo_view_bump_zoom_level (NemoView *view, int zoom_increment) { g_return_if_fail (NEMO_IS_VIEW (view)); if (!nemo_view_supports_zooming (view)) { return; } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment); } /** * nemo_view_zoom_to_level: * * Set the current zoom level by invoking the relevant subclass through the slot * **/ void nemo_view_zoom_to_level (NemoView *view, NemoZoomLevel zoom_level) { g_return_if_fail (NEMO_IS_VIEW (view)); if (!nemo_view_supports_zooming (view)) { return; } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->zoom_to_level (view, zoom_level); } NemoZoomLevel nemo_view_get_zoom_level (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NEMO_ZOOM_LEVEL_STANDARD); if (!nemo_view_supports_zooming (view)) { return NEMO_ZOOM_LEVEL_STANDARD; } return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level (view); } /** * nemo_view_can_zoom_in: * * Determine whether the view can be zoomed any closer. * @view: The zoomable NemoView. * * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise. * **/ gboolean nemo_view_can_zoom_in (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); if (!nemo_view_supports_zooming (view)) { return FALSE; } return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view); } /** * nemo_view_can_zoom_out: * * Determine whether the view can be zoomed any further away. * @view: The zoomable NemoView. * * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise. * **/ gboolean nemo_view_can_zoom_out (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); if (!nemo_view_supports_zooming (view)) { return FALSE; } return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view); } gboolean nemo_view_supports_zooming (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return view->details->supports_zooming; } /** * nemo_view_restore_default_zoom_level: * * restore to the default zoom level by invoking the relevant subclass through the slot * **/ void nemo_view_restore_default_zoom_level (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); if (!nemo_view_supports_zooming (view)) { return; } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view); } /* static NemoZoomLevel nemo_view_get_default_zoom_level (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); if (!nemo_view_supports_zooming (view)) { return -1; } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_default_zoom_level (view); } */ const char * nemo_view_get_view_id (NemoView *view) { return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (view); } char * nemo_view_get_first_visible_file (NemoView *view) { return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view); } void nemo_view_scroll_to_file (NemoView *view, const char *uri) { NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri); } /** * nemo_view_get_selection: * * Get a list of NemoFile pointers that represents the * currently-selected items in this view. Subclasses must override * the signal handler for the 'get_selection' signal. Callers are * responsible for g_free-ing the list (but not its data). * @view: NemoView whose selected items are of interest. * * Return value: GList of NemoFile pointers representing the selection. * **/ GList * nemo_view_get_selection (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view); } /** * nemo_view_peek_selection: * * Get a list of NemoFile pointers that represents the * currently-selected items in this view. Subclasses must override * the signal handler for the 'peek_selection' signal. The returned list * is owned by the view's icon container and should not be freed. * @view: NemoView whose selected items are of interest. * * Return value: GList of NemoFile pointers representing the selection. * **/ GList * nemo_view_peek_selection (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->peek_selection (view); } int nemo_view_get_selection_count (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), 0); return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_count (view); } /** * nemo_view_update_menus: * * Update the sensitivity and wording of dynamic menu items. * @view: NemoView in question. */ void nemo_view_update_menus (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); if (!view->details->active) { return; } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_menus (view); view->details->menu_states_untrustworthy = FALSE; } typedef struct { GAppInfo *application; GList *files; NemoView *directory_view; } ApplicationLaunchParameters; typedef struct { NemoFile *file; NemoView *directory_view; } ScriptLaunchParameters; typedef struct { NemoFile *file; NemoView *directory_view; } CreateTemplateParameters; typedef struct { NemoView *view; char *dest_uri; } BookmarkCallbackData; static BookmarkCallbackData * bookmark_callback_data_new (NemoView *view, gchar *uri) { BookmarkCallbackData *result; result = g_new0 (BookmarkCallbackData, 1); result->view = view; result->dest_uri = g_strdup(uri); return result; } static void bookmark_callback_data_free (BookmarkCallbackData *data) { g_free ((char *)data->dest_uri); g_free (data); } static ApplicationLaunchParameters * application_launch_parameters_new (GAppInfo *application, GList *files, NemoView *directory_view) { ApplicationLaunchParameters *result; result = g_new0 (ApplicationLaunchParameters, 1); result->application = g_object_ref (application); result->files = nemo_file_list_copy (files); if (directory_view != NULL) { g_object_ref (directory_view); result->directory_view = directory_view; } return result; } static void application_launch_parameters_free (ApplicationLaunchParameters *parameters) { g_object_unref (parameters->application); nemo_file_list_free (parameters->files); if (parameters->directory_view != NULL) { g_object_unref (parameters->directory_view); } g_free (parameters); } static GList * file_and_directory_list_to_files (GList *fad_list) { GList *res, *l; FileAndDirectory *fad; res = NULL; for (l = fad_list; l != NULL; l = l->next) { fad = l->data; res = g_list_prepend (res, nemo_file_ref (fad->file)); } return g_list_reverse (res); } static GList * file_and_directory_list_from_files (NemoDirectory *directory, GList *files) { GList *res, *l; FileAndDirectory *fad; res = NULL; for (l = files; l != NULL; l = l->next) { fad = g_new0 (FileAndDirectory, 1); fad->directory = nemo_directory_ref (directory); fad->file = nemo_file_ref (l->data); res = g_list_prepend (res, fad); } return g_list_reverse (res); } static void file_and_directory_free (FileAndDirectory *fad) { nemo_directory_unref (fad->directory); nemo_file_unref (fad->file); g_free (fad); } static void file_and_directory_list_free (GList *list) { GList *l; for (l = list; l != NULL; l = l->next) { file_and_directory_free (l->data); } g_list_free (list); } static gboolean file_and_directory_equal (gconstpointer v1, gconstpointer v2) { const FileAndDirectory *fad1, *fad2; fad1 = v1; fad2 = v2; return (fad1->file == fad2->file && fad1->directory == fad2->directory); } static guint file_and_directory_hash (gconstpointer v) { const FileAndDirectory *fad; fad = v; return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory); } static ScriptLaunchParameters * script_launch_parameters_new (NemoFile *file, NemoView *directory_view) { ScriptLaunchParameters *result; result = g_new0 (ScriptLaunchParameters, 1); g_object_ref (directory_view); result->directory_view = directory_view; nemo_file_ref (file); result->file = file; return result; } static void script_launch_parameters_free (ScriptLaunchParameters *parameters) { g_object_unref (parameters->directory_view); nemo_file_unref (parameters->file); g_free (parameters); } static CreateTemplateParameters * create_template_parameters_new (NemoFile *file, NemoView *directory_view) { CreateTemplateParameters *result; result = g_new0 (CreateTemplateParameters, 1); g_object_ref (directory_view); result->directory_view = directory_view; nemo_file_ref (file); result->file = file; return result; } static void create_templates_parameters_free (CreateTemplateParameters *parameters) { g_object_unref (parameters->directory_view); nemo_file_unref (parameters->file); g_free (parameters); } NemoWindow * nemo_view_get_nemo_window (NemoView *view) { g_assert (view->details->window != NULL); return view->details->window; } NemoWindowSlot * nemo_view_get_nemo_window_slot (NemoView *view) { g_assert (view->details->slot != NULL); return view->details->slot; } /* Returns the GtkWindow that this directory view occupies, or NULL * if at the moment this directory view is not in a GtkWindow or the * GtkWindow cannot be determined. Primarily used for parenting dialogs. */ static GtkWindow * nemo_view_get_containing_window (NemoView *view) { GtkWidget *window; g_assert (NEMO_IS_VIEW (view)); window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW); if (window == NULL) { return NULL; } return GTK_WINDOW (window); } static gboolean nemo_view_confirm_multiple (GtkWindow *parent_window, int count, gboolean tabs) { GtkDialog *dialog; char *prompt; char *detail; int response; if (count <= SILENT_WINDOW_OPEN_LIMIT) { return TRUE; } prompt = _("Are you sure you want to open all files?"); if (tabs) { detail = g_strdup_printf (ngettext("This will open %'d separate tab.", "This will open %'d separate tabs.", count), count); } else { detail = g_strdup_printf (ngettext("This will open %'d separate window.", "This will open %'d separate windows.", count), count); } dialog = eel_show_yes_no_dialog (prompt, detail, GTK_STOCK_OK, GTK_STOCK_CANCEL, parent_window); g_free (detail); response = gtk_dialog_run (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); return response == GTK_RESPONSE_YES; } static gboolean selection_contains_one_item_in_menu_callback (NemoView *view, GList *selection) { if (g_list_length (selection) == 1) { return TRUE; } /* If we've requested a menu update that hasn't yet occurred, then * the mismatch here doesn't surprise us, and we won't complain. * Otherwise, we will complain. */ if (!view->details->menu_states_untrustworthy) { g_warning ("Expected one selected item, found %'d. No action will be performed.", g_list_length (selection)); } return FALSE; } static gboolean selection_not_empty_in_menu_callback (NemoView *view, GList *selection) { if (selection != NULL) { return TRUE; } /* If we've requested a menu update that hasn't yet occurred, then * the mismatch here doesn't surprise us, and we won't complain. * Otherwise, we will complain. */ if (!view->details->menu_states_untrustworthy) { g_warning ("Empty selection found when selection was expected. No action will be performed."); } return FALSE; } static char * get_view_directory (NemoView *view) { char *uri, *path; GFile *f; uri = nemo_directory_get_uri (view->details->model); if (eel_uri_is_desktop (uri)) { g_free (uri); uri = nemo_get_desktop_directory_uri (); } f = g_file_new_for_uri (uri); path = g_file_get_path (f); g_object_unref (f); g_free (uri); return path; } static gboolean get_is_desktop_view (NemoView *view) { gchar *uri; gboolean ret; uri = nemo_directory_get_uri (view->details->model); ret = eel_uri_is_desktop (uri); g_free (uri); return ret; } void nemo_view_preview_files (NemoView *view, GList *files, GArray *locations) { NemoPreviewer *previewer; gchar *uri; guint xid; GtkWidget *toplevel; previewer = nemo_previewer_get_singleton (); uri = nemo_file_get_uri (files->data); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); xid = gdk_x11_window_get_xid (gtk_widget_get_window (toplevel)); nemo_previewer_call_show_file (previewer, uri, xid, TRUE); g_free (uri); } void nemo_view_activate_files (NemoView *view, GList *files, NemoWindowOpenFlags flags, gboolean confirm_multiple) { char *path; path = get_view_directory (view); nemo_mime_activate_files (nemo_view_get_containing_window (view), view->details->slot, files, path, flags, confirm_multiple); if (get_is_desktop_view(view)) { nemo_view_set_selection(view, NULL); } g_free (path); } void nemo_view_activate_file (NemoView *view, NemoFile *file, NemoWindowOpenFlags flags) { char *path; path = get_view_directory (view); nemo_mime_activate_file (nemo_view_get_containing_window (view), view->details->slot, file, path, flags); if (get_is_desktop_view(view)) { nemo_view_set_selection(view, NULL); } g_free (path); } static void action_open_callback (GtkAction *action, gpointer callback_data) { GList *selection; NemoView *view; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); nemo_view_activate_files (view, selection, 0, TRUE); nemo_file_list_free (selection); } static void action_open_close_parent_callback (GtkAction *action, gpointer callback_data) { GList *selection; NemoView *view; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); nemo_view_activate_files (view, selection, NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND, TRUE); nemo_file_list_free (selection); } static void action_open_alternate_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; GtkWindow *window; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); window = nemo_view_get_containing_window (view); if (nemo_view_confirm_multiple (window, g_list_length (selection), FALSE)) { g_list_foreach (selection, open_one_in_new_window, view); } nemo_file_list_free (selection); } static void action_open_new_tab_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; GtkWindow *window; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); window = nemo_view_get_containing_window (view); if (nemo_view_confirm_multiple (window, g_list_length (selection), TRUE)) { nemo_view_activate_files (view, selection, NEMO_WINDOW_OPEN_FLAG_NEW_TAB, FALSE); } nemo_file_list_free (selection); } static void app_chooser_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { GtkWindow *parent_window; NemoFile *file; GAppInfo *info; GList files; parent_window = user_data; if (response_id != GTK_RESPONSE_OK) { gtk_widget_destroy (GTK_WIDGET (dialog)); return; } GtkWidget *content = gtk_dialog_get_content_area (dialog); GList *children = gtk_container_get_children (GTK_CONTAINER (content)); NemoMimeApplicationChooser *chooser = children->data; g_list_free (children); info = nemo_mime_application_chooser_get_info (chooser); file = nemo_file_get_by_uri (nemo_mime_application_chooser_get_uri (chooser)); g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed"); files.next = NULL; files.prev = NULL; files.data = file; nemo_launch_application (info, &files, parent_window); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (info); } static void choose_program (NemoView *view, NemoFile *file) { GtkWidget *dialog; GtkWidget *ok_button; char *mime_type; char *uri = NULL; GList *uris = NULL; g_assert (NEMO_IS_VIEW (view)); g_assert (NEMO_IS_FILE (file)); mime_type = nemo_file_get_mime_type (file); uri = nemo_file_get_uri (file); dialog = gtk_dialog_new_with_buttons (_("Open with"), nemo_view_get_containing_window (view), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); GtkWidget *chooser = nemo_mime_application_chooser_new (uri, uris, mime_type, ok_button); GtkWidget *content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); gtk_box_pack_start (GTK_BOX (content), chooser, TRUE, TRUE, 0); gtk_widget_show_all (dialog); g_signal_connect_object (dialog, "response", G_CALLBACK (app_chooser_dialog_response_cb), nemo_view_get_containing_window (view), 0); } static void open_with_other_program (NemoView *view) { GList *selection; g_assert (NEMO_IS_VIEW (view)); selection = nemo_view_get_selection (view); if (selection_contains_one_item_in_menu_callback (view, selection)) { choose_program (view, NEMO_FILE (selection->data)); } nemo_file_list_free (selection); } static void action_other_application_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); open_with_other_program (NEMO_VIEW (callback_data)); } static void trash_or_delete_selected_files (NemoView *view) { GList *selection; /* This might be rapidly called multiple times for the same selection * when using keybindings. So we remember if the current selection * was already removed (but the view doesn't know about it yet). */ if (!view->details->selection_was_removed) { selection = nemo_view_get_selection_for_file_transfer (view); if (selection == NULL) { return; } trash_or_delete_files (nemo_view_get_containing_window (view), selection, TRUE, view); nemo_file_list_free (selection); view->details->selection_was_removed = TRUE; } } static gboolean real_trash (NemoView *view) { GtkAction *action; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_TRASH); if (gtk_action_get_sensitive (action) && gtk_action_get_visible (action)) { trash_or_delete_selected_files (view); return TRUE; } return FALSE; } static void action_trash_callback (GtkAction *action, gpointer callback_data) { trash_or_delete_selected_files (NEMO_VIEW (callback_data)); } static void delete_selected_files (NemoView *view) { GList *selection; GList *node; GList *locations; selection = nemo_view_get_selection_for_file_transfer (view); if (selection == NULL) { return; } locations = NULL; for (node = selection; node != NULL; node = node->next) { locations = g_list_prepend (locations, nemo_file_get_location ((NemoFile *) node->data)); } locations = g_list_reverse (locations); nemo_file_operations_delete (locations, nemo_view_get_containing_window (view), NULL, NULL); g_list_free_full (locations, g_object_unref); nemo_file_list_free (selection); } static void action_delete_callback (GtkAction *action, gpointer callback_data) { delete_selected_files (NEMO_VIEW (callback_data)); } static void action_restore_from_trash_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection_for_file_transfer (view); nemo_restore_files_from_trash (selection, nemo_view_get_containing_window (view)); nemo_file_list_free (selection); } static gboolean real_delete (NemoView *view) { GtkAction *action; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_DELETE); if (gtk_action_get_sensitive (action) && gtk_action_get_visible (action)) { delete_selected_files (view); return TRUE; } return FALSE; } static void action_duplicate_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; GArray *selected_item_locations; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection_for_file_transfer (view); if (selection_not_empty_in_menu_callback (view, selection)) { /* FIXME bugzilla.gnome.org 45061: * should change things here so that we use a get_icon_locations (view, selection). * Not a problem in this case but in other places the selection may change by * the time we go and retrieve the icon positions, relying on the selection * staying intact to ensure the right sequence and count of positions is fragile. */ selected_item_locations = nemo_view_get_selected_icon_locations (view); nemo_view_duplicate_selection (view, selection, selected_item_locations); g_array_free (selected_item_locations, TRUE); } nemo_file_list_free (selection); } static void action_create_link_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; GArray *selected_item_locations; g_assert (NEMO_IS_VIEW (callback_data)); view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (selection_not_empty_in_menu_callback (view, selection)) { selected_item_locations = nemo_view_get_selected_icon_locations (view); nemo_view_create_links_for_files (view, selection, selected_item_locations); g_array_free (selected_item_locations, TRUE); } nemo_file_list_free (selection); } static void action_pin_unpin_file_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; gboolean to_pin; g_assert (NEMO_IS_VIEW (callback_data)); view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (g_list_length (selection) < 1) { g_warning ("No selection to pin - why?"); return; } /* Apply pinning according to the current state of the first * selected file. ???*/ to_pin = !nemo_file_get_pinning (NEMO_FILE (selection->data)); if (selection_not_empty_in_menu_callback (view, selection)) { NemoFile *file; GList *iter; for (iter = selection; iter != NULL; iter = iter->next) { file = NEMO_FILE (iter->data); nemo_file_set_pinning (file, to_pin); } } nemo_file_list_free (selection); } static void action_select_all_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_select_all (callback_data); } static void action_invert_selection_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_invert_selection (callback_data); } static void pattern_select_response_cb (GtkWidget *dialog, int response, gpointer user_data) { NemoView *view; NemoDirectory *directory; GtkWidget *entry; GList *selection; GError *error; view = NEMO_VIEW (user_data); switch (response) { case GTK_RESPONSE_OK : entry = g_object_get_data (G_OBJECT (dialog), "entry"); directory = nemo_view_get_model (view); selection = nemo_directory_match_pattern (directory, gtk_entry_get_text (GTK_ENTRY (entry))); if (selection) { nemo_view_call_set_selection (view, selection); nemo_file_list_free (selection); nemo_view_reveal_selection(view); } /* fall through */ case GTK_RESPONSE_NONE : case GTK_RESPONSE_DELETE_EVENT : case GTK_RESPONSE_CANCEL : gtk_widget_destroy (GTK_WIDGET (dialog)); break; case GTK_RESPONSE_HELP : error = NULL; gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (dialog)), "help:gnome-help/files-select", gtk_get_current_event_time (), &error); if (error) { eel_show_error_dialog (_("There was an error displaying help."), error->message, GTK_WINDOW (dialog)); g_error_free (error); } break; default : g_assert_not_reached (); } } static void select_pattern (NemoView *view) { GtkWidget *dialog; GtkWidget *label; GtkWidget *example; GtkWidget *grid; GtkWidget *entry; char *example_pattern; dialog = gtk_dialog_new_with_buttons (_("Select Items Matching"), nemo_view_get_containing_window (view), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); label = gtk_label_new_with_mnemonic (_("_Pattern:")); gtk_widget_set_halign (label, GTK_ALIGN_START); example = gtk_label_new (NULL); gtk_widget_set_halign (example, GTK_ALIGN_START); example_pattern = g_strdup_printf ("%s%s ", _("Examples: "), "*.png, file\?\?.txt, pict*.\?\?\?"); gtk_label_set_markup (GTK_LABEL (example), example_pattern); g_free (example_pattern); entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); gtk_widget_set_hexpand (entry, TRUE); grid = gtk_grid_new (); g_object_set (grid, "orientation", GTK_ORIENTATION_VERTICAL, "border-width", 6, "row-spacing", 6, "column-spacing", 12, NULL); gtk_container_add (GTK_CONTAINER (grid), label); gtk_grid_attach_next_to (GTK_GRID (grid), entry, label, GTK_POS_RIGHT, 1, 1); gtk_grid_attach_next_to (GTK_GRID (grid), example, entry, GTK_POS_BOTTOM, 1, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); gtk_widget_show_all (grid); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid); g_object_set_data (G_OBJECT (dialog), "entry", entry); g_signal_connect (dialog, "response", G_CALLBACK (pattern_select_response_cb), view); gtk_widget_show_all (dialog); } static void action_select_pattern_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); select_pattern(callback_data); } static void action_reset_to_defaults_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_reset_to_defaults (callback_data); } static void hidden_files_mode_changed (NemoWindow *window, gpointer callback_data) { NemoView *directory_view; directory_view = NEMO_VIEW (callback_data); nemo_view_init_show_hidden_files (directory_view); } static void action_save_search_callback (GtkAction *action, gpointer callback_data) { NemoSearchDirectory *search; NemoView *directory_view; directory_view = NEMO_VIEW (callback_data); if (directory_view->details->model && NEMO_IS_SEARCH_DIRECTORY (directory_view->details->model)) { search = NEMO_SEARCH_DIRECTORY (directory_view->details->model); nemo_search_directory_save_search (search); /* Save search is disabled */ schedule_update_menus (directory_view); } } static void query_name_entry_changed_cb (GtkWidget *entry, GtkWidget *button) { const char *text; gboolean sensitive; text = gtk_entry_get_text (GTK_ENTRY (entry)); sensitive = (text != NULL) && (*text != 0); gtk_widget_set_sensitive (button, sensitive); } static void action_save_search_as_callback (GtkAction *action, gpointer callback_data) { NemoView *directory_view; NemoSearchDirectory *search; GtkWidget *dialog, *grid, *label, *entry, *chooser, *save_button; const char *entry_text; char *filename, *filename_utf8, *dirname, *path, *uri; GFile *location; directory_view = NEMO_VIEW (callback_data); if (directory_view->details->model && NEMO_IS_SEARCH_DIRECTORY (directory_view->details->model)) { search = NEMO_SEARCH_DIRECTORY (directory_view->details->model); dialog = gtk_dialog_new_with_buttons (_("Save Search as"), nemo_view_get_containing_window (directory_view), 0, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); save_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); grid = gtk_grid_new (); g_object_set (grid, "orientation", GTK_ORIENTATION_VERTICAL, "border-width", 5, "row-spacing", 6, "column-spacing", 12, NULL); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0); gtk_widget_show (grid); label = gtk_label_new_with_mnemonic (_("Search _name:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_widget_show (label); entry = gtk_entry_new (); gtk_widget_set_hexpand (entry, TRUE); gtk_grid_attach_next_to (GTK_GRID (grid), entry, label, GTK_POS_RIGHT, 1, 1); gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); gtk_widget_set_sensitive (save_button, FALSE); g_signal_connect (entry, "changed", G_CALLBACK (query_name_entry_changed_cb), save_button); gtk_widget_show (entry); label = gtk_label_new_with_mnemonic (_("_Folder:")); gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (grid), label); gtk_widget_show (label); chooser = gtk_file_chooser_button_new (_("Select Folder to Save Search In"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); gtk_widget_set_hexpand (chooser, TRUE); gtk_grid_attach_next_to (GTK_GRID (grid), chooser, label, GTK_POS_RIGHT, 1, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser); gtk_widget_show (chooser); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), g_get_home_dir ()); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); if (g_str_has_suffix (entry_text, NEMO_SAVED_SEARCH_EXTENSION)) { filename_utf8 = g_strdup (entry_text); } else { filename_utf8 = g_strconcat (entry_text, NEMO_SAVED_SEARCH_EXTENSION, NULL); } filename = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL); g_free (filename_utf8); dirname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); path = g_build_filename (dirname, filename, NULL); g_free (filename); g_free (dirname); uri = g_filename_to_uri (path, NULL, NULL); g_free (path); nemo_search_directory_save_to_file (search, uri); location = g_file_new_for_uri (uri); nemo_file_changes_queue_file_added (location); g_object_unref (location); nemo_file_changes_consume_changes (TRUE); g_free (uri); } gtk_widget_destroy (dialog); } } static void action_empty_trash_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_file_operations_empty_trash (GTK_WIDGET (callback_data)); } typedef struct { NemoView *view; NemoFile *new_file; } RenameData; static gboolean delayed_rename_file_hack_callback (RenameData *data) { NemoView *view; NemoFile *new_file; view = data->view; new_file = data->new_file; if (view->details->window != NULL && view->details->active) { NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE); nemo_view_reveal_selection (view); } view->details->delayed_rename_file_id = 0; return FALSE; } static void delayed_rename_file_hack_removed (RenameData *data) { g_object_unref (data->view); nemo_file_unref (data->new_file); g_free (data); } static void rename_file (NemoView *view, NemoFile *new_file) { RenameData *data; /* HACK!!!! This is a work around bug in listview. After the rename is enabled we will get file changes due to info about the new file being read, which will cause the model to change. When the model changes GtkTreeView clears the editing. This hack just delays editing for some time to try to avoid this problem. A major problem is that the selection of the row causes us to load the slow mimetype for the file, which leads to a file_changed. So, before we delay we select the row. */ if (NEMO_IS_LIST_VIEW (view)) { nemo_view_select_file (view, new_file); data = g_new (RenameData, 1); data->view = g_object_ref (view); data->new_file = nemo_file_ref (new_file); if (view->details->delayed_rename_file_id != 0) { g_source_remove (view->details->delayed_rename_file_id); } view->details->delayed_rename_file_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 100, (GSourceFunc)delayed_rename_file_hack_callback, data, (GDestroyNotify) delayed_rename_file_hack_removed); return; } /* no need to select because start_renaming_file selects * nemo_view_select_file (view, new_file); */ NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE); nemo_view_reveal_selection (view); } static void reveal_newly_added_folder (NemoView *view, NemoFile *new_file, NemoDirectory *directory, GFile *target_location) { GFile *location; location = nemo_file_get_location (new_file); if (g_file_equal (location, target_location)) { g_signal_handlers_disconnect_by_func (view, G_CALLBACK (reveal_newly_added_folder), (void *) target_location); rename_file (view, new_file); } g_object_unref (location); } typedef struct { NemoView *directory_view; GHashTable *added_locations; } NewFolderData; static void track_newly_added_locations (NemoView *view, NemoFile *new_file, NemoDirectory *directory, gpointer user_data) { NewFolderData *data; data = user_data; g_hash_table_insert (data->added_locations, nemo_file_get_location (new_file), NULL); } static void new_folder_done (GFile *new_folder, gboolean success, gpointer user_data) { NemoView *directory_view; NemoFile *file; char screen_string[32]; GdkScreen *screen; NewFolderData *data; data = (NewFolderData *)user_data; directory_view = data->directory_view; if (directory_view == NULL) { goto fail; } g_signal_handlers_disconnect_by_func (directory_view, G_CALLBACK (track_newly_added_locations), (void *) data); if (new_folder == NULL) { goto fail; } screen = gtk_widget_get_screen (GTK_WIDGET (directory_view)); g_snprintf (screen_string, sizeof (screen_string), "%d", gdk_screen_get_number (screen)); file = nemo_file_get (new_folder); if (g_hash_table_lookup_extended (data->added_locations, new_folder, NULL, NULL)) { /* The file was already added */ rename_file (directory_view, file); } else { /* We need to run after the default handler adds the folder we want to * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we * must use connect_after. */ g_signal_connect_data (directory_view, "add_file", G_CALLBACK (reveal_newly_added_folder), g_object_ref (new_folder), (GClosureNotify)g_object_unref, G_CONNECT_AFTER); } nemo_file_unref (file); fail: g_hash_table_destroy (data->added_locations); if (data->directory_view != NULL) { g_object_remove_weak_pointer (G_OBJECT (data->directory_view), (gpointer *) &data->directory_view); } g_free (data); } static NewFolderData * new_folder_data_new (NemoView *directory_view) { NewFolderData *data; data = g_new (NewFolderData, 1); data->directory_view = directory_view; data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); g_object_add_weak_pointer (G_OBJECT (data->directory_view), (gpointer *) &data->directory_view); return data; } static GdkPoint * context_menu_to_file_operation_position (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); if (nemo_view_using_manual_layout (view) && view->details->context_menu_position.x >= 0 && view->details->context_menu_position.y >= 0) { NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->widget_to_file_operation_position (view, &view->details->context_menu_position); return &view->details->context_menu_position; } else { return NULL; } } void nemo_view_new_folder (NemoView *view) { char *parent_uri; NewFolderData *data; GdkPoint *pos; data = new_folder_data_new (view); g_signal_connect_data (view, "add_file", G_CALLBACK (track_newly_added_locations), data, (GClosureNotify)NULL, G_CONNECT_AFTER); pos = context_menu_to_file_operation_position (view); parent_uri = nemo_view_get_backing_uri (view); nemo_file_operations_new_folder (GTK_WIDGET (view), pos, parent_uri, new_folder_done, data); g_free (parent_uri); } static NewFolderData * setup_new_folder_data (NemoView *directory_view) { NewFolderData *data; data = new_folder_data_new (directory_view); g_signal_connect_data (directory_view, "add_file", G_CALLBACK (track_newly_added_locations), data, (GClosureNotify)NULL, G_CONNECT_AFTER); return data; } void nemo_view_new_file_with_initial_contents (NemoView *view, const char *parent_uri, const char *filename, const char *initial_contents, int length, GdkPoint *pos) { NewFolderData *data; g_assert (parent_uri != NULL); data = setup_new_folder_data (view); if (pos == NULL) { pos = context_menu_to_file_operation_position (view); } nemo_file_operations_new_file (GTK_WIDGET (view), pos, parent_uri, filename, initial_contents, length, new_folder_done, data); } static void nemo_view_new_file (NemoView *directory_view, const char *parent_uri, NemoFile *source) { GdkPoint *pos; NewFolderData *data; char *source_uri; char *container_uri; container_uri = NULL; if (parent_uri == NULL) { container_uri = nemo_view_get_backing_uri (directory_view); g_assert (container_uri != NULL); } if (source == NULL) { nemo_view_new_file_with_initial_contents (directory_view, parent_uri != NULL ? parent_uri : container_uri, NULL, NULL, 0, NULL); g_free (container_uri); return; } g_return_if_fail (nemo_file_is_local (source)); pos = context_menu_to_file_operation_position (directory_view); data = setup_new_folder_data (directory_view); source_uri = nemo_file_get_uri (source); nemo_file_operations_new_file_from_template (GTK_WIDGET (directory_view), pos, parent_uri != NULL ? parent_uri : container_uri, NULL, source_uri, new_folder_done, data); g_free (source_uri); g_free (container_uri); } static void action_new_folder_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_new_folder (NEMO_VIEW (callback_data)); } static void action_new_empty_file_callback (GtkAction *action, gpointer callback_data) { g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_new_file (NEMO_VIEW (callback_data), NULL, NULL); } static void action_properties_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; GList *files; g_assert (NEMO_IS_VIEW (callback_data)); view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (g_list_length (selection) == 0) { if (view->details->directory_as_file != NULL) { files = g_list_append (NULL, nemo_file_ref (view->details->directory_as_file)); nemo_properties_window_present (files, GTK_WIDGET (view), NULL); nemo_file_list_free (files); } } else { nemo_properties_window_present (selection, GTK_WIDGET (view), NULL); } nemo_file_list_free (selection); } static void action_location_properties_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *files; g_assert (NEMO_IS_VIEW (callback_data)); view = NEMO_VIEW (callback_data); g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file)); files = g_list_append (NULL, nemo_file_ref (view->details->location_popup_directory_as_file)); nemo_properties_window_present (files, GTK_WIDGET (view), NULL); nemo_file_list_free (files); } static gboolean all_files_in_trash (GList *files) { GList *node; /* Result is ambiguous if called on NULL, so disallow. */ g_return_val_if_fail (files != NULL, FALSE); for (node = files; node != NULL; node = node->next) { if (!nemo_file_is_in_trash (NEMO_FILE (node->data))) { return FALSE; } } return TRUE; } static gboolean all_selected_items_in_trash (NemoView *view, GList *selection) { gboolean result; /* If the contents share a parent directory, we need only * check that parent directory. Otherwise we have to inspect * each selected item. */ result = (selection == NULL) ? FALSE : all_files_in_trash (selection); return result; } static void click_policy_changed_callback (gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_policy_changed (view); } static void click_to_rename_changed_callback (gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_to_rename_mode_changed (view); } static void nemo_to_menu_preferences_changed_callback (NemoView *view) { view->details->showing_bookmarks_in_to_menus = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS); view->details->showing_places_in_to_menus = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS); } gboolean nemo_view_should_sort_directories_first (NemoView *view) { return view->details->sort_directories_first; } static void sort_directories_first_changed_callback (gpointer callback_data) { NemoView *view; gboolean preference_value; view = NEMO_VIEW (callback_data); preference_value = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST); if (preference_value != view->details->sort_directories_first) { view->details->sort_directories_first = preference_value; return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->sort_directories_first_changed (view); } } static void swap_delete_keybinding_changed_callback (gpointer callback_data) { GtkBindingSet *binding_set = gtk_binding_set_find ("NemoView"); gboolean swap_keys = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SWAP_TRASH_DELETE); gtk_binding_entry_remove (binding_set, GDK_KEY_Delete, 0); gtk_binding_entry_remove (binding_set, GDK_KEY_KP_Delete, 0); gtk_binding_entry_remove (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK); gtk_binding_entry_remove (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK); if (swap_keys) { gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "trash", 0); } else { gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "delete", 0); } } static gboolean set_up_scripts_directory_global (void) { char *scripts_directory_path; if (scripts_directory_uri != NULL) { return TRUE; } scripts_directory_path = nemo_get_scripts_directory_path (); if (g_mkdir_with_parents (scripts_directory_path, 0755) == 0) { scripts_directory_uri = g_filename_to_uri (scripts_directory_path, NULL, NULL); scripts_directory_uri_length = strlen (scripts_directory_uri); } g_free (scripts_directory_path); return (scripts_directory_uri != NULL) ? TRUE : FALSE; } static void scripts_added_or_changed_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); view->details->scripts_invalid = TRUE; if (view->details->active) { schedule_update_menus (view); } } static void templates_added_or_changed_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); view->details->templates_invalid = TRUE; if (view->details->active) { schedule_update_menus (view); } } static void actions_added_or_changed_callback (NemoView *view) { view->details->actions_invalid = TRUE; if (view->details->active) { schedule_update_menus (view); } } static void add_directory_to_directory_list (NemoView *view, NemoDirectory *directory, GList **directory_list, GCallback changed_callback) { NemoFileAttributes attributes; if (g_list_find (*directory_list, directory) == NULL) { nemo_directory_ref (directory); attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT; nemo_directory_file_monitor_add (directory, directory_list, FALSE, attributes, (NemoDirectoryCallback)changed_callback, view); g_signal_connect_object (directory, "files_added", G_CALLBACK (changed_callback), view, 0); g_signal_connect_object (directory, "files_changed", G_CALLBACK (changed_callback), view, 0); *directory_list = g_list_append (*directory_list, directory); } } static void remove_directory_from_directory_list (NemoView *view, NemoDirectory *directory, GList **directory_list, GCallback changed_callback) { *directory_list = g_list_remove (*directory_list, directory); g_signal_handlers_disconnect_by_func (directory, G_CALLBACK (changed_callback), view); nemo_directory_file_monitor_remove (directory, directory_list); nemo_directory_unref (directory); } static void add_directory_to_scripts_directory_list (NemoView *view, NemoDirectory *directory) { add_directory_to_directory_list (view, directory, &view->details->scripts_directory_list, G_CALLBACK (scripts_added_or_changed_callback)); } static void remove_directory_from_scripts_directory_list (NemoView *view, NemoDirectory *directory) { remove_directory_from_directory_list (view, directory, &view->details->scripts_directory_list, G_CALLBACK (scripts_added_or_changed_callback)); } static void add_directory_to_templates_directory_list (NemoView *view, NemoDirectory *directory) { add_directory_to_directory_list (view, directory, &view->details->templates_directory_list, G_CALLBACK (templates_added_or_changed_callback)); } static void remove_directory_from_templates_directory_list (NemoView *view, NemoDirectory *directory) { remove_directory_from_directory_list (view, directory, &view->details->templates_directory_list, G_CALLBACK (templates_added_or_changed_callback)); } static void slot_active (NemoWindowSlot *slot, NemoView *view) { if (view->details->active) { return; } view->details->active = TRUE; nemo_view_merge_menus (view); schedule_update_menus (view); } static void slot_inactive (NemoWindowSlot *slot, NemoView *view) { if (!view->details->active) { return; } view->details->active = FALSE; nemo_view_unmerge_menus (view); remove_update_menus_timeout_callback (view); } static void slot_changed_pane (NemoWindowSlot *slot, NemoView *view) { g_signal_handlers_disconnect_matched (view->details->window, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view); view->details->window = nemo_window_slot_get_window (slot); schedule_update_menus (view); g_signal_connect_object (view->details->window, "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed), view, 0); hidden_files_mode_changed (view->details->window, view); } static void plugin_prefs_changed (GSettings *settings, gchar *key, gpointer user_data) { scripts_added_or_changed_callback (NULL, NULL, user_data); } void nemo_view_grab_focus (NemoView *view) { /* focus the child of the scrolled window if it exists */ GtkWidget *child; child = gtk_bin_get_child (GTK_BIN (view)); if (child) { gtk_widget_grab_focus (GTK_WIDGET (child)); } } static void update_undo_actions (NemoView *view) { NemoFileUndoInfo *info; NemoFileUndoManagerState undo_state; GtkAction *action; const gchar *label, *tooltip; gboolean available; gboolean undo_active, redo_active; gchar *undo_label, *undo_description, *redo_label, *redo_description; undo_label = undo_description = redo_label = redo_description = NULL; undo_active = FALSE; redo_active = FALSE; info = nemo_file_undo_manager_get_action (); undo_state = nemo_file_undo_manager_get_state (); if (info != NULL && (undo_state > NEMO_FILE_UNDO_MANAGER_STATE_NONE)) { if (undo_state == NEMO_FILE_UNDO_MANAGER_STATE_UNDO) { undo_active = TRUE; } else { redo_active = TRUE; } nemo_file_undo_info_get_strings (info, &undo_label, &undo_description, &redo_label, &redo_description); } /* Update undo entry */ action = gtk_action_group_get_action (view->details->dir_action_group, "Undo"); available = undo_active; if (available) { label = undo_label; tooltip = undo_description; } else { /* Reset to default info */ label = _("Undo"); tooltip = _("Undo last action"); } g_object_set (action, "label", label, "tooltip", tooltip, NULL); gtk_action_set_sensitive (action, available); /* Update redo entry */ action = gtk_action_group_get_action (view->details->dir_action_group, "Redo"); available = redo_active; if (available) { label = redo_label; tooltip = redo_description; } else { /* Reset to default info */ label = _("Redo"); tooltip = _("Redo last undone action"); } g_object_set (action, "label", label, "tooltip", tooltip, NULL); gtk_action_set_sensitive (action, available); g_free (undo_label); g_free (undo_description); g_free (redo_label); g_free (redo_description); } static void undo_manager_changed_cb (NemoFileUndoManager* manager, NemoView *view) { if (view->details->dir_action_group == NULL) { return; } update_undo_actions (view); } void nemo_view_set_selection (NemoView *nemo_view, GList *selection) { NemoView *view; view = NEMO_VIEW (nemo_view); if (!view->details->loading) { /* If we aren't still loading, set the selection right now, * and reveal the new selection. */ view->details->selection_change_is_due_to_shell = TRUE; nemo_view_call_set_selection (view, selection); view->details->selection_change_is_due_to_shell = FALSE; nemo_view_reveal_selection (view); } else { /* If we are still loading, set the list of pending URIs instead. * done_loading() will eventually select the pending URIs and reveal them. */ g_list_free_full (view->details->pending_selection, g_object_unref); view->details->pending_selection = eel_g_object_list_copy (selection); } } static char * get_bulk_rename_tool (void) { char *bulk_rename_tool; g_settings_get (nemo_preferences, NEMO_PREFERENCES_BULK_RENAME_TOOL, "^ay", &bulk_rename_tool); return g_strstrip (bulk_rename_tool); } static gboolean have_bulk_rename_tool (void) { char *bulk_rename_tool; gboolean have_tool; bulk_rename_tool = get_bulk_rename_tool (); have_tool = ((bulk_rename_tool != NULL) && (*bulk_rename_tool != '\0')); g_free (bulk_rename_tool); return have_tool; } static void nemo_view_init (NemoView *view) { AtkObject *atk_object; NemoDirectory *scripts_directory; NemoDirectory *templates_directory; char *templates_uri; NemoFileUndoManager* manager; view->details = G_TYPE_INSTANCE_GET_PRIVATE (view, NEMO_TYPE_VIEW, NemoViewDetails); view->details->load_timer = g_timer_new (); /* Default to true; desktop-icon-view sets to false */ view->details->show_foreign_files = TRUE; view->details->non_ready_files = g_hash_table_new_full (file_and_directory_hash, file_and_directory_equal, (GDestroyNotify)file_and_directory_free, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL); gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_NONE); gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (view)), GTK_JUNCTION_TOP | GTK_JUNCTION_LEFT); if (set_up_scripts_directory_global ()) { scripts_directory = nemo_directory_get_by_uri (scripts_directory_uri); add_directory_to_scripts_directory_list (view, scripts_directory); nemo_directory_unref (scripts_directory); } else { g_warning ("Ignoring scripts directory, it may be a broken link\n"); } if (nemo_should_use_templates_directory ()) { templates_uri = nemo_get_templates_directory_uri (); templates_directory = nemo_directory_get_by_uri (templates_uri); g_free (templates_uri); add_directory_to_templates_directory_list (view, templates_directory); nemo_directory_unref (templates_directory); } update_templates_directory (view); g_signal_connect_object (nemo_signaller_get_current (), "user_dirs_changed", G_CALLBACK (user_dirs_changed), view, G_CONNECT_SWAPPED); view->details->sort_directories_first = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST); g_signal_connect_object (nemo_trash_monitor_get (), "trash_state_changed", G_CALLBACK (nemo_view_trash_state_changed_callback), view, 0); /* React to clipboard changes */ g_signal_connect_object (nemo_clipboard_monitor_get (), "clipboard_changed", G_CALLBACK (clipboard_changed_callback), view, 0); /* Register to menu provider extension signal managing menu updates */ g_signal_connect_object (nemo_signaller_get_current (), "popup_menu_changed", G_CALLBACK (nemo_view_update_menus), view, G_CONNECT_SWAPPED); gtk_widget_show (GTK_WIDGET (view)); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_ENABLE_DELETE, G_CALLBACK (schedule_update_menus_callback), view); g_signal_connect_swapped (nemo_menu_config_preferences, "changed", G_CALLBACK (schedule_update_menus_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SWAP_TRASH_DELETE, G_CALLBACK (swap_delete_keybinding_changed_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_CLICK_POLICY, G_CALLBACK(click_policy_changed_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_CLICK_TO_RENAME, G_CALLBACK(click_to_rename_changed_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST, G_CALLBACK(sort_directories_first_changed_callback), view); g_signal_connect_swapped (gnome_lockdown_preferences, "changed::" NEMO_PREFERENCES_LOCKDOWN_COMMAND_LINE, G_CALLBACK (schedule_update_menus), view); g_signal_connect_swapped (nemo_window_state, "changed::" NEMO_WINDOW_STATE_START_WITH_STATUS_BAR, G_CALLBACK (nemo_view_display_selection_info), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS, G_CALLBACK (nemo_to_menu_preferences_changed_callback), view); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS, G_CALLBACK (nemo_to_menu_preferences_changed_callback), view); nemo_to_menu_preferences_changed_callback (view); manager = nemo_file_undo_manager_get (); g_signal_connect_object (manager, "undo-changed", G_CALLBACK (undo_manager_changed_cb), view, 0); g_signal_connect (nemo_plugin_preferences, "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS, G_CALLBACK (plugin_prefs_changed), view); /* Accessibility */ atk_object = gtk_widget_get_accessible (GTK_WIDGET (view)); atk_object_set_name (atk_object, _("Content View")); atk_object_set_description (atk_object, _("View of the current folder")); view->details->action_manager = nemo_action_manager_new (); view->details->action_manager_changed_id = g_signal_connect_swapped (view->details->action_manager, "changed", G_CALLBACK (actions_added_or_changed_callback), view); view->details->bookmarks = nemo_bookmark_list_get_default (); view->details->bookmarks_changed_id = g_signal_connect_swapped (view->details->bookmarks, "changed", G_CALLBACK (schedule_update_menus), view); } static void disconnect_action_activate (NemoAction *action, NemoView *view) { g_signal_handlers_disconnect_by_func (action, run_action_callback, view); } static void real_unmerge_menus (NemoView *view) { GtkUIManager *ui_manager; if (view->details->window == NULL) { return; } if (GTK_IS_ACTION_GROUP (view->details->copy_move_action_groups[0])) { disconnect_bookmark_signals (view); } ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->dir_merge_id, &view->details->dir_action_group); nemo_ui_unmerge_ui (ui_manager, &view->details->extensions_menu_merge_id, &view->details->extensions_menu_action_group); nemo_ui_unmerge_ui (ui_manager, &view->details->open_with_merge_id, &view->details->open_with_action_group); nemo_ui_unmerge_ui (ui_manager, &view->details->scripts_merge_id, &view->details->scripts_action_group); nemo_ui_unmerge_ui (ui_manager, &view->details->templates_merge_id, &view->details->templates_action_group); if (view->details->actions_action_group) { GList *action_list; action_list = gtk_action_group_list_actions (view->details->actions_action_group); g_list_foreach (action_list, (GFunc) disconnect_action_activate, view); g_list_free (action_list); } nemo_ui_unmerge_ui (ui_manager, &view->details->actions_merge_id, &view->details->actions_action_group); int i; for (i = 0; i < 4; i++) { nemo_ui_unmerge_ui (ui_manager, &view->details->copy_move_merge_ids[i], &view->details->copy_move_action_groups[i]); } } static void nemo_view_destroy (GtkWidget *object) { NemoView *view; GList *node, *next; view = NEMO_VIEW (object); disconnect_model_handlers (view); if (view->details->bookmarks_changed_id != 0) { g_signal_handler_disconnect (view->details->bookmarks, view->details->bookmarks_changed_id); view->details->bookmarks_changed_id = 0; } if (view->details->action_manager_changed_id != 0) { g_signal_handler_disconnect (view->details->action_manager, view->details->action_manager_changed_id); view->details->action_manager_changed_id = 0; } g_clear_object (&view->details->action_manager); nemo_view_unmerge_menus (view); /* We don't own the window, so no unref */ view->details->slot = NULL; view->details->window = NULL; nemo_view_stop_loading (view); for (node = view->details->scripts_directory_list; node != NULL; node = next) { next = node->next; remove_directory_from_scripts_directory_list (view, node->data); } for (node = view->details->templates_directory_list; node != NULL; node = next) { next = node->next; remove_directory_from_templates_directory_list (view, node->data); } while (view->details->subdirectory_list != NULL) { nemo_view_remove_subdirectory (view, view->details->subdirectory_list->data); } remove_update_menus_timeout_callback (view); remove_update_status_idle_callback (view); if (view->details->display_selection_idle_id != 0) { g_source_remove (view->details->display_selection_idle_id); view->details->display_selection_idle_id = 0; } if (view->details->reveal_selection_idle_id != 0) { g_source_remove (view->details->reveal_selection_idle_id); view->details->reveal_selection_idle_id = 0; } if (view->details->delayed_rename_file_id != 0) { g_source_remove (view->details->delayed_rename_file_id); view->details->delayed_rename_file_id = 0; } if (view->details->model) { nemo_directory_unref (view->details->model); view->details->model = NULL; } if (view->details->directory_as_file) { nemo_file_unref (view->details->directory_as_file); view->details->directory_as_file = NULL; } g_signal_handlers_disconnect_by_func (nemo_plugin_preferences, G_CALLBACK (plugin_prefs_changed), view); GTK_WIDGET_CLASS (nemo_view_parent_class)->destroy (object); } static void nemo_view_finalize (GObject *object) { NemoView *view; view = NEMO_VIEW (object); g_signal_handlers_disconnect_by_func (nemo_preferences, schedule_update_menus_callback, view); g_signal_handlers_disconnect_by_func (nemo_preferences, click_policy_changed_callback, view); g_signal_handlers_disconnect_by_func (nemo_preferences, click_to_rename_changed_callback, view); g_signal_handlers_disconnect_by_func (nemo_preferences, sort_directories_first_changed_callback, view); g_signal_handlers_disconnect_by_func (nemo_window_state, nemo_view_display_selection_info, view); g_signal_handlers_disconnect_by_func (nemo_menu_config_preferences, schedule_update_menus_callback, view); g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences, schedule_update_menus, view); g_signal_handlers_disconnect_by_func (nemo_preferences, nemo_to_menu_preferences_changed_callback, view); g_signal_handlers_disconnect_by_func (nemo_preferences, schedule_update_menus, view); unschedule_pop_up_location_context_menu (view); if (view->details->location_popup_event != NULL) { gdk_event_free ((GdkEvent *) view->details->location_popup_event); } g_clear_pointer (&view->details->load_timer, g_timer_destroy); g_hash_table_destroy (view->details->non_ready_files); G_OBJECT_CLASS (nemo_view_parent_class)->finalize (object); } /** * nemo_view_display_selection_info: * * Display information about the current selection, and notify the view frame of the changed selection. * @view: NemoView for which to display selection info. * **/ void nemo_view_display_selection_info (NemoView *view) { GList *selection; goffset non_folder_size; gboolean non_folder_size_known; guint non_folder_count, folder_count, folder_item_count; gboolean folder_item_count_known; guint file_item_count; GList *p; char *first_item_name; char *non_folder_str; char *folder_count_str; char *folder_item_count_str; char *status_string; char *view_status_string; char *free_space_str; char *obj_selected_free_space_str; NemoFile *file; g_return_if_fail (NEMO_IS_VIEW (view)); selection = nemo_file_list_ref (nemo_view_peek_selection (view)); folder_item_count_known = TRUE; folder_count = 0; folder_item_count = 0; non_folder_count = 0; non_folder_size_known = FALSE; non_folder_size = 0; first_item_name = NULL; folder_count_str = NULL; non_folder_str = NULL; folder_item_count_str = NULL; free_space_str = NULL; obj_selected_free_space_str = NULL; status_string = NULL; view_status_string = NULL; for (p = selection; p != NULL; p = p->next) { file = p->data; if (nemo_file_is_directory (file)) { folder_count++; if (nemo_file_get_directory_item_count (file, &file_item_count, NULL)) { folder_item_count += file_item_count; } else { folder_item_count_known = FALSE; } } else { non_folder_count++; if (!nemo_file_can_get_size (file)) { non_folder_size_known = TRUE; non_folder_size += nemo_file_get_size (file); } } if (first_item_name == NULL) { first_item_name = nemo_file_get_display_name (file); } } nemo_file_list_unref (selection); /* Break out cases for localization's sake. But note that there are still pieces * being assembled in a particular order, which may be a problem for some localizers. */ if (folder_count != 0) { if (folder_count == 1 && non_folder_count == 0) { folder_count_str = g_strdup_printf (_("\"%s\" selected"), first_item_name); } else { folder_count_str = g_strdup_printf (ngettext("%'d folder selected", "%'d folders selected", folder_count), folder_count); } if (folder_count == 1) { if (!folder_item_count_known) { folder_item_count_str = g_strdup (""); } else { folder_item_count_str = g_strdup_printf (ngettext(" (containing %'d item)", " (containing %'d items)", folder_item_count), folder_item_count); } } else { if (!folder_item_count_known) { folder_item_count_str = g_strdup (""); } else { /* translators: this is preceded with a string of form 'N folders' (N more than 1) */ folder_item_count_str = g_strdup_printf (ngettext(" (containing a total of %'d item)", " (containing a total of %'d items)", folder_item_count), folder_item_count); } } } if (non_folder_count != 0) { char *items_string; if (folder_count == 0) { if (non_folder_count == 1) { items_string = g_strdup_printf (_("\"%s\" selected"), first_item_name); } else { items_string = g_strdup_printf (ngettext("%'d item selected", "%'d items selected", non_folder_count), non_folder_count); } } else { /* Folders selected also, use "other" terminology */ items_string = g_strdup_printf (ngettext("%'d other item selected", "%'d other items selected", non_folder_count), non_folder_count); } if (non_folder_size_known) { char *size_string; int prefix; prefix = nemo_global_preferences_get_size_prefix_preference (); size_string = g_format_size_full (non_folder_size, prefix); /* This is marked for translation in case a localiser * needs to use something other than parentheses. The * first message gives the number of items selected; * the message in parentheses the size of those items. */ non_folder_str = g_strdup_printf (_("%s (%s)"), items_string, size_string); g_free (size_string); g_free (items_string); } else { non_folder_str = items_string; } } free_space_str = nemo_file_get_volume_free_space (view->details->directory_as_file); if (free_space_str != NULL) { obj_selected_free_space_str = g_strdup_printf (_("Free space: %s"), free_space_str); } if (folder_count == 0 && non_folder_count == 0) { char *item_count_str; guint item_count; item_count = nemo_view_get_item_count (view); item_count_str = g_strdup_printf (ngettext ("%'u item", "%'u items", item_count), item_count); if (free_space_str != NULL) { status_string = g_strdup_printf (_("%s, Free space: %s"), item_count_str, free_space_str); g_free (item_count_str); } else { status_string = item_count_str; } } else if (folder_count == 0) { view_status_string = g_strdup (non_folder_str); if (free_space_str != NULL) { /* Marking this for translation, since you * might want to change "," to something else. * After the comma the amount of free space will * be shown. */ status_string = g_strdup_printf (_("%s, %s"), non_folder_str, obj_selected_free_space_str); } } else if (non_folder_count == 0) { /* No use marking this for translation, since you * can't reorder the strings, which is the main thing * you'd want to do. */ view_status_string = g_strdup_printf ("%s%s", folder_count_str, folder_item_count_str); if (free_space_str != NULL) { /* Marking this for translation, since you * might want to change "," to something else. * After the comma the amount of free space will * be shown. */ status_string = g_strdup_printf (_("%s%s, %s"), folder_count_str, folder_item_count_str, obj_selected_free_space_str); } } else { /* This is marked for translation in case a localizer * needs to change ", " to something else. The comma * is between the message about the number of folders * and the number of items in those folders and the * message about the number of other items and the * total size of those items. */ view_status_string = g_strdup_printf (_("%s%s, %s"), folder_count_str, folder_item_count_str, non_folder_str); if (obj_selected_free_space_str != NULL) { /* This is marked for translation in case a localizer * needs to change ", " to something else. The first comma * is between the message about the number of folders * and the number of items in those folders and the * message about the number of other items and the * total size of those items. After the second comma * the free space is written. */ status_string = g_strdup_printf (_("%s%s, %s, %s"), folder_count_str, folder_item_count_str, non_folder_str, obj_selected_free_space_str); } } g_free (free_space_str); g_free (obj_selected_free_space_str); g_free (first_item_name); g_free (folder_count_str); g_free (folder_item_count_str); g_free (non_folder_str); if (status_string == NULL) { status_string = g_strdup (view_status_string); } nemo_window_slot_set_status (view->details->slot, status_string, view_status_string); g_free (status_string); g_free (view_status_string); } static void nemo_view_send_selection_change (NemoView *view) { g_signal_emit (view, signals[SELECTION_CHANGED], 0); view->details->send_selection_change_to_shell = FALSE; } void nemo_view_load_location (NemoView *nemo_view, GFile *location) { NemoDirectory *directory; NemoView *directory_view; directory_view = NEMO_VIEW (nemo_view); directory = nemo_directory_get (location); load_directory (directory_view, directory); nemo_directory_unref (directory); } static gboolean reveal_selection_idle_callback (gpointer data) { NemoView *view; view = NEMO_VIEW (data); view->details->reveal_selection_idle_id = 0; nemo_view_reveal_selection (view); return FALSE; } static gboolean idle_timer_report (gpointer user_data) { g_return_val_if_fail (NEMO_IS_VIEW (user_data), G_SOURCE_REMOVE); NemoView *view = NEMO_VIEW (user_data); g_printerr ("Idle...Folder load time: %f seconds\n", g_timer_elapsed (view->details->load_timer, NULL)); return G_SOURCE_REMOVE; } static void done_loading (NemoView *view, gboolean all_files_seen) { GList *selection; if (!view->details->loading) { return; } /* This can be called during destruction, in which case there * is no NemoWindow any more. */ if (view->details->window != NULL) { if (all_files_seen) { nemo_window_report_load_complete (view->details->window, NEMO_VIEW (view)); } schedule_update_menus (view); schedule_update_status (view); reset_update_interval (view); selection = view->details->pending_selection; if (selection != NULL && all_files_seen) { view->details->pending_selection = NULL; view->details->selection_change_is_due_to_shell = TRUE; nemo_view_call_set_selection (view, selection); view->details->selection_change_is_due_to_shell = FALSE; if (NEMO_IS_LIST_VIEW (view)) { /* HACK: We should be able to directly call reveal_selection here, * but at this point the GtkTreeView hasn't allocated the new nodes * yet, and it has a bug in the scroll calculation dealing with this * special case. It would always make the selection the top row, even * if no scrolling would be neccessary to reveal it. So we let it * allocate before revealing. */ if (view->details->reveal_selection_idle_id != 0) { g_source_remove (view->details->reveal_selection_idle_id); } view->details->reveal_selection_idle_id = g_idle_add (reveal_selection_idle_callback, view); } else { nemo_view_reveal_selection (view); } } g_list_free_full (selection, g_object_unref); nemo_view_display_selection_info (view); } view->details->loading = FALSE; g_signal_emit (view, signals[END_LOADING], 0, all_files_seen); if (g_getenv("NEMO_BENCHMARK_LOADING")) { if (nemo_startup_timer != NULL) { g_printerr ("Nemo startup time: %f seconds\n", g_timer_elapsed (nemo_startup_timer, NULL)); g_clear_pointer (&nemo_startup_timer, g_timer_destroy); } g_printerr ("Folder load time: %f seconds\n", g_timer_elapsed (view->details->load_timer, NULL)); g_idle_add_full (1000, (GSourceFunc) idle_timer_report, view, NULL); } } typedef struct { GHashTable *debuting_files; GList *added_files; } DebutingFilesData; static void debuting_files_data_free (DebutingFilesData *data) { g_hash_table_unref (data->debuting_files); nemo_file_list_free (data->added_files); g_free (data); } /* This signal handler watch for the arrival of the icons created * as the result of a file operation. Once the last one is detected * it selects and reveals them all. */ static void debuting_files_add_file_callback (NemoView *view, NemoFile *new_file, NemoDirectory *directory, DebutingFilesData *data) { GFile *location; location = nemo_file_get_location (new_file); if (g_hash_table_remove (data->debuting_files, location)) { nemo_file_ref (new_file); data->added_files = g_list_prepend (data->added_files, new_file); if (g_hash_table_size (data->debuting_files) == 0) { nemo_view_call_set_selection (view, data->added_files); nemo_view_reveal_selection (view); g_signal_handlers_disconnect_by_func (view, G_CALLBACK (debuting_files_add_file_callback), data); } } g_object_unref (location); } typedef struct { GList *added_files; NemoView *directory_view; } CopyMoveDoneData; static void copy_move_done_data_free (CopyMoveDoneData *data) { g_assert (data != NULL); if (data->directory_view != NULL) { g_object_remove_weak_pointer (G_OBJECT (data->directory_view), (gpointer *) &data->directory_view); } nemo_file_list_free (data->added_files); g_free (data); } static void pre_copy_move_add_file_callback (NemoView *view, NemoFile *new_file, NemoDirectory *directory, CopyMoveDoneData *data) { nemo_file_ref (new_file); data->added_files = g_list_prepend (data->added_files, new_file); } /* This needs to be called prior to nemo_file_operations_copy_move. * It hooks up a signal handler to catch any icons that get added before * the copy_done_callback is invoked. The return value should be passed * as the data for uri_copy_move_done_callback. */ static CopyMoveDoneData * pre_copy_move (NemoView *directory_view) { CopyMoveDoneData *copy_move_done_data; copy_move_done_data = g_new0 (CopyMoveDoneData, 1); copy_move_done_data->directory_view = directory_view; g_object_add_weak_pointer (G_OBJECT (copy_move_done_data->directory_view), (gpointer *) ©_move_done_data->directory_view); /* We need to run after the default handler adds the folder we want to * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we * must use connect_after. */ g_signal_connect (directory_view, "add_file", G_CALLBACK (pre_copy_move_add_file_callback), copy_move_done_data); return copy_move_done_data; } /* This function is used to pull out any debuting uris that were added * and (as a side effect) remove them from the debuting uri hash table. */ static gboolean copy_move_done_partition_func (gpointer data, gpointer callback_data) { GFile *location; gboolean result; location = nemo_file_get_location (NEMO_FILE (data)); result = g_hash_table_remove ((GHashTable *) callback_data, location); g_object_unref (location); return result; } static gboolean remove_not_really_moved_files (gpointer key, gpointer value, gpointer callback_data) { GList **added_files; GFile *loc; loc = key; if (GPOINTER_TO_INT (value)) { return FALSE; } added_files = callback_data; *added_files = g_list_prepend (*added_files, nemo_file_get (loc)); return TRUE; } /* When this function is invoked, the file operation is over, but all * the icons may not have been added to the directory view yet, so * we can't select them yet. * * We're passed a hash table of the uri's to look out for, we hook * up a signal handler to await their arrival. */ static void copy_move_done_callback (GHashTable *debuting_files, gboolean success, gpointer data) { NemoView *directory_view; CopyMoveDoneData *copy_move_done_data; DebutingFilesData *debuting_files_data; copy_move_done_data = (CopyMoveDoneData *) data; directory_view = copy_move_done_data->directory_view; if (directory_view != NULL) { g_assert (NEMO_IS_VIEW (directory_view)); debuting_files_data = g_new (DebutingFilesData, 1); debuting_files_data->debuting_files = g_hash_table_ref (debuting_files); debuting_files_data->added_files = eel_g_list_partition (copy_move_done_data->added_files, copy_move_done_partition_func, debuting_files, ©_move_done_data->added_files); /* We're passed the same data used by pre_copy_move_add_file_callback, so disconnecting * it will free data. We've already siphoned off the added_files we need, and stashed the * directory_view pointer. */ g_signal_handlers_disconnect_by_func (directory_view, G_CALLBACK (pre_copy_move_add_file_callback), data); /* Any items in the debuting_files hash table that have * "FALSE" as their value aren't really being copied * or moved, so we can't wait for an add_file signal * to come in for those. */ g_hash_table_foreach_remove (debuting_files, remove_not_really_moved_files, &debuting_files_data->added_files); if (g_hash_table_size (debuting_files) == 0) { /* on the off-chance that all the icons have already been added */ if (debuting_files_data->added_files != NULL) { nemo_view_call_set_selection (directory_view, debuting_files_data->added_files); nemo_view_reveal_selection (directory_view); } debuting_files_data_free (debuting_files_data); } else { /* We need to run after the default handler adds the folder we want to * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we * must use connect_after. */ g_signal_connect_data (directory_view, "add_file", G_CALLBACK (debuting_files_add_file_callback), debuting_files_data, (GClosureNotify) debuting_files_data_free, G_CONNECT_AFTER); } /* Schedule menu update for undo items */ schedule_update_menus (directory_view); } copy_move_done_data_free (copy_move_done_data); } static gboolean view_file_still_belongs (NemoView *view, NemoFile *file, NemoDirectory *directory) { if (view->details->model != directory && g_list_find (view->details->subdirectory_list, directory) == NULL) { return FALSE; } return nemo_directory_contains_file (directory, file); } static gboolean still_should_show_file (NemoView *view, NemoFile *file, NemoDirectory *directory) { return nemo_view_should_show_file (view, file) && view_file_still_belongs (view, file, directory); } static gboolean ready_to_load (NemoFile *file) { return nemo_file_check_if_ready (file, NEMO_FILE_ATTRIBUTES_FOR_ICON); } static int compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data) { const FileAndDirectory *fad1, *fad2; NemoView *view; view = callback_data; fad1 = a; fad2 = b; if (fad1->directory < fad2->directory) { return -1; } else if (fad1->directory > fad2->directory) { return 1; } else { return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, fad1->file, fad2->file); } } static void sort_files (NemoView *view, GList **list) { *list = g_list_sort_with_data (*list, compare_files_cover, view); } /* Go through all the new added and changed files. * Put any that are not ready to load in the non_ready_files hash table. * Add all the rest to the old_added_files and old_changed_files lists. * Sort the old_*_files lists if anything was added to them. */ static void process_new_files (NemoView *view) { GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files; GHashTable *non_ready_files; GList *node, *next; FileAndDirectory *pending; gboolean in_non_ready; new_added_files = view->details->new_added_files; view->details->new_added_files = NULL; new_changed_files = view->details->new_changed_files; view->details->new_changed_files = NULL; non_ready_files = view->details->non_ready_files; old_added_files = view->details->old_added_files; old_changed_files = view->details->old_changed_files; /* Newly added files go into the old_added_files list if they're * ready, and into the hash table if they're not. */ for (node = new_added_files; node != NULL; node = next) { next = node->next; pending = (FileAndDirectory *)node->data; in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL; if (nemo_view_should_show_file (view, pending->file)) { if (ready_to_load (pending->file)) { if (in_non_ready) { g_hash_table_remove (non_ready_files, pending); } new_added_files = g_list_delete_link (new_added_files, node); old_added_files = g_list_prepend (old_added_files, pending); } else { if (!in_non_ready) { new_added_files = g_list_delete_link (new_added_files, node); g_hash_table_insert (non_ready_files, pending, pending); } } } } file_and_directory_list_free (new_added_files); /* Newly changed files go into the old_added_files list if they're ready * and were seen non-ready in the past, into the old_changed_files list * if they are read and were not seen non-ready in the past, and into * the hash table if they're not ready. */ for (node = new_changed_files; node != NULL; node = next) { next = node->next; pending = (FileAndDirectory *)node->data; if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) { if (g_hash_table_lookup (non_ready_files, pending) != NULL) { g_hash_table_remove (non_ready_files, pending); if (still_should_show_file (view, pending->file, pending->directory)) { new_changed_files = g_list_delete_link (new_changed_files, node); old_added_files = g_list_prepend (old_added_files, pending); } } else if (nemo_view_should_show_file (view, pending->file)) { new_changed_files = g_list_delete_link (new_changed_files, node); old_changed_files = g_list_prepend (old_changed_files, pending); } } } file_and_directory_list_free (new_changed_files); /* If any files were added to old_added_files, then resort it. */ if (old_added_files != view->details->old_added_files) { view->details->old_added_files = old_added_files; sort_files (view, &view->details->old_added_files); } /* Resort old_changed_files too, since file attributes * relevant to sorting could have changed. */ if (old_changed_files != view->details->old_changed_files) { view->details->old_changed_files = old_changed_files; sort_files (view, &view->details->old_changed_files); } } static void process_old_files (NemoView *view) { GList *files_added, *files_changed, *node; FileAndDirectory *pending; GList *selection, *files; gboolean send_selection_change; files_added = view->details->old_added_files; files_changed = view->details->old_changed_files; send_selection_change = FALSE; if (files_added != NULL || files_changed != NULL) { g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0); for (node = files_added; node != NULL; node = node->next) { pending = node->data; g_signal_emit (view, signals[ADD_FILE], 0, pending->file, pending->directory); } for (node = files_changed; node != NULL; node = node->next) { pending = node->data; g_signal_emit (view, signals[still_should_show_file (view, pending->file, pending->directory) ? FILE_CHANGED : REMOVE_FILE], 0, pending->file, pending->directory); } g_signal_emit (view, signals[END_FILE_CHANGES], 0); if (files_changed != NULL) { selection = nemo_file_list_ref (nemo_view_peek_selection (view)); files = file_and_directory_list_to_files (files_changed); send_selection_change = eel_g_lists_sort_and_check_for_intersection (&files, &selection); nemo_file_list_free (files); nemo_file_list_unref (selection); } file_and_directory_list_free (view->details->old_added_files); view->details->old_added_files = NULL; file_and_directory_list_free (view->details->old_changed_files); view->details->old_changed_files = NULL; } if (send_selection_change) { /* Send a selection change since some file names could * have changed. */ nemo_view_send_selection_change (view); } } static void display_pending_files (NemoView *view) { /* Don't dispatch any updates while the view is frozen. */ if (view->details->updates_frozen) { return; } process_new_files (view); process_old_files (view); if (view->details->model != NULL && nemo_directory_are_all_files_seen (view->details->model) && g_hash_table_size (view->details->non_ready_files) == 0) { done_loading (view, TRUE); } } void nemo_view_freeze_updates (NemoView *view) { view->details->updates_frozen = TRUE; view->details->updates_queued = 0; view->details->needs_reload = FALSE; } void nemo_view_unfreeze_updates (NemoView *view) { view->details->updates_frozen = FALSE; if (view->details->needs_reload) { view->details->needs_reload = FALSE; if (view->details->model != NULL) { load_directory (view, view->details->model); } } else { schedule_idle_display_of_pending_files (view); } } static gboolean display_selection_info_idle_callback (gpointer data) { NemoView *view; view = NEMO_VIEW (data); g_object_ref (G_OBJECT (view)); view->details->display_selection_idle_id = 0; nemo_view_display_selection_info (view); if (view->details->send_selection_change_to_shell) { nemo_view_send_selection_change (view); } g_object_unref (G_OBJECT (view)); return FALSE; } static void remove_update_menus_timeout_callback (NemoView *view) { if (view->details->update_menus_timeout_id != 0) { g_source_remove (view->details->update_menus_timeout_id); view->details->update_menus_timeout_id = 0; } } static void update_menus_if_pending (NemoView *view) { if (!view->details->menu_states_untrustworthy) { return; } remove_update_menus_timeout_callback (view); nemo_view_update_menus (view); } static gboolean update_menus_timeout_callback (gpointer data) { NemoView *view; view = NEMO_VIEW (data); g_object_ref (G_OBJECT (view)); view->details->update_menus_timeout_id = 0; nemo_view_update_menus (view); g_object_unref (G_OBJECT (view)); return FALSE; } static gboolean display_pending_callback (gpointer data) { NemoView *view; view = NEMO_VIEW (data); g_object_ref (G_OBJECT (view)); view->details->display_pending_source_id = 0; display_pending_files (view); g_object_unref (G_OBJECT (view)); return FALSE; } static void schedule_idle_display_of_pending_files (NemoView *view) { /* Get rid of a pending source as it might be a timeout */ unschedule_display_of_pending_files (view); /* We want higher priority than the idle that handles the relayout to avoid a resort on each add. But we still want to allow repaints and other hight prio events while we have pending files to show. */ view->details->display_pending_source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, display_pending_callback, view, NULL); } static void schedule_timeout_display_of_pending_files (NemoView *view, guint interval) { /* No need to schedule an update if there's already one pending. */ if (view->details->display_pending_source_id != 0) { return; } view->details->display_pending_source_id = g_timeout_add (interval, display_pending_callback, view); } static void unschedule_display_of_pending_files (NemoView *view) { /* Get rid of source if it's active. */ if (view->details->display_pending_source_id != 0) { g_source_remove (view->details->display_pending_source_id); view->details->display_pending_source_id = 0; } } static void queue_pending_files (NemoView *view, NemoDirectory *directory, GList *files, GList **pending_list) { if (files == NULL) { return; } /* Don't queue any more updates if we need to reload anyway */ if (view->details->needs_reload) { return; } if (view->details->updates_frozen) { view->details->updates_queued += g_list_length (files); /* Mark the directory for reload when there are too much queued * changes to prevent the pending list from growing infinitely. */ if (view->details->updates_queued > MAX_QUEUED_UPDATES) { view->details->needs_reload = TRUE; return; } } *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files), *pending_list); schedule_timeout_display_of_pending_files (view, view->details->update_interval); } static void remove_changes_timeout_callback (NemoView *view) { if (view->details->changes_timeout_id != 0) { g_source_remove (view->details->changes_timeout_id); view->details->changes_timeout_id = 0; } } static void reset_update_interval (NemoView *view) { view->details->update_interval = UPDATE_INTERVAL_MIN; remove_changes_timeout_callback (view); /* Reschedule a pending timeout to idle */ if (view->details->display_pending_source_id != 0) { schedule_idle_display_of_pending_files (view); } } static gboolean changes_timeout_callback (gpointer data) { gint64 now; gint64 time_delta; gboolean ret; NemoView *view; view = NEMO_VIEW (data); g_object_ref (G_OBJECT (view)); now = g_get_monotonic_time (); time_delta = now - view->details->last_queued; if (time_delta < UPDATE_INTERVAL_RESET*1000) { if (view->details->update_interval < UPDATE_INTERVAL_MAX && view->details->loading) { /* Increase */ view->details->update_interval += UPDATE_INTERVAL_INC; } ret = TRUE; } else { /* Reset */ reset_update_interval (view); ret = FALSE; } g_object_unref (G_OBJECT (view)); return ret; } static void schedule_changes (NemoView *view) { /* Remember when the change was queued */ view->details->last_queued = g_get_monotonic_time (); /* No need to schedule if there are already changes pending or during loading */ if (view->details->changes_timeout_id != 0 || view->details->loading) { return; } view->details->changes_timeout_id = g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view); } static void files_added_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoView *view; GtkWindow *window; char *uri; view = NEMO_VIEW (callback_data); window = nemo_view_get_containing_window (view); uri = nemo_view_get_uri (view); DEBUG_FILES (files, "Files added in window %p: %s", window, uri ? uri : "(no directory)"); g_free (uri); schedule_changes (view); queue_pending_files (view, directory, files, &view->details->new_added_files); /* The number of items could have changed */ schedule_update_status (view); } static void files_changed_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoView *view; GtkWindow *window; char *uri; view = NEMO_VIEW (callback_data); window = nemo_view_get_containing_window (view); uri = nemo_view_get_uri (view); DEBUG_FILES (files, "Files changed in window %p: %s", window, uri ? uri : "(no directory)"); g_free (uri); schedule_changes (view); queue_pending_files (view, directory, files, &view->details->new_changed_files); /* The free space or the number of items could have changed */ schedule_update_status (view); /* A change in MIME type could affect the Open with menu, for * one thing, so we need to update menus when files change. */ schedule_update_menus (view); } static void done_loading_callback (NemoDirectory *directory, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); process_new_files (view); if (g_hash_table_size (view->details->non_ready_files) == 0) { /* Unschedule a pending update and schedule a new one with the minimal * update interval. This gives the view a short chance at gathering the * (cached) deep counts. */ unschedule_display_of_pending_files (view); schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); } } static void load_error_callback (NemoDirectory *directory, GError *error, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); /* FIXME: By doing a stop, we discard some pending files. Is * that OK? */ nemo_view_stop_loading (view); nemo_window_back_or_forward (NEMO_WINDOW (view->details->window), TRUE, 0, FALSE); /* Emit a signal to tell subclasses that a load error has * occurred, so they can handle it in the UI. */ g_signal_emit (view, signals[LOAD_ERROR], 0, error); } static void real_load_error (NemoView *view, GError *error) { /* Report only one error per failed directory load (from the UI * point of view, not from the NemoDirectory point of view). * Otherwise you can get multiple identical errors caused by * unrelated code that just happens to try to iterate this * directory. */ if (!view->details->reported_load_error) { nemo_report_error_loading_directory (nemo_view_get_directory_as_file (view), error, nemo_view_get_containing_window (view)); } view->details->reported_load_error = TRUE; } void nemo_view_add_subdirectory (NemoView *view, NemoDirectory*directory) { NemoFileAttributes attributes; g_assert (!g_list_find (view->details->subdirectory_list, directory)); nemo_directory_ref (directory); attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_EXTENSION_INFO; nemo_directory_file_monitor_add (directory, &view->details->model, view->details->show_hidden_files, attributes, files_added_callback, view); g_signal_connect (directory, "files_added", G_CALLBACK (files_added_callback), view); g_signal_connect (directory, "files_changed", G_CALLBACK (files_changed_callback), view); view->details->subdirectory_list = g_list_prepend ( view->details->subdirectory_list, directory); } void nemo_view_remove_subdirectory (NemoView *view, NemoDirectory*directory) { g_assert (g_list_find (view->details->subdirectory_list, directory)); view->details->subdirectory_list = g_list_remove ( view->details->subdirectory_list, directory); g_signal_handlers_disconnect_by_func (directory, G_CALLBACK (files_added_callback), view); g_signal_handlers_disconnect_by_func (directory, G_CALLBACK (files_changed_callback), view); nemo_directory_file_monitor_remove (directory, &view->details->model); nemo_directory_unref (directory); } /** * nemo_view_get_loading: * @view: an #NemoView. * * Return value: #gboolean inicating whether @view is currently loaded. * **/ gboolean nemo_view_get_loading (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return view->details->loading; } GtkUIManager * nemo_view_get_ui_manager (NemoView *view) { if (view->details->window == NULL) { return NULL; } return nemo_window_get_ui_manager (view->details->window); } /** * nemo_view_get_model: * * Get the model for this NemoView. * @view: NemoView of interest. * * Return value: NemoDirectory for this view. * **/ NemoDirectory * nemo_view_get_model (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); return view->details->model; } GdkAtom nemo_view_get_copied_files_atom (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), GDK_NONE); return copied_files_atom; } static void prepend_uri_one (gpointer data, gpointer callback_data) { NemoFile *file; GList **result; g_assert (NEMO_IS_FILE (data)); g_assert (callback_data != NULL); result = (GList **) callback_data; file = (NemoFile *) data; *result = g_list_prepend (*result, nemo_file_get_uri (file)); } static void offset_drop_points (GArray *relative_item_points, int x_offset, int y_offset) { guint index; if (relative_item_points == NULL) { return; } for (index = 0; index < relative_item_points->len; index++) { g_array_index (relative_item_points, GdkPoint, index).x += x_offset; g_array_index (relative_item_points, GdkPoint, index).y += y_offset; } } static void nemo_view_create_links_for_files (NemoView *view, GList *files, GArray *relative_item_points) { GList *uris; char *dir_uri; CopyMoveDoneData *copy_move_done_data; g_assert (relative_item_points->len == 0 || g_list_length (files) == relative_item_points->len); g_assert (NEMO_IS_VIEW (view)); g_assert (files != NULL); /* create a list of URIs */ uris = NULL; g_list_foreach (files, prepend_uri_one, &uris); uris = g_list_reverse (uris); g_assert (g_list_length (uris) == g_list_length (files)); /* offset the drop locations a bit so that we don't pile * up the icons on top of each other */ offset_drop_points (relative_item_points, DUPLICATE_HORIZONTAL_ICON_OFFSET, DUPLICATE_VERTICAL_ICON_OFFSET); copy_move_done_data = pre_copy_move (view); dir_uri = nemo_view_get_backing_uri (view); nemo_file_operations_copy_move (uris, relative_item_points, dir_uri, GDK_ACTION_LINK, GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data); g_free (dir_uri); g_list_free_full (uris, g_free); } static void nemo_view_duplicate_selection (NemoView *view, GList *files, GArray *relative_item_points) { GList *uris; CopyMoveDoneData *copy_move_done_data; g_assert (NEMO_IS_VIEW (view)); g_assert (files != NULL); g_assert (g_list_length (files) == relative_item_points->len || relative_item_points->len == 0); /* create a list of URIs */ uris = NULL; g_list_foreach (files, prepend_uri_one, &uris); uris = g_list_reverse (uris); g_assert (g_list_length (uris) == g_list_length (files)); /* offset the drop locations a bit so that we don't pile * up the icons on top of each other */ offset_drop_points (relative_item_points, DUPLICATE_HORIZONTAL_ICON_OFFSET, DUPLICATE_VERTICAL_ICON_OFFSET); copy_move_done_data = pre_copy_move (view); nemo_file_operations_copy_move (uris, relative_item_points, NULL, GDK_ACTION_COPY, GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data); g_list_free_full (uris, g_free); } /* special_link_in_selection * * Return TRUE if one of our special links is in the selection. * Special links include the following: * NEMO_DESKTOP_LINK_TRASH, NEMO_DESKTOP_LINK_HOME, NEMO_DESKTOP_LINK_MOUNT */ static gboolean special_link_in_selection (NemoView *view, GList *selection) { gboolean saw_link; GList *node; NemoFile *file; g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); saw_link = FALSE; for (node = selection; node != NULL; node = node->next) { file = NEMO_FILE (node->data); saw_link = NEMO_IS_DESKTOP_ICON_FILE (file); if (saw_link) { break; } } return saw_link; } /* desktop_or_home_dir_in_selection * * Return TRUE if either the desktop or the home directory is in the selection. */ static gboolean desktop_or_home_dir_in_selection (NemoView *view, GList *selection) { gboolean saw_desktop_or_home_dir; GList *node; NemoFile *file; g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); saw_desktop_or_home_dir = FALSE; for (node = selection; node != NULL; node = node->next) { file = NEMO_FILE (node->data); saw_desktop_or_home_dir = nemo_file_is_home (file) || nemo_file_is_desktop_directory (file); if (saw_desktop_or_home_dir) { break; } } return saw_desktop_or_home_dir; } /* directory_in_selection * * Return TRUE if selection contains a directory. */ static gboolean directory_in_selection (NemoView *view, GList *selection) { gboolean has_dir; GList *node; NemoFile *file; g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); has_dir = FALSE; for (node = selection; node != NULL; node = node->next) { file = NEMO_FILE (node->data); has_dir = nemo_file_is_directory (file); if (has_dir) { break; } } return has_dir; } static void trash_or_delete_done_cb (GHashTable *debuting_uris, gboolean user_cancel, NemoView *view) { if (user_cancel) { view->details->selection_was_removed = FALSE; } } static void trash_or_delete_files (GtkWindow *parent_window, const GList *files, gboolean delete_if_all_already_in_trash, NemoView *view) { GList *locations; const GList *node; locations = NULL; for (node = files; node != NULL; node = node->next) { locations = g_list_prepend (locations, nemo_file_get_location ((NemoFile *) node->data)); } locations = g_list_reverse (locations); nemo_file_operations_trash_or_delete (locations, parent_window, (NemoDeleteCallback) trash_or_delete_done_cb, view); g_list_free_full (locations, g_object_unref); } static gboolean can_rename_file (NemoView *view, NemoFile *file) { return nemo_file_can_rename (file); } gboolean nemo_view_get_is_renaming (NemoView *view) { return view->details->is_renaming; } void nemo_view_set_is_renaming (NemoView *view, gboolean is_renaming) { view->details->is_renaming = is_renaming; } static void start_renaming_file (NemoView *view, NemoFile *file, gboolean select_all) { view->details->is_renaming = TRUE; if (file != NULL) { nemo_view_select_file (view, file); } } static void update_context_menu_position_from_event (NemoView *view, GdkEventButton *event) { g_return_if_fail (NEMO_IS_VIEW (view)); if (event != NULL) { view->details->context_menu_position.x = event->x; view->details->context_menu_position.y = event->y; } else { view->details->context_menu_position.x = -1; view->details->context_menu_position.y = -1; } } /* handle the open command */ static void open_one_in_new_window (gpointer data, gpointer callback_data) { g_assert (NEMO_IS_FILE (data)); g_assert (NEMO_IS_VIEW (callback_data)); nemo_view_activate_file (NEMO_VIEW (callback_data), NEMO_FILE (data), NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); } NemoFile * nemo_view_get_directory_as_file (NemoView *view) { g_assert (NEMO_IS_VIEW (view)); return view->details->directory_as_file; } static void open_with_launch_application_callback (GtkAction *action, gpointer callback_data) { ApplicationLaunchParameters *launch_parameters; launch_parameters = (ApplicationLaunchParameters *) callback_data; nemo_launch_application (launch_parameters->application, launch_parameters->files, nemo_view_get_containing_window (launch_parameters->directory_view)); } static char * escape_action_name (const char *action_name, const char *prefix) { GString *s; if (action_name == NULL) { return NULL; } s = g_string_new (prefix); while (*action_name != 0) { switch (*action_name) { case '\\': g_string_append (s, "\\\\"); break; case '/': g_string_append (s, "\\s"); break; case '&': g_string_append (s, "\\a"); break; case '"': g_string_append (s, "\\q"); break; default: g_string_append_c (s, *action_name); } action_name ++; } return g_string_free (s, FALSE); } static char * escape_action_path (const char *action_path) { GString *s; if (action_path == NULL) { return NULL; } s = g_string_sized_new (strlen (action_path) + 2); while (*action_path != 0) { switch (*action_path) { case '\\': g_string_append (s, "\\\\"); break; case '&': g_string_append (s, "\\a"); break; case '"': g_string_append (s, "\\q"); break; default: g_string_append_c (s, *action_path); } action_path ++; } return g_string_free (s, FALSE); } static void add_submenu (GtkUIManager *ui_manager, GtkActionGroup *action_group, guint merge_id, const char *parent_path, const char *uri, const char *label, GdkPixbuf *pixbuf, gboolean add_action) { char *escaped_label; char *action_name; char *submenu_name; char *escaped_submenu_name; GtkAction *action; if (parent_path != NULL) { action_name = escape_action_name (uri, "submenu_"); submenu_name = g_path_get_basename (uri); escaped_submenu_name = escape_action_path (submenu_name); escaped_label = eel_str_double_underscores (label); if (add_action) { action = gtk_action_new (action_name, escaped_label, NULL, NULL); if (pixbuf != NULL) { gtk_action_set_gicon (action, G_ICON (pixbuf)); } g_object_set (action, "hide-if-empty", FALSE, NULL); gtk_action_group_add_action (action_group, action); g_object_unref (action); } gtk_ui_manager_add_ui (ui_manager, merge_id, parent_path, escaped_submenu_name, action_name, GTK_UI_MANAGER_MENU, FALSE); g_free (action_name); g_free (escaped_label); g_free (submenu_name); g_free (escaped_submenu_name); } } static void menu_item_show_image (GtkUIManager *ui_manager, const char *parent_path, const char *action_name, gboolean ignore_gtk_pref) { GtkImageMenuItem *menuitem; char *path; gboolean show = TRUE; path = g_strdup_printf ("%s/%s", parent_path, action_name); menuitem = GTK_IMAGE_MENU_ITEM (gtk_ui_manager_get_widget (ui_manager, path)); g_free (path); if (!ignore_gtk_pref) { g_object_get (gtk_settings_get_default (), "gtk-menu-images", &show, NULL); if (!show && !gtk_image_menu_item_get_always_show_image (menuitem)) { return; } } if (menuitem != NULL) { gtk_image_menu_item_set_always_show_image (menuitem, show); } } static void add_application_to_open_with_menu (NemoView *view, GAppInfo *application, GList *files, int index, const char *menu_placeholder, const char *popup_placeholder, const gboolean submenu) { ApplicationLaunchParameters *launch_parameters; char *tip; char *label; char *action_name; char *escaped_app; GtkAction *action; GIcon *app_icon; GtkUIManager *ui_manager; launch_parameters = application_launch_parameters_new (application, files, view); escaped_app = eel_str_double_underscores (g_app_info_get_name (application)); if (submenu) label = g_strdup_printf ("%s", escaped_app); else label = g_strdup_printf (_("Open With %s"), escaped_app); tip = g_strdup_printf (ngettext ("Use \"%s\" to open the selected item", "Use \"%s\" to open the selected items", g_list_length (files)), escaped_app); g_free (escaped_app); action_name = g_strdup_printf ("open_with_%d", index); action = gtk_action_new (action_name, label, tip, NULL); app_icon = g_app_info_get_icon (application); if (app_icon != NULL) { g_object_ref (app_icon); } else { app_icon = g_themed_icon_new ("application-x-executable"); } gtk_action_set_gicon (action, app_icon); g_object_unref (app_icon); g_signal_connect_data (action, "activate", G_CALLBACK (open_with_launch_application_callback), launch_parameters, (GClosureNotify)application_launch_parameters_free, 0); gtk_action_group_add_action (view->details->open_with_action_group, action); g_object_unref (action); ui_manager = nemo_window_get_ui_manager (view->details->window); gtk_ui_manager_add_ui (ui_manager, view->details->open_with_merge_id, menu_placeholder, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); menu_item_show_image (ui_manager, menu_placeholder, action_name, TRUE); gtk_ui_manager_add_ui (ui_manager, view->details->open_with_merge_id, popup_placeholder, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); menu_item_show_image (ui_manager, popup_placeholder, action_name, TRUE); g_free (action_name); g_free (label); g_free (tip); } static void get_x_content_async_callback (const char **content, gpointer user_data) { NemoView *view; view = NEMO_VIEW (user_data); if (view->details->window != NULL) { schedule_update_menus (view); } g_object_unref (view); } static void add_x_content_apps (NemoView *view, NemoFile *file, GList **applications) { GMount *mount; char **x_content_types; unsigned int n; g_return_if_fail (applications != NULL); mount = nemo_file_get_mount (file); if (mount == NULL) { return; } x_content_types = nemo_get_cached_x_content_types_for_mount (mount); if (x_content_types != NULL) { for (n = 0; x_content_types[n] != NULL; n++) { char *x_content_type = x_content_types[n]; GList *app_info_for_x_content_type; app_info_for_x_content_type = g_app_info_get_all_for_type (x_content_type); *applications = g_list_concat (*applications, app_info_for_x_content_type); } g_strfreev (x_content_types); } else { nemo_get_x_content_types_for_mount_async (mount, get_x_content_async_callback, NULL, g_object_ref (view)); } g_object_unref (mount); } static void reset_open_with_menu (NemoView *view, GList *selection) { GList *applications, *node; NemoFile *file; gboolean submenu_visible, filter_default; int num_applications; int index; gboolean other_applications_visible; gboolean open_with_chooser_visible; GtkUIManager *ui_manager; GtkAction *action; GAppInfo *default_app; /* Clear any previous inserted items in the applications and viewers placeholders */ ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->open_with_merge_id, &view->details->open_with_action_group); nemo_ui_prepare_merge_ui (ui_manager, "OpenWithGroup", &view->details->open_with_merge_id, &view->details->open_with_action_group); other_applications_visible = (selection != NULL); filter_default = (selection != NULL); for (node = selection; node != NULL; node = node->next) { file = NEMO_FILE (node->data); other_applications_visible &= (!nemo_mime_file_opens_in_view (file) || nemo_file_is_directory (file)); } default_app = NULL; if (filter_default) { default_app = nemo_mime_get_default_application_for_files (selection); } applications = NULL; if (other_applications_visible) { applications = nemo_mime_get_applications_for_files (selection); } if (g_list_length (selection) == 1) { add_x_content_apps (view, NEMO_FILE (selection->data), &applications); } num_applications = g_list_length (applications); if (file_list_all_are_folders (selection)) { submenu_visible = (num_applications > 0); } else { submenu_visible = (num_applications > 1); } for (node = applications, index = 0; node != NULL; node = node->next, index++) { GAppInfo *application; char *menu_path; char *popup_path; application = node->data; if (default_app != NULL && g_app_info_equal (default_app, application)) { continue; } if (submenu_visible) { menu_path = (char *)NEMO_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; popup_path = (char *)NEMO_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; } else { menu_path = (char *)NEMO_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER; popup_path = (char *)NEMO_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER; } gtk_ui_manager_add_ui (nemo_window_get_ui_manager (view->details->window), view->details->open_with_merge_id, menu_path, "separator", NULL, GTK_UI_MANAGER_SEPARATOR, FALSE); add_application_to_open_with_menu (view, node->data, selection, index, menu_path, popup_path, submenu_visible); } g_list_free_full (applications, g_object_unref); if (default_app != NULL) { g_object_unref (default_app); } open_with_chooser_visible = other_applications_visible && g_list_length (selection) == 1; if (submenu_visible) { action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OTHER_APPLICATION1); gtk_action_set_visible (action, open_with_chooser_visible); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OTHER_APPLICATION2); gtk_action_set_visible (action, FALSE); } else { action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OTHER_APPLICATION1); gtk_action_set_visible (action, FALSE); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OTHER_APPLICATION2); gtk_action_set_visible (action, open_with_chooser_visible); } } static void move_copy_selection_to_location (NemoView *view, int copy_action, char *target_uri) { GList *selection, *uris, *l; selection = nemo_view_get_selection_for_file_transfer (view); if (selection == NULL) { return; } uris = NULL; for (l = selection; l != NULL; l = l->next) { uris = g_list_prepend (uris, nemo_file_get_uri ((NemoFile *) l->data)); } uris = g_list_reverse (uris); nemo_view_move_copy_items (view, uris, NULL, target_uri, copy_action, 0, 0); g_list_free_full (uris, g_free); nemo_file_list_free (selection); } static void action_move_bookmark_callback (GtkAction *action, gpointer callback_data) { NemoView *view; BookmarkCallbackData *data; data = (BookmarkCallbackData *) callback_data; view = NEMO_VIEW(data->view); move_copy_selection_to_location (view, GDK_ACTION_MOVE, data->dest_uri); } static void action_copy_bookmark_callback (GtkAction *action, gpointer callback_data) { NemoView *view; BookmarkCallbackData *data; data = (BookmarkCallbackData *) callback_data; view = NEMO_VIEW(data->view); move_copy_selection_to_location (view, GDK_ACTION_COPY, data->dest_uri); } static void setup_bookmark_action( char *action_name, const char *bookmark_name, const char *icon_name, char *mount_uri, GtkUIManager *ui_manager, gboolean move, GtkActionGroup *action_group, gint merge_id, const char *path, NemoView *view) { GtkAction *action; action = gtk_action_new (action_name, bookmark_name, NULL, NULL); gtk_action_set_icon_name (action, icon_name); if (move) { g_signal_connect_data (action, "activate", G_CALLBACK (action_move_bookmark_callback), bookmark_callback_data_new(view, mount_uri), (GClosureNotify)bookmark_callback_data_free, 0); } else { g_signal_connect_data (action, "activate", G_CALLBACK (action_copy_bookmark_callback), bookmark_callback_data_new(view, mount_uri), (GClosureNotify)bookmark_callback_data_free, 0); } gtk_action_group_add_action (action_group, action); gtk_ui_manager_add_ui ( ui_manager, merge_id, path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); g_free (action_name); } static void add_bookmark_to_action (NemoView *view, const gchar *bookmark_name, const gchar *icon_name, gchar *mount_uri, gint index) { GtkUIManager *ui_manager; ui_manager = nemo_window_get_ui_manager (view->details->window); setup_bookmark_action(g_strdup_printf ("BM_MOVETO_POPUP_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, TRUE, view->details->copy_move_action_groups[0], view->details->copy_move_merge_ids[0], NEMO_VIEW_POPUP_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("BM_COPYTO_POPUP_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, FALSE, view->details->copy_move_action_groups[1], view->details->copy_move_merge_ids[1], NEMO_VIEW_POPUP_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("BM_MOVETO_MENU_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, TRUE, view->details->copy_move_action_groups[2], view->details->copy_move_merge_ids[2], NEMO_VIEW_MENU_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("BM_COPYTO_MENU_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, FALSE, view->details->copy_move_action_groups[3], view->details->copy_move_merge_ids[3], NEMO_VIEW_MENU_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER, view); } static void add_place_to_action (NemoView *view, const gchar *bookmark_name, const gchar *icon_name, gchar *mount_uri, gint index) { GtkUIManager *ui_manager; ui_manager = nemo_window_get_ui_manager (view->details->window); setup_bookmark_action(g_strdup_printf ("PLACE_MOVETO_POPUP_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, TRUE, view->details->copy_move_action_groups[0], view->details->copy_move_merge_ids[0], NEMO_VIEW_POPUP_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("PLACE_COPYTO_POPUP_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, FALSE, view->details->copy_move_action_groups[1], view->details->copy_move_merge_ids[1], NEMO_VIEW_POPUP_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("PLACE_MOVETO_MENU_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, TRUE, view->details->copy_move_action_groups[2], view->details->copy_move_merge_ids[2], NEMO_VIEW_MENU_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER, view); setup_bookmark_action(g_strdup_printf ("PLACE_COPYTO_MENU_%d", index), bookmark_name, icon_name, mount_uri, ui_manager, FALSE, view->details->copy_move_action_groups[3], view->details->copy_move_merge_ids[3], NEMO_VIEW_MENU_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER, view); } static void reset_move_copy_to_menu (NemoView *view) { NemoBookmark *bookmark; NemoFile *file; int bookmark_count, index; GtkUIManager *ui_manager; GFile *root; const gchar *bookmark_name; gchar *icon_name; char *mount_uri; ui_manager = nemo_window_get_ui_manager (view->details->window); int i; for (i = 0; i < 4; i++) { nemo_ui_unmerge_ui (ui_manager, &view->details->copy_move_merge_ids[i], &view->details->copy_move_action_groups[i]); gchar *id = g_strdup_printf ("MoveCopyMenuGroup_%d", i); nemo_ui_prepare_merge_ui (ui_manager, id, &view->details->copy_move_merge_ids[i], &view->details->copy_move_action_groups[i]); g_free (id); } GtkAction *action; mount_uri = nemo_get_home_directory_uri (); file = nemo_file_get_by_uri (mount_uri); g_free (mount_uri); icon_name = nemo_file_get_control_icon_name (file); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_HOME); gtk_action_set_icon_name (action, icon_name); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_HOME); gtk_action_set_icon_name (action, icon_name); g_clear_pointer (&icon_name, g_free); g_object_unref (file); mount_uri = nemo_get_desktop_directory_uri (); file = nemo_file_get_by_uri (mount_uri); g_free (mount_uri); icon_name = nemo_file_get_control_icon_name (file); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_DESKTOP); gtk_action_set_icon_name (action, icon_name); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_DESKTOP); gtk_action_set_icon_name (action, icon_name); g_clear_pointer (&icon_name, g_free); g_object_unref (file); if (view->details->showing_bookmarks_in_to_menus) { bookmark_count = nemo_bookmark_list_length (view->details->bookmarks); for (index = 0; index < bookmark_count; ++index) { bookmark = nemo_bookmark_list_item_at (view->details->bookmarks, index); /* Unlike the sidebar or the bookmarks menu, we are using bookmarks as file operation targets, not locations to open. As such, we should never show unmounted/invalid locations in the move-to/copy-to menu */ if (!nemo_bookmark_uri_get_exists (bookmark)) { continue; } root = nemo_bookmark_get_location (bookmark); file = nemo_file_get (root); nemo_file_unref (file); bookmark_name = nemo_bookmark_get_name (bookmark); icon_name = nemo_bookmark_get_icon_name (bookmark); mount_uri = nemo_bookmark_get_uri (bookmark); add_bookmark_to_action (view, bookmark_name, icon_name, mount_uri, index); g_object_unref (root); g_free (icon_name); g_free (mount_uri); } } if (view->details->showing_places_in_to_menus) { GList *mounts, *l, *ll, *drives, *volumes; GVolumeMonitor *volume_monitor; GMount *mount; GVolume *volume; GDrive *drive; GList *network_mounts = NULL; GList *network_volumes = NULL; gchar *name, *identifier; index = 0; /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */ volume_monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (volume_monitor); for (l = mounts; l != NULL; l = l->next) { mount = l->data; if (g_mount_is_shadowed (mount)) { g_object_unref (mount); continue; } volume = g_mount_get_volume (mount); if (volume != NULL) { g_object_unref (volume); g_object_unref (mount); continue; } root = g_mount_get_default_location (mount); if (!g_file_is_native (root)) { gboolean really_network = TRUE; gchar *path = g_file_get_path (root); if (!path) { network_mounts = g_list_prepend (network_mounts, mount); g_object_unref (root); continue; } gchar *escaped1 = g_uri_unescape_string (path, ""); gchar *escaped2 = g_uri_unescape_string (escaped1, ""); gchar *ptr = g_strrstr (escaped2, "file://"); if (ptr != NULL) { GFile *actual_file = g_file_new_for_uri (ptr); if (g_file_is_native(actual_file)) { really_network = FALSE; } g_object_unref(actual_file); } g_free (path); g_free (escaped1); g_free (escaped2); if (really_network) { network_mounts = g_list_prepend (network_mounts, mount); g_object_unref (root); continue; } } icon_name = nemo_get_mount_icon_name (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); add_place_to_action (view, name, icon_name, mount_uri, index); g_object_unref (root); g_object_unref (mount); g_free (icon_name); g_free (name); g_free (mount_uri); index++; } g_list_free (mounts); /* first go through all connected drives */ drives = g_volume_monitor_get_connected_drives (volume_monitor); for (l = drives; l != NULL; l = l->next) { drive = l->data; volumes = g_drive_get_volumes (drive); if (volumes != NULL) { for (ll = volumes; ll != NULL; ll = ll->next) { volume = ll->data; identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS); if (g_strcmp0 (identifier, "network") == 0) { g_free (identifier); network_volumes = g_list_prepend (network_volumes, volume); continue; } g_free (identifier); mount = g_volume_get_mount (volume); if (mount != NULL) { /* Show mounted volume in the sidebar */ icon_name = nemo_get_mount_icon_name (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); add_place_to_action (view, name, icon_name, mount_uri, index); g_object_unref (root); g_object_unref (mount); g_free (icon_name); g_free (name); g_free (mount_uri); index++; } g_object_unref (volume); } g_list_free (volumes); } g_object_unref (drive); } g_list_free (drives); /* add all volumes that is not associated with a drive */ volumes = g_volume_monitor_get_volumes (volume_monitor); for (l = volumes; l != NULL; l = l->next) { volume = l->data; drive = g_volume_get_drive (volume); if (drive != NULL) { g_object_unref (volume); g_object_unref (drive); continue; } identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS); if (g_strcmp0 (identifier, "network") == 0) { g_free (identifier); network_volumes = g_list_prepend (network_volumes, volume); continue; } g_free (identifier); mount = g_volume_get_mount (volume); if (mount != NULL) { icon_name = nemo_get_mount_icon_name (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); g_object_unref (root); name = g_mount_get_name (mount); add_place_to_action (view, name, icon_name, mount_uri, index); g_object_unref (mount); g_free (icon_name); g_free (name); g_free (mount_uri); index++; } g_object_unref (volume); } g_list_free (volumes); g_object_unref (volume_monitor); network_volumes = g_list_reverse (network_volumes); for (l = network_volumes; l != NULL; l = l->next) { volume = l->data; mount = g_volume_get_mount (volume); if (mount != NULL) { network_mounts = g_list_prepend (network_mounts, mount); continue; } } g_list_free_full (network_volumes, g_object_unref); network_mounts = g_list_reverse (network_mounts); for (l = network_mounts; l != NULL; l = l->next) { mount = l->data; root = g_mount_get_default_location (mount); icon_name = nemo_get_mount_icon_name (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); add_place_to_action (view, name, icon_name, mount_uri, index); g_object_unref (root); g_free (icon_name); g_free (name); g_free (mount_uri); index++; } g_list_free_full (network_mounts, g_object_unref); } } static void disconnect_bookmark (gpointer data, gpointer callback_data) { GtkAction *action = GTK_ACTION (data); g_signal_handlers_disconnect_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_move_bookmark_callback, NULL); g_signal_handlers_disconnect_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_copy_bookmark_callback, NULL); } static void disconnect_bookmark_signals (NemoView *view) { int i; GList *list; GtkActionGroup *group; for (i = 0; i < 4; i++) { group = GTK_ACTION_GROUP (view->details->copy_move_action_groups[i]); list = gtk_action_group_list_actions (group); g_list_foreach (list, disconnect_bookmark, NULL); g_list_free (list); } } static GList * get_all_extension_menu_items (GtkWidget *window, GList *selection) { GList *items; GList *providers; GList *l; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_MENU_PROVIDER); items = NULL; for (l = providers; l != NULL; l = l->next) { NemoMenuProvider *provider; GList *file_items; provider = NEMO_MENU_PROVIDER (l->data); file_items = nemo_menu_provider_get_file_items (provider, window, selection); items = g_list_concat (items, file_items); } nemo_module_extension_list_free (providers); return items; } typedef struct { NemoMenuItem *item; NemoView *view; GList *selection; GtkAction *action; } ExtensionActionCallbackData; static void extension_action_callback_data_free (ExtensionActionCallbackData *data) { g_object_unref (data->item); nemo_file_list_free (data->selection); g_free (data); } static gboolean search_in_menu_items (GList* items, const char *item_name) { GList* list; for (list = items; list != NULL; list = list->next) { NemoMenu* menu; char *name; g_object_get (list->data, "name", &name, NULL); if (strcmp (name, item_name) == 0) { g_free (name); return TRUE; } g_free (name); menu = NULL; g_object_get (list->data, "menu", &menu, NULL); if (menu != NULL) { gboolean ret; GList* submenus; submenus = nemo_menu_get_items (menu); ret = search_in_menu_items (submenus, item_name); nemo_menu_item_list_free (submenus); g_object_unref (menu); if (ret) { return TRUE; } } } return FALSE; } static void extension_action_callback (GtkAction *action, gpointer callback_data) { ExtensionActionCallbackData *data; char *item_name; gboolean is_valid; GList *l; GList *items; data = callback_data; /* Make sure the selected menu item is valid for the final sniffed * mime type */ g_object_get (data->item, "name", &item_name, NULL); items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)), data->selection); is_valid = search_in_menu_items (items, item_name); for (l = items; l != NULL; l = l->next) { g_object_unref (l->data); } g_list_free (items); g_free (item_name); if (is_valid) { nemo_menu_item_activate (data->item); } } static GdkPixbuf * get_menu_icon_for_file (NemoFile *file, GtkWidget *widget) { NemoIconInfo *info; GdkPixbuf *pixbuf; int size, scale; size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); scale = gtk_widget_get_scale_factor (widget); info = nemo_file_get_icon (file, size, 0, scale, 0); pixbuf = nemo_icon_info_get_pixbuf_nodefault_at_size (info, size); nemo_icon_info_unref (info); return pixbuf; } static GtkAction * add_extension_action_for_files (NemoView *view, NemoMenuItem *item, GList *files) { GtkAction *ret = NULL; char *name, *label, *tip, *icon; gboolean sensitive, priority; gboolean separator; GtkAction *action; GtkWidget *widget_a, *widget_b; ExtensionActionCallbackData *data; g_object_get (G_OBJECT (item), "name", &name, "label", &label, "tip", &tip, "icon", &icon, "sensitive", &sensitive, "priority", &priority, "widget-a", &widget_a, "widget-b", &widget_b, "separator", &separator, NULL); if (widget_a == NULL && !separator) { action = gtk_action_new (name, label, tip, NULL); if (icon != NULL) { GIcon *gicon; if (g_path_is_absolute (icon)) { GFile *file; file = g_file_new_for_path (icon); gicon = g_file_icon_new (file); g_object_unref (file); } else if (icon) { gicon = g_themed_icon_new (icon); } else { gicon = NULL; } gtk_action_set_gicon (action, gicon); g_clear_object (&gicon); } } else if (separator) { action = nemo_separator_action_new (name); } else { action = nemo_widget_action_new (name, widget_a, widget_b); } gtk_action_set_sensitive (action, sensitive); g_object_set (action, "is-important", priority, NULL); data = g_new0 (ExtensionActionCallbackData, 1); data->item = g_object_ref (item); data->view = view; data->selection = nemo_file_list_copy (files); data->action = action; g_signal_connect_data (action, "activate", G_CALLBACK (extension_action_callback), data, (GClosureNotify)extension_action_callback_data_free, 0); if (gtk_action_group_get_action (view->details->extensions_menu_action_group, gtk_action_get_name (GTK_ACTION (action))) == NULL) { gtk_action_group_add_action (view->details->extensions_menu_action_group, GTK_ACTION (action)); ret = action; } g_object_unref (action); g_free (name); g_free (label); g_free (tip); g_free (icon); return ret; } static void add_extension_menu_items (NemoView *view, GList *files, GList *menu_items, const char *subdirectory) { GtkUIManager *ui_manager; GList *l; ui_manager = nemo_window_get_ui_manager (view->details->window); for (l = menu_items; l; l = l->next) { NemoMenuItem *item; NemoMenu *menu; GtkAction *action = NULL; char *path; item = NEMO_MENU_ITEM (l->data); g_object_get (item, "menu", &menu, NULL); action = add_extension_action_for_files (view, item, files); if (action) { GtkUIManagerItemType item_type; if (G_OBJECT_TYPE (action) == NEMO_TYPE_SEPARATOR_ACTION) item_type = GTK_UI_MANAGER_SEPARATOR; else { item_type = (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM; } path = g_build_path ("/", NEMO_VIEW_POPUP_PATH_EXTENSION_ACTIONS, subdirectory, NULL); gtk_ui_manager_add_ui (ui_manager, view->details->extensions_menu_merge_id, path, gtk_action_get_name (action), gtk_action_get_name (action), item_type, FALSE); g_free (path); path = g_build_path ("/", NEMO_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER, subdirectory, NULL); gtk_ui_manager_add_ui (ui_manager, view->details->extensions_menu_merge_id, path, gtk_action_get_name (action), gtk_action_get_name (action), item_type, FALSE); g_free (path); /* recursively fill the menu */ if (menu != NULL) { char *subdir; GList *children; children = nemo_menu_get_items (menu); subdir = g_build_path ("/", subdirectory, gtk_action_get_name (action), NULL); add_extension_menu_items (view, files, children, subdir); nemo_menu_item_list_free (children); g_free (subdir); } } } } static void reset_extension_actions_menu (NemoView *view, GList *selection) { GList *items; GtkUIManager *ui_manager; /* Clear any previous inserted items in the extension actions placeholder */ ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->extensions_menu_merge_id, &view->details->extensions_menu_action_group); nemo_ui_prepare_merge_ui (ui_manager, "DirExtensionsMenuGroup", &view->details->extensions_menu_merge_id, &view->details->extensions_menu_action_group); items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)), selection); if (items != NULL) { add_extension_menu_items (view, selection, items, ""); g_list_foreach (items, (GFunc) g_object_unref, NULL); g_list_free (items); } } static char * change_to_view_directory (NemoView *view) { char *path; char *old_path; old_path = g_get_current_dir (); path = get_view_directory (view); /* FIXME: What to do about non-local directories? */ if (path != NULL) { g_chdir (path); } g_free (path); return old_path; } static char ** get_file_names_as_parameter_array (GList *selection, NemoDirectory *model) { NemoFile *file; char **parameters; GList *node; GFile *file_location; GFile *model_location; int i; if (model == NULL) { return NULL; } parameters = g_new (char *, g_list_length (selection) + 1); model_location = nemo_directory_get_location (model); for (node = selection, i = 0; node != NULL; node = node->next, i++) { file = NEMO_FILE (node->data); if (!nemo_file_is_local (file)) { parameters[i] = NULL; g_strfreev (parameters); return NULL; } file_location = nemo_file_get_location (NEMO_FILE (node->data)); parameters[i] = g_file_get_relative_path (model_location, file_location); if (parameters[i] == NULL) { parameters[i] = g_file_get_path (file_location); } g_object_unref (file_location); } g_object_unref (model_location); parameters[i] = NULL; return parameters; } static char * get_file_paths_or_uris_as_newline_delimited_string (GList *selection, gboolean get_paths) { char *path; char *uri; char *result; NemoDesktopLink *link; GString *expanding_string; GList *node; GFile *location; expanding_string = g_string_new (""); for (node = selection; node != NULL; node = node->next) { uri = NULL; if (NEMO_IS_DESKTOP_ICON_FILE (node->data)) { link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (node->data)); if (link != NULL) { location = nemo_desktop_link_get_activation_location (link); uri = g_file_get_uri (location); g_object_unref (location); g_object_unref (G_OBJECT (link)); } } else { uri = nemo_file_get_uri (NEMO_FILE (node->data)); } if (uri == NULL) { continue; } if (get_paths) { path = g_filename_from_uri (uri, NULL, NULL); if (path != NULL) { g_string_append (expanding_string, path); g_free (path); g_string_append (expanding_string, "\n"); } } else { g_string_append (expanding_string, uri); g_string_append (expanding_string, "\n"); } g_free (uri); } result = expanding_string->str; g_string_free (expanding_string, FALSE); return result; } static char * get_file_paths_as_newline_delimited_string (GList *selection) { return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE); } static char * get_file_uris_as_newline_delimited_string (GList *selection) { return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE); } /* returns newly allocated strings for setting the environment variables */ static void get_strings_for_environment_variables (NemoView *view, GList *selected_files, char **file_paths, char **uris, char **uri) { char *directory_uri; /* We need to check that the directory uri starts with "file:" since * nemo_directory_is_local returns FALSE for nfs. */ directory_uri = nemo_directory_get_uri (view->details->model); if (g_str_has_prefix (directory_uri, "file:") || eel_uri_is_desktop (directory_uri) || eel_uri_is_trash (directory_uri)) { *file_paths = get_file_paths_as_newline_delimited_string (selected_files); } else { *file_paths = g_strdup (""); } g_free (directory_uri); *uris = get_file_uris_as_newline_delimited_string (selected_files); *uri = nemo_directory_get_uri (view->details->model); if (eel_uri_is_desktop (*uri)) { g_free (*uri); *uri = nemo_get_desktop_directory_uri (); } } static NemoView * get_directory_view_of_extra_pane (NemoView *view) { NemoWindowSlot *slot; NemoView *next_view; slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view)); if (slot != NULL) { next_view = nemo_window_slot_get_current_view (slot); if (NEMO_IS_VIEW (next_view)) { return NEMO_VIEW (next_view); } } return NULL; } /* * Set up some environment variables that scripts can use * to take advantage of the current Nemo state. */ static void set_script_environment_variables (NemoView *view, GList *selected_files) { char *file_paths; char *uris; char *uri; char *geometry_string; NemoView *next_view; get_strings_for_environment_variables (view, selected_files, &file_paths, &uris, &uri); g_setenv ("NEMO_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE); g_free (file_paths); g_setenv ("NEMO_SCRIPT_SELECTED_URIS", uris, TRUE); g_free (uris); g_setenv ("NEMO_SCRIPT_CURRENT_URI", uri, TRUE); g_free (uri); geometry_string = eel_gtk_window_get_geometry_string (GTK_WINDOW (nemo_view_get_containing_window (view))); g_setenv ("NEMO_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE); g_free (geometry_string); /* next pane */ next_view = get_directory_view_of_extra_pane (view); if (next_view) { GList *next_pane_selected_files; next_pane_selected_files = nemo_view_get_selection (next_view); get_strings_for_environment_variables (next_view, next_pane_selected_files, &file_paths, &uris, &uri); nemo_file_list_free (next_pane_selected_files); } else { file_paths = g_strdup(""); uris = g_strdup(""); uri = g_strdup(""); } g_setenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS", file_paths, TRUE); g_free (file_paths); g_setenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_URIS", uris, TRUE); g_free (uris); g_setenv ("NEMO_SCRIPT_NEXT_PANE_CURRENT_URI", uri, TRUE); g_free (uri); } /* Unset all the special script environment variables. */ static void unset_script_environment_variables (void) { g_unsetenv ("NEMO_SCRIPT_SELECTED_FILE_PATHS"); g_unsetenv ("NEMO_SCRIPT_SELECTED_URIS"); g_unsetenv ("NEMO_SCRIPT_CURRENT_URI"); g_unsetenv ("NEMO_SCRIPT_WINDOW_GEOMETRY"); g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS"); g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_URIS"); g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_CURRENT_URI"); } static void run_script_callback (GtkAction *action, gpointer callback_data) { ScriptLaunchParameters *launch_parameters; GdkScreen *screen; GList *selected_files; char *file_uri; char *local_file_path; char *quoted_path; char *old_working_dir; char **parameters; launch_parameters = (ScriptLaunchParameters *) callback_data; file_uri = nemo_file_get_uri (launch_parameters->file); local_file_path = g_filename_from_uri (file_uri, NULL, NULL); g_assert (local_file_path != NULL); g_free (file_uri); quoted_path = g_shell_quote (local_file_path); g_free (local_file_path); old_working_dir = change_to_view_directory (launch_parameters->directory_view); selected_files = nemo_view_get_selection (launch_parameters->directory_view); set_script_environment_variables (launch_parameters->directory_view, selected_files); parameters = get_file_names_as_parameter_array (selected_files, launch_parameters->directory_view->details->model); screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view)); DEBUG ("run_script_callback, script_path=\"%s\" (omitting script parameters)", local_file_path); nemo_launch_application_from_command_array (screen, quoted_path, FALSE, (const char * const *) parameters); g_strfreev (parameters); nemo_file_list_free (selected_files); unset_script_environment_variables (); g_chdir (old_working_dir); g_free (old_working_dir); g_free (quoted_path); } static void add_script_to_scripts_menus (NemoView *directory_view, NemoFile *file, const char *menu_path, const char *popup_path, const char *popup_bg_path) { ScriptLaunchParameters *launch_parameters; char *tip; char *name; char *uri; char *action_name; char *escaped_label; GdkPixbuf *pixbuf; GtkUIManager *ui_manager; GtkAction *action; name = nemo_file_get_display_name (file); uri = nemo_file_get_uri (file); tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name); launch_parameters = script_launch_parameters_new (file, directory_view); action_name = escape_action_name (uri, "script_"); escaped_label = eel_str_double_underscores (name); action = gtk_action_new (action_name, escaped_label, tip, NULL); pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view)); if (pixbuf != NULL) { gtk_action_set_gicon (action, G_ICON (pixbuf)); g_object_unref (pixbuf); } g_signal_connect_data (action, "activate", G_CALLBACK (run_script_callback), launch_parameters, (GClosureNotify)script_launch_parameters_free, 0); gtk_action_group_add_action_with_accel (directory_view->details->scripts_action_group, action, NULL); g_object_unref (action); ui_manager = nemo_window_get_ui_manager (directory_view->details->window); gtk_ui_manager_add_ui (ui_manager, directory_view->details->scripts_merge_id, menu_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); gtk_ui_manager_add_ui (ui_manager, directory_view->details->scripts_merge_id, popup_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); gtk_ui_manager_add_ui (ui_manager, directory_view->details->scripts_merge_id, popup_bg_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); menu_item_show_image (ui_manager, menu_path, action_name, FALSE); menu_item_show_image (ui_manager, popup_path, action_name, FALSE); menu_item_show_image (ui_manager, popup_bg_path, action_name, FALSE); g_free (name); g_free (uri); g_free (tip); g_free (action_name); g_free (escaped_label); } static void add_submenu_to_directory_menus (NemoView *directory_view, GtkActionGroup *action_group, guint merge_id, NemoFile *file, const char *menu_path, const char *popup_path, const char *popup_bg_path) { char *name; GdkPixbuf *pixbuf; char *uri; GtkUIManager *ui_manager; ui_manager = nemo_window_get_ui_manager (directory_view->details->window); uri = nemo_file_get_uri (file); name = nemo_file_get_display_name (file); pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view)); add_submenu (ui_manager, action_group, merge_id, menu_path, uri, name, pixbuf, TRUE); add_submenu (ui_manager, action_group, merge_id, popup_path, uri, name, pixbuf, FALSE); add_submenu (ui_manager, action_group, merge_id, popup_bg_path, uri, name, pixbuf, FALSE); if (pixbuf) { g_object_unref (pixbuf); } g_free (name); g_free (uri); } static gboolean directory_belongs_in_scripts_menu (const char *uri) { int num_levels; int i; if (!g_str_has_prefix (uri, scripts_directory_uri)) { return FALSE; } num_levels = 0; for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) { if (uri[i] == '/') { num_levels++; } } if (num_levels > MAX_MENU_LEVELS) { return FALSE; } return TRUE; } static gboolean update_directory_in_scripts_menu (NemoView *view, NemoDirectory *directory) { char *menu_path, *popup_path, *popup_bg_path; GList *file_list, *filtered, *node; gboolean any_scripts; NemoFile *file; NemoDirectory *dir; char *uri; char *escaped_path; uri = nemo_directory_get_uri (directory); escaped_path = escape_action_path (uri + scripts_directory_uri_length); g_free (uri); menu_path = g_strconcat (NEMO_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER, escaped_path, NULL); popup_path = g_strconcat (NEMO_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER, escaped_path, NULL); popup_bg_path = g_strconcat (NEMO_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER, escaped_path, NULL); g_free (escaped_path); file_list = nemo_directory_get_file_list (directory); filtered = nemo_file_list_filter_hidden (file_list, FALSE); nemo_file_list_free (file_list); file_list = nemo_file_list_sort_by_display_name (filtered); any_scripts = FALSE; for (node = file_list; node != NULL; node = node->next) { file = node->data; if (nemo_file_is_launchable (file) && nemo_global_preferences_should_load_plugin (nemo_file_peek_name (file), NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS)) { add_script_to_scripts_menus (view, file, menu_path, popup_path, popup_bg_path); any_scripts = TRUE; } else if (nemo_file_is_directory (file)) { uri = nemo_file_get_uri (file); if (directory_belongs_in_scripts_menu (uri)) { dir = nemo_directory_get_by_uri (uri); add_directory_to_scripts_directory_list (view, dir); nemo_directory_unref (dir); add_submenu_to_directory_menus (view, view->details->scripts_action_group, view->details->scripts_merge_id, file, menu_path, popup_path, popup_bg_path); any_scripts = TRUE; } g_free (uri); } } nemo_file_list_free (file_list); g_free (popup_path); g_free (popup_bg_path); g_free (menu_path); return any_scripts; } static void update_scripts_menu (NemoView *view) { gboolean any_scripts; GList *sorted_copy, *node; NemoDirectory *directory; char *uri; GtkUIManager *ui_manager; GtkAction *action; /* There is a race condition here. If we don't mark the scripts menu as valid before we begin our task then we can lose script menu updates that occur before we finish. */ view->details->scripts_invalid = FALSE; ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->scripts_merge_id, &view->details->scripts_action_group); nemo_ui_prepare_merge_ui (ui_manager, "ScriptsGroup", &view->details->scripts_merge_id, &view->details->scripts_action_group); /* As we walk through the directories, remove any that no longer belong. */ any_scripts = FALSE; sorted_copy = nemo_directory_list_sort_by_uri (nemo_directory_list_copy (view->details->scripts_directory_list)); for (node = sorted_copy; node != NULL; node = node->next) { directory = node->data; uri = nemo_directory_get_uri (directory); if (!directory_belongs_in_scripts_menu (uri)) { remove_directory_from_scripts_directory_list (view, directory); } else if (update_directory_in_scripts_menu (view, directory)) { any_scripts = TRUE; } g_free (uri); } nemo_directory_list_free (sorted_copy); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SCRIPTS); gtk_action_set_visible (action, any_scripts); } static void run_action_callback (NemoAction *action, gpointer callback_data) { NemoView *view = NEMO_VIEW (callback_data); GList *selected_files; selected_files = nemo_view_get_selection (view); NemoFile *parent = nemo_view_get_directory_as_file (view); nemo_action_activate (action, selected_files, parent); nemo_file_list_free (selected_files); } typedef struct { NemoView *view; GList *selection; } ActionVisibilityData; static void determine_visibility (gpointer data, gpointer callback_data) { NemoAction *action = NEMO_ACTION (data); ActionVisibilityData *av_data = (ActionVisibilityData *) callback_data; GList *selection; NemoView *view; view = av_data->view; selection = av_data->selection; NemoFile *parent = nemo_view_get_directory_as_file (view); if (nemo_action_get_visibility (action, selection, parent, FALSE)) { gchar *label, *tt; label = nemo_action_get_label (action, selection, parent); tt = nemo_action_get_tt (action, selection, parent); gtk_action_set_label (GTK_ACTION (action), label); gtk_action_set_tooltip (GTK_ACTION (action), tt); g_free (label); g_free (tt); gtk_action_set_visible (GTK_ACTION (action), TRUE); } else { gtk_action_set_visible (GTK_ACTION (action), FALSE); } } static void update_actions_visibility (NemoView *view, GList *selection) { GList *actions = gtk_action_group_list_actions (view->details->actions_action_group); ActionVisibilityData data; data.view = view; data.selection = selection; g_list_foreach (actions, determine_visibility, &data); g_list_free (actions); } static void add_action_to_action_menus (NemoView *directory_view, NemoAction *action, const char *menu_path, const char *popup_path, const char *popup_bg_path) { GtkUIManager *ui_manager; const gchar *action_name = gtk_action_get_name (GTK_ACTION (action)); gtk_action_group_add_action (directory_view->details->actions_action_group, GTK_ACTION (action)); gtk_action_set_visible (GTK_ACTION (action), FALSE); g_signal_handlers_disconnect_by_func (action, run_action_callback, directory_view); g_signal_connect (action, "activate", G_CALLBACK (run_action_callback), directory_view); ui_manager = nemo_window_get_ui_manager (directory_view->details->window); gtk_ui_manager_add_ui (ui_manager, directory_view->details->actions_merge_id, menu_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); gtk_ui_manager_add_ui (ui_manager, directory_view->details->actions_merge_id, popup_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); gtk_ui_manager_add_ui (ui_manager, directory_view->details->actions_merge_id, popup_bg_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); } static void update_actions (NemoView *view) { NemoAction *action; GList *action_list, *node; action_list = nemo_action_manager_list_actions (view->details->action_manager); for (node = action_list; node != NULL; node = node->next) { action = node->data; add_action_to_action_menus (view, action, NEMO_VIEW_MENU_PATH_ACTIONS_PLACEHOLDER, NEMO_VIEW_POPUP_PATH_ACTIONS_PLACEHOLDER, NEMO_VIEW_POPUP_PATH_BACKGROUND_ACTIONS_PLACEHOLDER); } } static void update_actions_menu (NemoView *view) { GtkUIManager *ui_manager; view->details->actions_invalid = FALSE; ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->actions_merge_id, &view->details->actions_action_group); nemo_ui_prepare_merge_ui (ui_manager, "ActionsGroup", &view->details->actions_merge_id, &view->details->actions_action_group); update_actions (view); } static void create_template_callback (GtkAction *action, gpointer callback_data) { CreateTemplateParameters *parameters; parameters = callback_data; nemo_view_new_file (parameters->directory_view, NULL, parameters->file); } static void add_template_to_templates_menus (NemoView *directory_view, NemoFile *file, const char *menu_path, const char *popup_bg_path) { char *tmp, *tip, *uri, *name; char *escaped_label; GdkPixbuf *pixbuf; char *action_name; CreateTemplateParameters *parameters; GtkUIManager *ui_manager; GtkAction *action; tmp = nemo_file_get_display_name (file); name = eel_filename_strip_extension (tmp); g_free (tmp); uri = nemo_file_get_uri (file); tip = g_strdup_printf (_("Create a new document from template \"%s\""), name); action_name = escape_action_name (uri, "template_"); escaped_label = eel_str_double_underscores (name); parameters = create_template_parameters_new (file, directory_view); action = gtk_action_new (action_name, escaped_label, tip, NULL); pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view)); if (pixbuf != NULL) { gtk_action_set_gicon (action, G_ICON (pixbuf)); g_object_unref (pixbuf); } g_signal_connect_data (action, "activate", G_CALLBACK (create_template_callback), parameters, (GClosureNotify)create_templates_parameters_free, 0); gtk_action_group_add_action (directory_view->details->templates_action_group, action); g_object_unref (action); ui_manager = nemo_window_get_ui_manager (directory_view->details->window); gtk_ui_manager_add_ui (ui_manager, directory_view->details->templates_merge_id, menu_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); gtk_ui_manager_add_ui (ui_manager, directory_view->details->templates_merge_id, popup_bg_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); menu_item_show_image (ui_manager, menu_path, action_name, TRUE); menu_item_show_image (ui_manager, popup_bg_path, action_name, TRUE); g_free (escaped_label); g_free (name); g_free (tip); g_free (uri); g_free (action_name); } static void update_templates_directory (NemoView *view) { NemoDirectory *templates_directory; GList *node, *next; char *templates_uri; for (node = view->details->templates_directory_list; node != NULL; node = next) { next = node->next; remove_directory_from_templates_directory_list (view, node->data); } if (nemo_should_use_templates_directory ()) { templates_uri = nemo_get_templates_directory_uri (); templates_directory = nemo_directory_get_by_uri (templates_uri); g_free (templates_uri); add_directory_to_templates_directory_list (view, templates_directory); nemo_directory_unref (templates_directory); } } static void user_dirs_changed (NemoView *view) { update_templates_directory (view); view->details->templates_invalid = TRUE; schedule_update_menus (view); } static gboolean directory_belongs_in_templates_menu (const char *templates_directory_uri, const char *uri) { int num_levels; int i; if (templates_directory_uri == NULL) { return FALSE; } if (!g_str_has_prefix (uri, templates_directory_uri)) { return FALSE; } num_levels = 0; for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++) { if (uri[i] == '/') { num_levels++; } } if (num_levels > MAX_MENU_LEVELS) { return FALSE; } return TRUE; } static gboolean update_directory_in_templates_menu (NemoView *view, const char *templates_directory_uri, NemoDirectory *directory) { char *menu_path, *popup_bg_path; GList *file_list, *filtered, *node; gboolean any_templates; NemoFile *file; NemoDirectory *dir; char *escaped_path; char *uri; int num; /* We know this directory belongs to the template dir, so it must exist */ g_assert (templates_directory_uri); uri = nemo_directory_get_uri (directory); escaped_path = escape_action_path (uri + strlen (templates_directory_uri)); g_free (uri); menu_path = g_strconcat (NEMO_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER, escaped_path, NULL); popup_bg_path = g_strconcat (NEMO_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER, escaped_path, NULL); g_free (escaped_path); file_list = nemo_directory_get_file_list (directory); filtered = nemo_file_list_filter_hidden (file_list, FALSE); nemo_file_list_free (file_list); file_list = nemo_file_list_sort_by_display_name (filtered); num = 0; any_templates = FALSE; for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) { file = node->data; if (nemo_file_is_directory (file)) { uri = nemo_file_get_uri (file); if (directory_belongs_in_templates_menu (templates_directory_uri, uri)) { dir = nemo_directory_get_by_uri (uri); add_directory_to_templates_directory_list (view, dir); nemo_directory_unref (dir); add_submenu_to_directory_menus (view, view->details->templates_action_group, view->details->templates_merge_id, file, menu_path, NULL, popup_bg_path); any_templates = TRUE; } g_free (uri); } else if (nemo_file_can_read (file)) { add_template_to_templates_menus (view, file, menu_path, popup_bg_path); any_templates = TRUE; } } nemo_file_list_free (file_list); g_free (popup_bg_path); g_free (menu_path); return any_templates; } static void update_templates_menu (NemoView *view) { gboolean any_templates; GList *sorted_copy, *node; NemoDirectory *directory; GtkUIManager *ui_manager; char *uri; GtkAction *action; char *templates_directory_uri; if (nemo_should_use_templates_directory ()) { templates_directory_uri = nemo_get_templates_directory_uri (); } else { templates_directory_uri = NULL; } /* There is a race condition here. If we don't mark the scripts menu as valid before we begin our task then we can lose template menu updates that occur before we finish. */ view->details->templates_invalid = FALSE; ui_manager = nemo_window_get_ui_manager (view->details->window); nemo_ui_unmerge_ui (ui_manager, &view->details->templates_merge_id, &view->details->templates_action_group); nemo_ui_prepare_merge_ui (ui_manager, "TemplatesGroup", &view->details->templates_merge_id, &view->details->templates_action_group); /* As we walk through the directories, remove any that no longer belong. */ any_templates = FALSE; sorted_copy = nemo_directory_list_sort_by_uri (nemo_directory_list_copy (view->details->templates_directory_list)); for (node = sorted_copy; node != NULL; node = node->next) { directory = node->data; uri = nemo_directory_get_uri (directory); if (!directory_belongs_in_templates_menu (templates_directory_uri, uri)) { remove_directory_from_templates_directory_list (view, directory); } else if (update_directory_in_templates_menu (view, templates_directory_uri, directory)) { any_templates = TRUE; } g_free (uri); } nemo_directory_list_free (sorted_copy); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_NO_TEMPLATES); gtk_action_set_visible (action, !any_templates); g_free (templates_directory_uri); } static GtkMenu * create_popup_menu (NemoView *view, const char *popup_path) { GtkWidget *menu; menu = gtk_ui_manager_get_widget (nemo_window_get_ui_manager (view->details->window), popup_path); gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (GTK_WIDGET (view))); gtk_widget_show (GTK_WIDGET (menu)); return GTK_MENU (menu); } static void copy_or_cut_files (NemoView *view, GList *clipboard_contents, gboolean cut) { int count; char *status_string, *name; NemoClipboardInfo info; GtkTargetList *target_list; GtkTargetEntry *targets; int n_targets; info.files = clipboard_contents; info.cut = cut; target_list = gtk_target_list_new (NULL, 0); gtk_target_list_add (target_list, copied_files_atom, 0, 0); gtk_target_list_add_uri_targets (target_list, 0); gtk_target_list_add_text_targets (target_list, 0); targets = gtk_target_table_new_from_list (target_list, &n_targets); gtk_target_list_unref (target_list); gtk_clipboard_set_with_data (nemo_clipboard_get (GTK_WIDGET (view)), targets, n_targets, nemo_get_clipboard_callback, nemo_clear_clipboard_callback, NULL); gtk_target_table_free (targets, n_targets); nemo_clipboard_monitor_set_clipboard_info (nemo_clipboard_monitor_get (), &info); count = g_list_length (clipboard_contents); if (count == 1) { name = nemo_file_get_display_name (clipboard_contents->data); if (cut) { status_string = g_strdup_printf (_("\"%s\" will be moved " "if you select the Paste command"), name); } else { status_string = g_strdup_printf (_("\"%s\" will be copied " "if you select the Paste command"), name); } g_free (name); } else { if (cut) { status_string = g_strdup_printf (ngettext("The %'d selected item will be moved " "if you select the Paste command", "The %'d selected items will be moved " "if you select the Paste command", count), count); } else { status_string = g_strdup_printf (ngettext("The %'d selected item will be copied " "if you select the Paste command", "The %'d selected items will be copied " "if you select the Paste command", count), count); } } nemo_window_slot_set_status (view->details->slot, status_string, NULL); g_free (status_string); } static void action_copy_files_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection_for_file_transfer (view); copy_or_cut_files (view, selection, FALSE); nemo_file_list_free (selection); } static void move_copy_selection_to_next_pane (NemoView *view, int copy_action) { NemoWindowSlot *slot; char *dest_location; slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view)); g_return_if_fail (slot != NULL); dest_location = nemo_window_slot_get_current_uri (slot); g_return_if_fail (dest_location != NULL); move_copy_selection_to_location (view, copy_action, dest_location); } static void action_copy_to_next_pane_callback (GtkAction *action, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); move_copy_selection_to_next_pane (view, GDK_ACTION_COPY); } static void action_move_to_next_pane_callback (GtkAction *action, gpointer callback_data) { NemoWindowSlot *slot; char *dest_location; NemoView *view; view = NEMO_VIEW (callback_data); slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view)); g_return_if_fail (slot != NULL); dest_location = nemo_window_slot_get_current_uri (slot); g_return_if_fail (dest_location != NULL); move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location); } static void action_copy_to_home_callback (GtkAction *action, gpointer callback_data) { NemoView *view; char *dest_location; view = NEMO_VIEW (callback_data); dest_location = nemo_get_home_directory_uri (); move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location); g_free (dest_location); } static void action_move_to_home_callback (GtkAction *action, gpointer callback_data) { NemoView *view; char *dest_location; view = NEMO_VIEW (callback_data); dest_location = nemo_get_home_directory_uri (); move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location); g_free (dest_location); } static void action_copy_to_desktop_callback (GtkAction *action, gpointer callback_data) { NemoView *view; char *dest_location; view = NEMO_VIEW (callback_data); dest_location = nemo_get_desktop_directory_uri (); move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location); g_free (dest_location); } static void action_move_to_desktop_callback (GtkAction *action, gpointer callback_data) { NemoView *view; char *dest_location; view = NEMO_VIEW (callback_data); dest_location = nemo_get_desktop_directory_uri (); move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location); g_free (dest_location); } static void browse_move_to_response_cb (GtkDialog *dialog, gint response, NemoView *view) { gchar *uri; switch (response) { case GTK_RESPONSE_OK: uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); move_copy_selection_to_location (view, GDK_ACTION_MOVE, uri); g_free (uri); break; case GTK_RESPONSE_CANCEL: default: break; } gtk_widget_destroy (GTK_WIDGET (dialog)); } static void browse_copy_to_response_cb (GtkDialog *dialog, gint response, NemoView *view) { gchar *uri; switch (response) { case GTK_RESPONSE_OK: uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); move_copy_selection_to_location (view, GDK_ACTION_COPY, uri); g_free (uri); break; case GTK_RESPONSE_CANCEL: default: break; } gtk_widget_destroy (GTK_WIDGET (dialog)); } static void action_browse_for_move_to_folder_callback (GtkAction *action, gpointer callback_data) { GtkWidget *dialog; NemoView *view; view = NEMO_VIEW (callback_data); dialog = gtk_file_chooser_dialog_new (_("Select Target Folder For Move"), nemo_view_get_containing_window (view), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE); g_signal_connect (dialog, "response", G_CALLBACK (browse_move_to_response_cb), view); gtk_widget_show (dialog); } static void action_browse_for_copy_to_folder_callback (GtkAction *action, gpointer callback_data) { GtkWidget *dialog; NemoView *view; view = NEMO_VIEW (callback_data); dialog = gtk_file_chooser_dialog_new (_("Select Target Folder For Copy"), nemo_view_get_containing_window (view), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE); g_signal_connect (dialog, "response", G_CALLBACK (browse_copy_to_response_cb), view); gtk_widget_show (dialog); } static void action_cut_files_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection_for_file_transfer (view); copy_or_cut_files (view, selection, TRUE); nemo_file_list_free (selection); } static void paste_clipboard_data (NemoView *view, GtkSelectionData *selection_data, char *destination_uri) { gboolean cut; GList *item_uris; cut = FALSE; item_uris = nemo_clipboard_get_uri_list_from_selection_data (selection_data, &cut, copied_files_atom); if (item_uris == NULL|| destination_uri == NULL) { nemo_window_slot_set_status (view->details->slot, _("There is nothing on the clipboard to paste."), NULL); } else { nemo_view_move_copy_items (view, item_uris, NULL, destination_uri, cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY, 0, 0); /* If items are cut then remove from clipboard */ if (cut) { gtk_clipboard_clear (nemo_clipboard_get (GTK_WIDGET (view))); } g_list_free_full (item_uris, g_free); } } static void paste_clipboard_received_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) { NemoView *view; char *view_uri; view = NEMO_VIEW (data); view_uri = nemo_view_get_backing_uri (view); if (view->details->window != NULL) { paste_clipboard_data (view, selection_data, view_uri); } g_free (view_uri); g_object_unref (view); } typedef struct { NemoView *view; NemoFile *target; } PasteIntoData; static void paste_into_clipboard_received_callback (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer callback_data) { PasteIntoData *data; NemoView *view; char *directory_uri; data = (PasteIntoData *) callback_data; view = NEMO_VIEW (data->view); if (view->details->window != NULL) { directory_uri = nemo_file_get_activation_uri (data->target); paste_clipboard_data (view, selection_data, directory_uri); g_free (directory_uri); } g_object_unref (view); nemo_file_unref (data->target); g_free (data); } static void action_paste_files_callback (GtkAction *action, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); g_object_ref (view); gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view)), copied_files_atom, paste_clipboard_received_callback, view); } static void paste_into (NemoView *view, NemoFile *target) { PasteIntoData *data; g_assert (NEMO_IS_VIEW (view)); g_assert (NEMO_IS_FILE (target)); data = g_new (PasteIntoData, 1); data->view = g_object_ref (view); data->target = nemo_file_ref (target); gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view)), copied_files_atom, paste_into_clipboard_received_callback, data); } static void cb_open_as_root_watch (GPid pid, gint status, gpointer user_data) { g_spawn_close_pid(pid); } static void open_as_root (const gchar *path) { gchar *argv[4]; argv[0] = (gchar *)"pkexec"; argv[1] = (gchar *)"nemo"; argv[2] = g_strdup (path); argv[3] = NULL; GPid pid; g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL); g_child_watch_add(pid, (GChildWatchFunc)cb_open_as_root_watch, NULL); g_free (argv[2]); } static void open_in_terminal (const gchar *path) { gchar *argv[2]; argv[0] = g_settings_get_string (gnome_terminal_preferences, GNOME_DESKTOP_TERMINAL_EXEC); argv[1] = NULL; g_spawn_async(path, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); } static void action_paste_files_into_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (selection != NULL) { paste_into (view, NEMO_FILE (selection->data)); nemo_file_list_free (selection); } } static void action_open_as_root_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (selection != NULL) { gchar *path = nemo_file_get_path (NEMO_FILE (selection->data)); open_as_root (path); nemo_file_list_free (selection); g_free (path); } else { gchar *path; gchar *uri = nemo_view_get_uri (view); GFile *gfile = g_file_new_for_uri (uri); if (g_file_has_uri_scheme (gfile, "x-nemo-desktop")) { path = nemo_get_desktop_directory (); } else { path = g_file_get_path (gfile); } open_as_root (path); g_free (uri); g_free (path); g_object_unref (gfile); } } static void action_follow_symlink_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (nemo_file_is_symbolic_link (selection->data)) { gchar *uri = nemo_file_get_symbolic_link_target_uri (selection->data); gchar *view_uri = nemo_view_get_uri (view); GFile *location = g_file_new_for_uri (uri); GFile *parent = g_file_get_parent (location); GFile *current = g_file_new_for_uri (view_uri); if (g_file_equal (current, parent)) { nemo_view_scroll_to_file (view, uri); GList *l = NULL; l = g_list_append (l, nemo_file_get_existing (location)); nemo_view_set_selection (view, l); } else { if (get_is_desktop_view (view)) { nemo_mime_launch_fm_and_select_file (location); } else { nemo_window_slot_open_location (view->details->slot, location, 0); } } g_free (uri); g_free (view_uri); g_object_unref (location); g_object_unref (parent); g_object_unref (current); } nemo_file_list_free (selection); } static void action_open_containing_folder_callback (GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; NemoFile *item; GFile *activation_location; NemoFile *activation_file; NemoFile *location; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); item = NEMO_FILE (selection->data); activation_location = nemo_file_get_activation_location (item); activation_file = nemo_file_get (activation_location); location = nemo_file_get_parent (activation_file); nemo_view_activate_file (view, location, 0); nemo_file_unref (location); nemo_file_unref (activation_file); g_object_unref (activation_location); } static void action_open_in_terminal_callback(GtkAction *action, gpointer callback_data) { NemoView *view; GList *selection; view = NEMO_VIEW (callback_data); selection = nemo_view_get_selection (view); if (selection != NULL) { gchar *path; if (nemo_file_is_directory (NEMO_FILE (selection->data))) { path = nemo_file_get_path (NEMO_FILE (selection->data)); } else { NemoFile *location = nemo_file_get_parent (NEMO_FILE (selection->data)); path = nemo_file_get_path (location); nemo_file_unref (location); } open_in_terminal (path); g_free (path); nemo_file_list_free (selection); } else { gchar *path; gchar *uri = nemo_view_get_uri (view); GFile *gfile = g_file_new_for_uri (uri); if (g_file_has_uri_scheme (gfile, "x-nemo-desktop")) { path = nemo_get_desktop_directory (); } else { path = g_file_get_path (gfile); } open_in_terminal (path); g_free (uri); g_free (path); g_object_unref (gfile); } } static void invoke_external_bulk_rename_utility (NemoView *view, GList *selection) { GString *cmd; char *parameter; char *quoted_parameter; char *bulk_rename_tool; GList *walk; NemoFile *file; /* assemble command line */ bulk_rename_tool = get_bulk_rename_tool (); cmd = g_string_new (bulk_rename_tool); g_free (bulk_rename_tool); for (walk = selection; walk; walk = walk->next) { file = walk->data; parameter = nemo_file_get_uri (file); quoted_parameter = g_shell_quote (parameter); g_free (parameter); cmd = g_string_append (cmd, " "); cmd = g_string_append (cmd, quoted_parameter); g_free (quoted_parameter); } guint i = 0; // Escape percents for (i = 0; i < strlen(cmd->str); i++) { if (cmd->str[i] == '%') { g_string_insert_c(cmd, i++, '%'); } } /* spawning and error handling */ nemo_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (view)), cmd->str, FALSE, NULL); g_string_free (cmd, TRUE); } static void real_action_undo (NemoView *view) { GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); nemo_file_undo_manager_undo (GTK_WINDOW (toplevel)); } static void real_action_redo (NemoView *view) { GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); nemo_file_undo_manager_redo (GTK_WINDOW (toplevel)); } static void action_undo_callback (GtkAction *action, gpointer callback_data) { real_action_undo (NEMO_VIEW (callback_data)); } static void action_redo_callback (GtkAction *action, gpointer callback_data) { real_action_redo (NEMO_VIEW (callback_data)); } static void real_action_rename (NemoView *view, gboolean select_all) { NemoFile *file; GList *selection; g_assert (NEMO_IS_VIEW (view)); selection = nemo_view_get_selection (view); if (selection_not_empty_in_menu_callback (view, selection)) { /* If there is more than one file selected, invoke a batch renamer */ if (selection->next != NULL) { if (have_bulk_rename_tool ()) { invoke_external_bulk_rename_utility (view, selection); } } else { file = NEMO_FILE (selection->data); if (!select_all) { /* directories don't have a file extension, so * they are always pre-selected as a whole */ select_all = nemo_file_is_directory (file); } NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, file, select_all); } } nemo_file_list_free (selection); } static void action_rename_callback (GtkAction *action, gpointer callback_data) { real_action_rename (NEMO_VIEW (callback_data), FALSE); } static void action_rename_select_all_callback (GtkAction *action, gpointer callback_data) { real_action_rename (NEMO_VIEW (callback_data), TRUE); } static void file_mount_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { if (error != NULL && (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED))) { eel_show_error_dialog (_("Unable to mount location"), error->message, NULL); } } static void file_unmount_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); g_object_unref (view); if (error != NULL && (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED))) { eel_show_error_dialog (_("Unable to unmount location"), error->message, NULL); } } static void file_eject_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { NemoView *view; view = NEMO_VIEW (callback_data); g_object_unref (view); if (error != NULL && (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED))) { eel_show_error_dialog (_("Unable to eject location"), error->message, NULL); } } static void file_stop_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { if (error != NULL && (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED))) { eel_show_error_dialog (_("Unable to stop drive"), error->message, NULL); } } static void action_mount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_mount (file)) { mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); nemo_file_mount (file, mount_op, NULL, file_mount_callback, NULL); g_object_unref (mount_op); } } nemo_file_list_free (selection); } static void action_unmount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_unmount (file)) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view)); g_object_unref (mount_op); } } nemo_file_list_free (selection); } static void action_eject_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_eject (file)) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view)); g_object_unref (mount_op); } } nemo_file_list_free (selection); } static void file_start_callback (NemoFile *file, GFile *result_location, GError *error, gpointer callback_data) { if (error != NULL && (error->domain != G_IO_ERROR || (error->code != G_IO_ERROR_CANCELLED && error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED))) { eel_show_error_dialog (_("Unable to start location"), error->message, NULL); } } static void action_start_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) { mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_start (file, mount_op, NULL, file_start_callback, NULL); g_object_unref (mount_op); } } nemo_file_list_free (selection); } static void action_stop_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_stop (file)) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_stop (file, mount_op, NULL, file_stop_callback, NULL); g_object_unref (mount_op); } } nemo_file_list_free (selection); } static void action_detect_media_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection, *l; NemoView *view; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); for (l = selection; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) { nemo_file_poll_for_media (file); } } nemo_file_list_free (selection); } static void action_self_mount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); nemo_file_mount (file, mount_op, NULL, file_mount_callback, NULL); g_object_unref (mount_op); } static void action_self_unmount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view)); g_object_unref (mount_op); } static void action_self_eject_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view)); g_object_unref (mount_op); } static void action_self_start_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_start (file, mount_op, NULL, file_start_callback, NULL); g_object_unref (mount_op); } static void action_self_stop_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_stop (file, mount_op, NULL, file_stop_callback, NULL); g_object_unref (mount_op); } static void action_self_detect_media_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; view = NEMO_VIEW (data); file = nemo_view_get_directory_as_file (view); if (file == NULL) { return; } nemo_file_poll_for_media (file); } static void action_location_mount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); nemo_file_mount (file, mount_op, NULL, file_mount_callback, NULL); g_object_unref (mount_op); } static void action_location_unmount_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view)); g_object_unref (mount_op); } static void action_location_eject_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view)); g_object_unref (mount_op); } static void action_location_start_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_start (file, mount_op, NULL, file_start_callback, NULL); g_object_unref (mount_op); } static void action_location_stop_volume_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; GMountOperation *mount_op; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view)); nemo_file_stop (file, mount_op, NULL, file_stop_callback, NULL); g_object_unref (mount_op); } static void action_location_detect_media_callback (GtkAction *action, gpointer data) { NemoFile *file; NemoView *view; view = NEMO_VIEW (data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } nemo_file_poll_for_media (file); } static void connect_to_server_response_callback (GtkDialog *dialog, int response_id, gpointer data) { #ifdef GIO_CONVERSION_DONE GtkEntry *entry; char *uri; const char *name; char *icon; entry = GTK_ENTRY (data); switch (response_id) { case GTK_RESPONSE_OK: uri = g_object_get_data (G_OBJECT (dialog), "link-uri"); icon = g_object_get_data (G_OBJECT (dialog), "link-icon"); name = gtk_entry_get_text (entry); gnome_vfs_connect_to_server (uri, (char *)name, icon); gtk_widget_destroy (GTK_WIDGET (dialog)); break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CANCEL: gtk_widget_destroy (GTK_WIDGET (dialog)); break; default : g_assert_not_reached (); } #endif /* FIXME: the above code should make a server connection permanent */ gtk_widget_destroy (GTK_WIDGET (dialog)); } static void entry_activate_callback (GtkEntry *entry, gpointer user_data) { GtkDialog *dialog; dialog = GTK_DIALOG (user_data); gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); } static void action_connect_to_server_link_callback (GtkAction *action, gpointer data) { NemoFile *file; GList *selection; NemoView *view; char *uri; NemoIconInfo *icon; const char *icon_name; char *name; GtkWidget *dialog; GtkWidget *label; GtkWidget *entry; GtkWidget *box; char *title; view = NEMO_VIEW (data); selection = nemo_view_get_selection (view); if (g_list_length (selection) != 1) { nemo_file_list_free (selection); return; } file = NEMO_FILE (selection->data); uri = nemo_file_get_activation_uri (file); icon = nemo_file_get_icon (file, NEMO_ICON_SIZE_STANDARD, 0, gtk_widget_get_scale_factor (GTK_WIDGET (view)), 0); icon_name = nemo_icon_info_get_used_name (icon); name = nemo_file_get_display_name (file); if (uri != NULL) { title = g_strdup_printf (_("Connect to Server %s"), name); dialog = gtk_dialog_new_with_buttons (title, nemo_view_get_containing_window (view), 0, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Connect"), GTK_RESPONSE_OK, NULL); g_object_set_data_full (G_OBJECT (dialog), "link-uri", g_strdup (uri), g_free); g_object_set_data_full (G_OBJECT (dialog), "link-icon", g_strdup (icon_name), g_free); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_widget_show (box); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), box, TRUE, TRUE, 0); label = gtk_label_new_with_mnemonic (_("Link _name:")); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 12); entry = gtk_entry_new (); if (name) { gtk_entry_set_text (GTK_ENTRY (entry), name); } g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_callback), dialog); gtk_widget_show (entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 12); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); g_signal_connect (dialog, "response", G_CALLBACK (connect_to_server_response_callback), entry); gtk_widget_show (dialog); } g_free (uri); nemo_icon_info_unref (icon); g_free (name); } static void action_location_open_alternate_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } nemo_view_activate_file (view, file, NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW); } static void action_location_open_in_new_tab_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; if (file == NULL) { return; } nemo_view_activate_file (view, file, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); } static void action_location_cut_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; GList *files; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; g_return_if_fail (file != NULL); files = g_list_append (NULL, file); copy_or_cut_files (view, files, TRUE); g_list_free (files); } static void action_location_copy_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; GList *files; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; g_return_if_fail (file != NULL); files = g_list_append (NULL, file); copy_or_cut_files (view, files, FALSE); g_list_free (files); } static void action_location_paste_files_into_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; g_return_if_fail (file != NULL); paste_into (view, file); } static void action_location_trash_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; GList *files; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; g_return_if_fail (file != NULL); files = g_list_append (NULL, file); trash_or_delete_files (nemo_view_get_containing_window (view), files, TRUE, view); g_list_free (files); } static void action_location_delete_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; GFile *location; GList *files; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; g_return_if_fail (file != NULL); location = nemo_file_get_location (file); files = g_list_append (NULL, location); nemo_file_operations_delete (files, nemo_view_get_containing_window (view), NULL, NULL); g_list_free_full (files, g_object_unref); } static void action_location_restore_from_trash_callback (GtkAction *action, gpointer callback_data) { NemoView *view; NemoFile *file; GList l; view = NEMO_VIEW (callback_data); file = view->details->location_popup_directory_as_file; l.prev = NULL; l.next = NULL; l.data = file; nemo_restore_files_from_trash (&l, nemo_view_get_containing_window (view)); } static void nemo_view_init_show_hidden_files (NemoView *view) { NemoWindowShowHiddenFilesMode mode; gboolean show_hidden_changed; if (view->details->ignore_hidden_file_preferences) { return; } mode = nemo_window_get_hidden_files_mode (view->details->window); if (mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE) { show_hidden_changed = !view->details->show_hidden_files; view->details->show_hidden_files = TRUE; } else { show_hidden_changed = view->details->show_hidden_files; view->details->show_hidden_files = FALSE; } if (show_hidden_changed && (view->details->model != NULL)) { load_directory (view, view->details->model); } } static const GtkActionEntry directory_view_entries[] = { /* name, stock id, label */ { "New Documents", "document-new-symbolic", N_("Create New _Document") }, /* name, stock id, label */ { "Open With", NULL, N_("Open Wit_h"), NULL, N_("Choose a program with which to open the selected item") }, /* name, stock id */ { "Properties", "document-properties-symbolic", /* label, accelerator */ N_("_Properties"), "Return", /* tooltip */ N_("View or modify the properties of each selected item"), G_CALLBACK (action_properties_callback) }, /* name, stock id */ { "PropertiesAccel", NULL, /* label, accelerator */ "PropertiesAccel", "I", /* tooltip */ NULL, G_CALLBACK (action_properties_callback) }, /* name, stock id */ { "New Folder", "folder-new-symbolic", /* label, accelerator */ N_("Create New _Folder"), "N", /* tooltip */ N_("Create a new empty folder inside this folder"), G_CALLBACK (action_new_folder_callback) }, /* name, stock id, label */ { "No Templates", NULL, N_("No templates installed") }, /* name, stock id */ { "New Empty Document", NULL, /* translators: this is used to indicate that a document doesn't contain anything */ /* label, accelerator */ N_("_Empty Document"), NULL, /* tooltip */ N_("Create a new empty document inside this folder"), G_CALLBACK (action_new_empty_file_callback) }, /* name, stock id */ { "Open", NULL, /* label, accelerator */ N_("_Open"), "o", /* tooltip */ N_("Open the selected item in this window"), G_CALLBACK (action_open_callback) }, /* name, stock id */ { "OpenAccel", NULL, /* label, accelerator */ "OpenAccel", "Down", /* tooltip */ NULL, G_CALLBACK (action_open_callback) }, /* name, stock id */ { "OpenAlternate", NULL, /* label, accelerator */ N_("Open in Navigation Window"), "o", /* tooltip */ N_("Open each selected item in a navigation window"), G_CALLBACK (action_open_alternate_callback) }, /* name, stock id */ { "OpenInNewTab", NULL, /* label, accelerator */ N_("Open in New _Tab"), "t", /* tooltip */ N_("Open each selected item in a new tab"), G_CALLBACK (action_open_new_tab_callback) }, /* name, stock id */ { NEMO_ACTION_OPEN_IN_TERMINAL, "utilities-terminal-symbolic", /* label, accelerator */ N_("Open in Terminal"), "", /* tooltip */ N_("Open terminal in the selected folder"), G_CALLBACK (action_open_in_terminal_callback) }, /* name, stock id */ { NEMO_ACTION_OPEN_AS_ROOT, "dialog-password-symbolic", /* label, accelerator */ N_("Open as Root"), "", /* tooltip */ N_("Open the folder with administration privileges"), G_CALLBACK (action_open_as_root_callback) }, /* name, stock id */ { NEMO_ACTION_FOLLOW_SYMLINK, "go-jump-symbolic", /* label, accelerator */ N_("Follow link to original file"), "", /* tooltip */ N_("Navigate to the original file that this symbolic link points to"), G_CALLBACK (action_follow_symlink_callback) }, /* name, stock id */ { NEMO_ACTION_OPEN_CONTAINING_FOLDER, "go-jump-symbolic", /* label, accelerator */ N_("Open containing folder"), "O", /* tooltip */ N_("Navigate to the folder that the selected item is stored in"), G_CALLBACK (action_open_containing_folder_callback) }, /* name, stock id */ { "OtherApplication1", NULL, /* label, accelerator */ N_("Other _Application..."), NULL, /* tooltip */ N_("Choose another application with which to open the selected item"), G_CALLBACK (action_other_application_callback) }, /* name, stock id */ { "OtherApplication2", NULL, /* label, accelerator */ N_("Open With Other _Application..."), NULL, /* tooltip */ N_("Choose another application with which to open the selected item"), G_CALLBACK (action_other_application_callback) }, /* name, stock id */ { "Empty Trash", NULL, /* label, accelerator */ N_("E_mpty Trash"), NULL, /* tooltip */ N_("Delete all items in the Trash"), G_CALLBACK (action_empty_trash_callback) }, /* name, stock id */ { "Cut", "edit-cut-symbolic", /* label, accelerator */ N_("Cu_t"), "X", /* tooltip */ N_("Prepare the selected files to be moved with a Paste command"), G_CALLBACK (action_cut_files_callback) }, /* name, stock id */ { "Copy", "edit-copy-symbolic", /* label, accelerator */ N_("_Copy"), "C", /* tooltip */ N_("Prepare the selected files to be copied with a Paste command"), G_CALLBACK (action_copy_files_callback) }, /* name, stock id */ { "Paste", "edit-paste-symbolic", /* label, accelerator */ N_("_Paste"), "V", /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command"), G_CALLBACK (action_paste_files_callback) }, /* We make accelerator "" instead of null here to not inherit the stock accelerator for paste */ /* name, stock id */ { "Paste Files Into", "edit-paste-symbolic", /* label, accelerator */ N_("_Paste Into Folder"), "", /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into the selected folder"), G_CALLBACK (action_paste_files_into_callback) }, /* name, stock id, label */ { "CopyToMenu", NULL, N_("Cop_y to") }, /* name, stock id, label */ { "MoveToMenu", NULL, N_("M_ove to") }, /* name, stock id */ { "Select All", NULL, /* label, accelerator */ N_("Select _All"), "A", /* tooltip */ N_("Select all items in this window"), G_CALLBACK (action_select_all_callback) }, /* name, stock id */ { "Select Pattern", NULL, /* label, accelerator */ N_("Select I_tems Matching..."), "S", /* tooltip */ N_("Select items in this window matching a given pattern"), G_CALLBACK (action_select_pattern_callback) }, /* name, stock id */ { "Invert Selection", NULL, /* label, accelerator */ N_("_Invert Selection"), "I", /* tooltip */ N_("Select all and only the items that are not currently selected"), G_CALLBACK (action_invert_selection_callback) }, /* name, stock id */ { "Duplicate", NULL, /* label, accelerator */ N_("D_uplicate"), NULL, /* tooltip */ N_("Duplicate each selected item"), G_CALLBACK (action_duplicate_callback) }, /* name, stock id */ { "Create Link", NULL, /* label, accelerator */ N_("Ma_ke Link"), "M", /* tooltip */ N_("Create a symbolic link for each selected item"), G_CALLBACK (action_create_link_callback) }, /* name, stock id */ { "Rename", NULL, /* label, accelerator */ N_("_Rename..."), "F2", /* tooltip */ N_("Rename selected item"), G_CALLBACK (action_rename_callback) }, /* name, stock id */ { "RenameSelectAll", NULL, /* label, accelerator */ "RenameSelectAll", "F2", /* tooltip */ NULL, G_CALLBACK (action_rename_select_all_callback) }, /* name, stock id */ { "Trash", NULL, /* label, accelerator */ N_("Mo_ve to Trash"), NULL, /* tooltip */ N_("Move each selected item to the Trash"), G_CALLBACK (action_trash_callback) }, /* name, stock id */ { "Delete", NULL, /* label, accelerator */ N_("_Delete"), NULL, /* tooltip */ N_("Delete each selected item, without moving to the Trash"), G_CALLBACK (action_delete_callback) }, /* name, stock id */ { "Restore From Trash", NULL, /* label, accelerator */ N_("_Restore"), NULL, NULL, G_CALLBACK (action_restore_from_trash_callback) }, /* name, stock id */ { "Undo", "edit-undo-symbolic", /* label, accelerator */ N_("_Undo"), "Z", /* tooltip */ N_("Undo the last action"), G_CALLBACK (action_undo_callback) }, /* name, stock id */ { "Redo", "edit-redo-symbolic", /* label, accelerator */ N_("_Redo"), "Y", /* tooltip */ N_("Redo the last undone action"), G_CALLBACK (action_redo_callback) }, /* * multiview-TODO: decide whether "Reset to Defaults" should * be window-wide, and not just view-wide. * Since this also resets the "Show hidden files" mode, * it is a mixture of both ATM. */ /* name, stock id */ { "Reset to Defaults", NULL, /* label, accelerator */ N_("Reset View to _Defaults"), NULL, /* tooltip */ N_("Reset sorting order and zoom level to match preferences for this view"), G_CALLBACK (action_reset_to_defaults_callback) }, /* name, stock id */ { "Connect To Server Link", NULL, /* label, accelerator */ N_("Connect To This Server"), NULL, /* tooltip */ N_("Make a permanent connection to this server"), G_CALLBACK (action_connect_to_server_link_callback) }, /* name, stock id */ { "Mount Volume", "media-mount-symbolic", /* label, accelerator */ N_("_Mount"), NULL, /* tooltip */ N_("Mount the selected volume"), G_CALLBACK (action_mount_volume_callback) }, /* name, stock id */ { "Unmount Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Unmount"), NULL, /* tooltip */ N_("Unmount the selected volume"), G_CALLBACK (action_unmount_volume_callback) }, /* name, stock id */ { "Eject Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Eject"), NULL, /* tooltip */ N_("Eject the selected volume"), G_CALLBACK (action_eject_volume_callback) }, /* name, stock id */ { "Start Volume", NULL, /* label, accelerator */ N_("_Start"), NULL, /* tooltip */ N_("Start the selected volume"), G_CALLBACK (action_start_volume_callback) }, /* name, stock id */ { "Stop Volume", NULL, /* label, accelerator */ N_("_Stop"), NULL, /* tooltip */ N_("Stop the selected volume"), G_CALLBACK (action_stop_volume_callback) }, /* name, stock id */ { "Poll", NULL, /* label, accelerator */ N_("_Detect Media"), NULL, /* tooltip */ N_("Detect media in the selected drive"), G_CALLBACK (action_detect_media_callback) }, /* name, stock id */ { "Self Mount Volume", "media-mount-symbolic", /* label, accelerator */ N_("_Mount"), NULL, /* tooltip */ N_("Mount the volume associated with the open folder"), G_CALLBACK (action_self_mount_volume_callback) }, /* name, stock id */ { "Self Unmount Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Unmount"), NULL, /* tooltip */ N_("Unmount the volume associated with the open folder"), G_CALLBACK (action_self_unmount_volume_callback) }, /* name, stock id */ { "Self Eject Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Eject"), NULL, /* tooltip */ N_("Eject the volume associated with the open folder"), G_CALLBACK (action_self_eject_volume_callback) }, /* name, stock id */ { "Self Start Volume", NULL, /* label, accelerator */ N_("_Start"), NULL, /* tooltip */ N_("Start the volume associated with the open folder"), G_CALLBACK (action_self_start_volume_callback) }, /* name, stock id */ { "Self Stop Volume", NULL, /* label, accelerator */ N_("_Stop"), NULL, /* tooltip */ N_("Stop the volume associated with the open folder"), G_CALLBACK (action_self_stop_volume_callback) }, /* name, stock id */ { "Self Poll", NULL, /* label, accelerator */ N_("_Detect Media"), NULL, /* tooltip */ N_("Detect media in the selected drive"), G_CALLBACK (action_self_detect_media_callback) }, /* name, stock id */ { "OpenCloseParent", NULL, /* label, accelerator */ N_("Open File and Close window"), "Down", /* tooltip */ NULL, G_CALLBACK (action_open_close_parent_callback) }, /* name, stock id */ { "Save Search", NULL, /* label, accelerator */ N_("Sa_ve Search"), NULL, /* tooltip */ N_("Save the edited search"), G_CALLBACK (action_save_search_callback) }, /* name, stock id */ { "Save Search As", NULL, /* label, accelerator */ N_("Sa_ve Search As..."), NULL, /* tooltip */ N_("Save the current search as a file"), G_CALLBACK (action_save_search_as_callback) }, /* Location-specific actions */ /* name, stock id */ { NEMO_ACTION_LOCATION_OPEN_ALTERNATE, NULL, /* label, accelerator */ N_("Open in Navigation Window"), "", /* tooltip */ N_("Open this folder in a navigation window"), G_CALLBACK (action_location_open_alternate_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_OPEN_IN_NEW_TAB, NULL, /* label, accelerator */ N_("Open in New _Tab"), "", /* tooltip */ N_("Open this folder in a new tab"), G_CALLBACK (action_location_open_in_new_tab_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_CUT, "edit-cut-symbolic", /* label, accelerator */ N_("Cu_t"), "", /* tooltip */ N_("Prepare this folder to be moved with a Paste command"), G_CALLBACK (action_location_cut_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_COPY, "edit-copy-symbolic", /* label, accelerator */ N_("_Copy"), "", /* tooltip */ N_("Prepare this folder to be copied with a Paste command"), G_CALLBACK (action_location_copy_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_PASTE_FILES_INTO, "edit-paste-symbolic", /* label, accelerator */ N_("_Paste Into Folder"), "", /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into this folder"), G_CALLBACK (action_location_paste_files_into_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_TRASH, NULL, /* label, accelerator */ N_("Mo_ve to Trash"), "", /* tooltip */ N_("Move this folder to the Trash"), G_CALLBACK (action_location_trash_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_DELETE, NEMO_ICON_DELETE, /* label, accelerator */ N_("_Delete"), "", /* tooltip */ N_("Delete this folder, without moving to the Trash"), G_CALLBACK (action_location_delete_callback) }, /* name, stock id */ { NEMO_ACTION_LOCATION_RESTORE_FROM_TRASH, NULL, /* label, accelerator */ N_("_Restore"), NULL, NULL, G_CALLBACK (action_location_restore_from_trash_callback) }, /* name, stock id */ { "Location Mount Volume", "media-mount-symbolic", /* label, accelerator */ N_("_Mount"), NULL, /* tooltip */ N_("Mount the volume associated with this folder"), G_CALLBACK (action_location_mount_volume_callback) }, /* name, stock id */ { "Location Unmount Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Unmount"), NULL, /* tooltip */ N_("Unmount the volume associated with this folder"), G_CALLBACK (action_location_unmount_volume_callback) }, /* name, stock id */ { "Location Eject Volume", "media-eject-symbolic", /* label, accelerator */ N_("_Eject"), NULL, /* tooltip */ N_("Eject the volume associated with this folder"), G_CALLBACK (action_location_eject_volume_callback) }, /* name, stock id */ { "Location Start Volume", NULL, /* label, accelerator */ N_("_Start"), NULL, /* tooltip */ N_("Start the volume associated with this folder"), G_CALLBACK (action_location_start_volume_callback) }, /* name, stock id */ { "Location Stop Volume", NULL, /* label, accelerator */ N_("_Stop"), NULL, /* tooltip */ N_("Stop the volume associated with this folder"), G_CALLBACK (action_location_stop_volume_callback) }, /* name, stock id */ { "Location Poll", NULL, /* label, accelerator */ N_("_Detect Media"), NULL, /* tooltip */ N_("Detect media in the selected drive"), G_CALLBACK (action_location_detect_media_callback) }, /* name, stock id */ { "LocationProperties", "document-properties-symbolic", /* label, accelerator */ N_("_Properties"), NULL, /* tooltip */ N_("View or modify the properties of this folder"), G_CALLBACK (action_location_properties_callback) }, /* name, stock id, label */ {NEMO_ACTION_COPY_TO_NEXT_PANE, NULL, N_("_Other pane"), NULL, N_("Copy the current selection to the other pane in the window"), G_CALLBACK (action_copy_to_next_pane_callback) }, /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_NEXT_PANE, NULL, N_("_Other pane"), NULL, N_("Move the current selection to the other pane in the window"), G_CALLBACK (action_move_to_next_pane_callback) }, /* name, stock id, label */ {NEMO_ACTION_COPY_TO_HOME, NULL, N_("_Home"), NULL, N_("Copy the current selection to the home folder"), G_CALLBACK (action_copy_to_home_callback) }, /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_HOME, NULL, N_("_Home"), NULL, N_("Move the current selection to the home folder"), G_CALLBACK (action_move_to_home_callback) }, /* name, stock id, label */ {NEMO_ACTION_COPY_TO_DESKTOP, NULL, N_("_Desktop"), NULL, N_("Copy the current selection to the desktop"), G_CALLBACK (action_copy_to_desktop_callback) }, /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_DESKTOP, NULL, N_("_Desktop"), NULL, N_("Move the current selection to the desktop"), G_CALLBACK (action_move_to_desktop_callback) }, {NEMO_ACTION_BROWSE_MOVE_TO, "document-open-symbolic", N_("Browse..."), NULL, N_("Browse for a folder to move the selection to"), G_CALLBACK (action_browse_for_move_to_folder_callback) }, {NEMO_ACTION_BROWSE_COPY_TO, "document-open-symbolic", N_("Browse..."), NULL, N_("Browse for a folder to copy the selection to"), G_CALLBACK (action_browse_for_copy_to_folder_callback) }, {NEMO_ACTION_PIN_FILE, "view-pin-symbolic", N_("P_in"), "D", N_("Pin the selected file so it always appears at the top of this location's file list"), G_CALLBACK (action_pin_unpin_file_callback) }, {NEMO_ACTION_UNPIN_FILE, "view-pin-symbolic", N_("Unp_in"), "D", N_("Unpin the selected file from the top of this location's file list"), G_CALLBACK (action_pin_unpin_file_callback) } }; static void connect_proxy (NemoView *view, GtkAction *action, GtkWidget *proxy, GtkActionGroup *action_group) { if (strcmp (gtk_action_get_name (action), NEMO_ACTION_NEW_EMPTY_DOCUMENT) == 0 && GTK_IS_IMAGE_MENU_ITEM (proxy)) { GtkWidget *image; image = gtk_image_new_from_icon_name ("text-x-generic", GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), image); gtk_action_set_always_show_image (action, TRUE); } } static void pre_activate (NemoView *view, GtkAction *action, GtkActionGroup *action_group) { GdkEvent *event; GtkWidget *proxy; gboolean activated_from_popup; /* check whether action was activated through a popup menu. * If not, unset the last stored context menu popup position */ activated_from_popup = FALSE; event = gtk_get_current_event (); proxy = gtk_get_event_widget (event); if (proxy != NULL) { GtkWidget *toplevel; GdkWindowTypeHint hint; toplevel = gtk_widget_get_toplevel (proxy); if (GTK_IS_WINDOW (toplevel)) { hint = gtk_window_get_type_hint (GTK_WINDOW (toplevel)); if (hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) { activated_from_popup = TRUE; } } } if (!activated_from_popup) { update_context_menu_position_from_event (view, NULL); } } static void real_merge_menus (NemoView *view) { GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkAction *action; char *tooltip; ui_manager = nemo_window_get_ui_manager (view->details->window); action_group = gtk_action_group_new ("DirViewActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); view->details->dir_action_group = action_group; gtk_action_group_add_actions (action_group, directory_view_entries, G_N_ELEMENTS (directory_view_entries), view); tooltip = g_strdup_printf (_("Run scripts")); /* Create a script action here specially because its tooltip is dynamic */ action = gtk_action_new ("Scripts", _("_Scripts"), tooltip, NULL); gtk_action_group_add_action (action_group, action); g_object_unref (action); g_free (tooltip); action = gtk_action_group_get_action (action_group, NEMO_ACTION_NO_TEMPLATES); gtk_action_set_sensitive (action, FALSE); g_signal_connect_object (action_group, "connect-proxy", G_CALLBACK (connect_proxy), G_OBJECT (view), G_CONNECT_SWAPPED); g_signal_connect_object (action_group, "pre-activate", G_CALLBACK (pre_activate), G_OBJECT (view), G_CONNECT_SWAPPED); /* Insert action group at end so clipboard action group ends up before it */ gtk_ui_manager_insert_action_group (ui_manager, action_group, -1); g_object_unref (action_group); /* owned by ui manager */ view->details->dir_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-directory-view-ui.xml", NULL); view->details->scripts_invalid = TRUE; view->details->templates_invalid = TRUE; view->details->actions_invalid = TRUE; } static gboolean can_paste_into_file (NemoFile *file) { if (nemo_file_is_directory (file) && nemo_file_can_write (file)) { return TRUE; } if (nemo_file_has_activation_uri (file)) { GFile *location; NemoFile *activation_file; gboolean res; location = nemo_file_get_activation_location (file); activation_file = nemo_file_get (location); g_object_unref (location); /* The target location might not have data for it read yet, and we can't want to do sync I/O, so treat the unknown case as can-write */ res = (nemo_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) || (nemo_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY && nemo_file_can_write (activation_file)); nemo_file_unref (activation_file); return res; } return FALSE; } static void clipboard_targets_received (GtkClipboard *clipboard, GdkAtom *targets, int n_targets, gpointer user_data) { NemoView *view; gboolean can_paste; int i; GList *selection; int count; GtkAction *action; view = NEMO_VIEW (user_data); can_paste = FALSE; if (view->details->window == NULL || !view->details->active) { /* We've been destroyed or became inactive since call */ g_object_unref (view); return; } if (targets) { for (i=0; i < n_targets; i++) { if (targets[i] == copied_files_atom) { can_paste = TRUE; } } } selection = nemo_file_list_ref (nemo_view_peek_selection (view)); count = nemo_view_get_selection_count (view); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PASTE); gtk_action_set_sensitive (action, can_paste && !nemo_view_is_read_only (view)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PASTE_FILES_INTO); gtk_action_set_sensitive (action, can_paste && count == 1 && can_paste_into_file (NEMO_FILE (selection->data))); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_PASTE_FILES_INTO); g_object_set_data (G_OBJECT (action), "can-paste-according-to-clipboard", GINT_TO_POINTER (can_paste)); gtk_action_set_sensitive (action, GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), "can-paste-according-to-clipboard")) && GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), "can-paste-according-to-destination"))); nemo_file_list_unref (selection); g_object_unref (view); } static gboolean should_show_empty_trash (NemoView *view) { return (showing_trash_directory (view)); } static gboolean file_list_all_are_folders (GList *file_list) { GList *l; NemoFile *file, *linked_file; char *activation_uri; gboolean is_dir; for (l = file_list; l != NULL; l = l->next) { file = NEMO_FILE (l->data); if (nemo_file_is_nemo_link (file) && !NEMO_IS_DESKTOP_ICON_FILE (file)) { if (nemo_file_is_launcher (file)) { return FALSE; } activation_uri = nemo_file_get_activation_uri (file); if (activation_uri == NULL) { g_free (activation_uri); return FALSE; } linked_file = nemo_file_get_existing_by_uri (activation_uri); /* We might not actually know the type of the linked file yet, * however we don't want to schedule a read, since that might do things * like ask for password etc. This is a bit unfortunate, but I don't * know any way around it, so we do various heuristics here * to get things mostly right */ is_dir = (linked_file != NULL && nemo_file_is_directory (linked_file)) || (activation_uri != NULL && activation_uri[strlen (activation_uri) - 1] == '/'); nemo_file_unref (linked_file); g_free (activation_uri); if (!is_dir) { return FALSE; } } else if (!(nemo_file_is_directory (file) || NEMO_IS_DESKTOP_ICON_FILE (file))) { return FALSE; } } return TRUE; } static void file_should_show_foreach (NemoFile *file, gboolean *show_mount, gboolean *show_unmount, gboolean *show_eject, gboolean *show_connect, gboolean *show_start, gboolean *show_stop, gboolean *show_poll, GDriveStartStopType *start_stop_type) { char *uri; *show_mount = FALSE; *show_unmount = FALSE; *show_eject = FALSE; *show_connect = FALSE; *show_start = FALSE; *show_stop = FALSE; *show_poll = FALSE; if (nemo_file_can_eject (file)) { *show_eject = TRUE; } if (nemo_file_can_mount (file)) { *show_mount = TRUE; } if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) { *show_start = TRUE; } if (nemo_file_can_stop (file)) { *show_stop = TRUE; } /* Dot not show both Unmount and Eject/Safe Removal; too confusing to * have too many menu entries */ if (nemo_file_can_unmount (file) && !*show_eject && !*show_stop) { *show_unmount = TRUE; } if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) { *show_poll = TRUE; } *start_stop_type = nemo_file_get_start_stop_type (file); if (nemo_file_is_nemo_link (file)) { uri = nemo_file_get_activation_uri (file); if (uri != NULL && (g_str_has_prefix (uri, "ftp:") || g_str_has_prefix (uri, "ssh:") || g_str_has_prefix (uri, "sftp:") || g_str_has_prefix (uri, "dav:") || g_str_has_prefix (uri, "davs:"))) { *show_connect = TRUE; } g_free (uri); } } static void file_should_show_self (NemoFile *file, gboolean *show_mount, gboolean *show_unmount, gboolean *show_eject, gboolean *show_start, gboolean *show_stop, gboolean *show_poll, GDriveStartStopType *start_stop_type) { *show_mount = FALSE; *show_unmount = FALSE; *show_eject = FALSE; *show_start = FALSE; *show_stop = FALSE; *show_poll = FALSE; if (file == NULL) { return; } if (nemo_file_can_eject (file)) { *show_eject = TRUE; } if (nemo_file_can_mount (file)) { *show_mount = TRUE; } if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) { *show_start = TRUE; } if (nemo_file_can_stop (file)) { *show_stop = TRUE; } /* Dot not show both Unmount and Eject/Safe Removal; too confusing to * have too many menu entries */ if (nemo_file_can_unmount (file) && !*show_eject && !*show_stop) { *show_unmount = TRUE; } if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) { *show_poll = TRUE; } *start_stop_type = nemo_file_get_start_stop_type (file); } static gboolean files_are_all_directories (GList *files) { NemoFile *file; GList *l; gboolean all_directories; all_directories = TRUE; for (l = files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); all_directories &= nemo_file_is_directory (file); } return all_directories; } static gboolean files_is_none_directory (GList *files) { NemoFile *file; GList *l; gboolean no_directory; no_directory = TRUE; for (l = files; l != NULL; l = l->next) { file = NEMO_FILE (l->data); no_directory &= !nemo_file_is_directory (file); } return no_directory; } static void update_restore_from_trash_action (GtkAction *action, GList *files, gboolean is_self) { NemoFile *original_file; NemoFile *original_dir; GHashTable *original_dirs_hash; GList *original_dirs; GFile *original_location; char *tooltip, *original_name; original_file = NULL; original_dir = NULL; original_dirs = NULL; original_dirs_hash = NULL; original_location = NULL; original_name = NULL; if (files != NULL) { if (g_list_length (files) == 1) { original_file = nemo_file_get_trash_original_file (files->data); } else { original_dirs_hash = nemo_trashed_files_get_original_directories (files, NULL); if (original_dirs_hash != NULL) { original_dirs = g_hash_table_get_keys (original_dirs_hash); if (g_list_length (original_dirs) == 1) { original_dir = nemo_file_ref (NEMO_FILE (original_dirs->data)); } } } } if (original_file != NULL || original_dirs != NULL) { gtk_action_set_visible (action, TRUE); if (original_file != NULL) { original_location = nemo_file_get_location (original_file); } else if (original_dir != NULL) { original_location = nemo_file_get_location (original_dir); } if (original_location != NULL) { original_name = g_file_get_parse_name (original_location); } if (is_self) { g_assert (g_list_length (files) == 1); g_assert (original_location != NULL); tooltip = g_strdup_printf (_("Move the open folder out of the trash to \"%s\""), original_name); } else if (files_are_all_directories (files)) { if (original_name != NULL) { tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash to \"%s\"", "Move the selected folders out of the trash to \"%s\"", g_list_length (files)), original_name); } else { tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash", "Move the selected folders out of the trash", g_list_length (files))); } } else if (files_is_none_directory (files)) { if (original_name != NULL) { tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash to \"%s\"", "Move the selected files out of the trash to \"%s\"", g_list_length (files)), original_name); } else { tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash", "Move the selected files out of the trash", g_list_length (files))); } } else { if (original_name != NULL) { tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash to \"%s\"", "Move the selected items out of the trash to \"%s\"", g_list_length (files)), original_name); } else { tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash", "Move the selected items out of the trash", g_list_length (files))); } } g_free (original_name); g_object_set (action, "tooltip", tooltip, NULL); g_free (tooltip); if (original_location != NULL) { g_object_unref (original_location); } } else { gtk_action_set_visible (action, FALSE); } nemo_file_unref (original_file); nemo_file_unref (original_dir); g_list_free (original_dirs); if (original_dirs_hash != NULL) { g_hash_table_destroy (original_dirs_hash); } } static void real_update_menus_volumes (NemoView *view, GList *selection, gint selection_count) { GList *l; NemoFile *file; gboolean show_mount; gboolean show_unmount; gboolean show_eject; gboolean show_connect; gboolean show_start; gboolean show_stop; gboolean show_poll; GDriveStartStopType start_stop_type; gboolean show_self_mount; gboolean show_self_unmount; gboolean show_self_eject; gboolean show_self_start; gboolean show_self_stop; gboolean show_self_poll; GDriveStartStopType self_start_stop_type; GtkAction *action; show_mount = (selection != NULL); show_unmount = (selection != NULL); show_eject = (selection != NULL); show_connect = (selection != NULL && selection_count == 1); show_start = (selection != NULL && selection_count == 1); show_stop = (selection != NULL && selection_count == 1); show_poll = (selection != NULL && selection_count == 1); start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; self_start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; for (l = selection; l != NULL && (show_mount || show_unmount || show_eject || show_connect || show_start || show_stop || show_poll); l = l->next) { gboolean show_mount_one; gboolean show_unmount_one; gboolean show_eject_one; gboolean show_connect_one; gboolean show_start_one; gboolean show_stop_one; gboolean show_poll_one; file = NEMO_FILE (l->data); file_should_show_foreach (file, &show_mount_one, &show_unmount_one, &show_eject_one, &show_connect_one, &show_start_one, &show_stop_one, &show_poll_one, &start_stop_type); show_mount &= show_mount_one; show_unmount &= show_unmount_one; show_eject &= show_eject_one; show_connect &= show_connect_one; show_start &= show_start_one; show_stop &= show_stop_one; show_poll &= show_poll_one; } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_CONNECT_TO_SERVER_LINK); gtk_action_set_visible (action, show_connect); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOUNT_VOLUME); gtk_action_set_visible (action, show_mount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_UNMOUNT_VOLUME); gtk_action_set_visible (action, show_unmount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_EJECT_VOLUME); gtk_action_set_visible (action, show_eject); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_START_VOLUME); gtk_action_set_visible (action, show_start); if (show_start) { switch (start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the selected drive")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the selected drive")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Connect")); gtk_action_set_tooltip (action, _("Connect to the selected drive")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Start Multi-disk Drive")); gtk_action_set_tooltip (action, _("Start the selected multi-disk drive")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("U_nlock Drive")); gtk_action_set_tooltip (action, _("Unlock the selected drive")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_STOP_VOLUME); gtk_action_set_visible (action, show_stop); if (show_stop) { switch (start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Stop")); gtk_action_set_tooltip (action, _("Stop the selected drive")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Safely Remove Drive")); gtk_action_set_tooltip (action, _("Safely remove the selected drive")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Disconnect")); gtk_action_set_tooltip (action, _("Disconnect the selected drive")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Stop Multi-disk Drive")); gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("_Lock Drive")); gtk_action_set_tooltip (action, _("Lock the selected drive")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_POLL); gtk_action_set_visible (action, show_poll); show_self_mount = show_self_unmount = show_self_eject = show_self_start = show_self_stop = show_self_poll = FALSE; file = nemo_view_get_directory_as_file (view); file_should_show_self (file, &show_self_mount, &show_self_unmount, &show_self_eject, &show_self_start, &show_self_stop, &show_self_poll, &self_start_stop_type); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_MOUNT_VOLUME); gtk_action_set_visible (action, show_self_mount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_UNMOUNT_VOLUME); gtk_action_set_visible (action, show_self_unmount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_EJECT_VOLUME); gtk_action_set_visible (action, show_self_eject); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_START_VOLUME); gtk_action_set_visible (action, show_self_start); if (show_self_start) { switch (self_start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Connect")); gtk_action_set_tooltip (action, _("Connect to the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Start Multi-disk Drive")); gtk_action_set_tooltip (action, _("Start the multi-disk drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("_Unlock Drive")); gtk_action_set_tooltip (action, _("Unlock the drive associated with the open folder")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_STOP_VOLUME); gtk_action_set_visible (action, show_self_stop); if (show_self_stop) { switch (self_start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Stop")); gtk_action_set_tooltip (action, _("_Stop the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Safely Remove Drive")); gtk_action_set_tooltip (action, _("Safely remove the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Disconnect")); gtk_action_set_tooltip (action, _("Disconnect the drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Stop Multi-disk Drive")); gtk_action_set_tooltip (action, _("Stop the multi-disk drive associated with the open folder")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("_Lock Drive")); gtk_action_set_tooltip (action, _("Lock the drive associated with the open folder")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELF_POLL); gtk_action_set_visible (action, show_self_poll); } static void real_update_location_menu_volumes (NemoView *view) { GtkAction *action; NemoFile *file; gboolean show_mount; gboolean show_unmount; gboolean show_eject; gboolean show_connect; gboolean show_start; gboolean show_stop; gboolean show_poll; GDriveStartStopType start_stop_type; g_assert (NEMO_IS_VIEW (view)); g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file)); file = NEMO_FILE (view->details->location_popup_directory_as_file); file_should_show_foreach (file, &show_mount, &show_unmount, &show_eject, &show_connect, &show_start, &show_stop, &show_poll, &start_stop_type); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_MOUNT_VOLUME); gtk_action_set_visible (action, show_mount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_UNMOUNT_VOLUME); gtk_action_set_visible (action, show_unmount); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_EJECT_VOLUME); gtk_action_set_visible (action, show_eject); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_START_VOLUME); gtk_action_set_visible (action, show_start); if (show_start) { switch (start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the selected drive")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Start")); gtk_action_set_tooltip (action, _("Start the selected drive")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Connect")); gtk_action_set_tooltip (action, _("Connect to the selected drive")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Start Multi-disk Drive")); gtk_action_set_tooltip (action, _("Start the selected multi-disk drive")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("_Unlock Drive")); gtk_action_set_tooltip (action, _("Unlock the selected drive")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_STOP_VOLUME); gtk_action_set_visible (action, show_stop); if (show_stop) { switch (start_stop_type) { default: case G_DRIVE_START_STOP_TYPE_UNKNOWN: gtk_action_set_label (action, _("_Stop")); gtk_action_set_tooltip (action, _("Stop the selected volume")); break; case G_DRIVE_START_STOP_TYPE_SHUTDOWN: gtk_action_set_label (action, _("_Safely Remove Drive")); gtk_action_set_tooltip (action, _("Safely remove the selected drive")); break; case G_DRIVE_START_STOP_TYPE_NETWORK: gtk_action_set_label (action, _("_Disconnect")); gtk_action_set_tooltip (action, _("Disconnect the selected drive")); break; case G_DRIVE_START_STOP_TYPE_MULTIDISK: gtk_action_set_label (action, _("_Stop Multi-disk Drive")); gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive")); break; case G_DRIVE_START_STOP_TYPE_PASSWORD: gtk_action_set_label (action, _("_Lock Drive")); gtk_action_set_tooltip (action, _("Lock the selected drive")); break; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_POLL); gtk_action_set_visible (action, show_poll); } /* TODO: we should split out this routine into two functions: * Update on clipboard changes * Update on selection changes */ static void real_update_paste_menu (NemoView *view, GList *selection, gint selection_count) { gboolean can_paste_files_into; gboolean selection_is_read_only; gboolean selection_contains_recent; gboolean is_read_only; GtkAction *action; selection_is_read_only = selection_count == 1 && (!nemo_file_can_write (NEMO_FILE (selection->data)) && !nemo_file_has_activation_uri (NEMO_FILE (selection->data))); is_read_only = nemo_view_is_read_only (view); selection_contains_recent = showing_recent_directory (view); can_paste_files_into = (!selection_contains_recent && selection_count == 1 && can_paste_into_file (NEMO_FILE (selection->data))); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PASTE); gtk_action_set_sensitive (action, !is_read_only); gtk_action_set_visible (action, !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PASTE_FILES_INTO); gtk_action_set_visible (action, can_paste_files_into); gtk_action_set_sensitive (action, !selection_is_read_only); /* Ask the clipboard */ g_object_ref (view); /* Need to keep the object alive until we get the reply */ gtk_clipboard_request_targets (nemo_clipboard_get (GTK_WIDGET (view)), clipboard_targets_received, view); } static void real_update_location_menu (NemoView *view) { GtkAction *action; NemoFile *file; gboolean is_special_link; gboolean is_desktop_or_home_dir; gboolean is_recent; gboolean can_delete_file, show_delete; gboolean show_separate_delete_command; gboolean show_open_in_new_tab; gboolean show_open_alternate; GList l; char *label; char *tip; show_open_in_new_tab = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); show_open_alternate = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_OPEN_ALTERNATE); gtk_action_set_visible (action, show_open_alternate); label = _("Open in New _Window"); g_object_set (action, "label", label, NULL); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_OPEN_IN_NEW_TAB); gtk_action_set_visible (action, show_open_in_new_tab); label = _("Open in New _Tab"); g_object_set (action, "label", label, NULL); file = view->details->location_popup_directory_as_file; g_assert (NEMO_IS_FILE (file)); g_assert (nemo_file_check_if_ready (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO)); is_special_link = NEMO_IS_DESKTOP_ICON_FILE (file); is_desktop_or_home_dir = nemo_file_is_home (file) || nemo_file_is_desktop_directory (file); is_recent = nemo_file_is_in_recent (file); can_delete_file = nemo_file_can_delete (file) && !is_special_link && !is_desktop_or_home_dir; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_CUT); gtk_action_set_sensitive (action, !is_recent && can_delete_file); gtk_action_set_visible (action, !is_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_PASTE_FILES_INTO); g_object_set_data (G_OBJECT (action), "can-paste-according-to-destination", GINT_TO_POINTER (can_paste_into_file (file))); gtk_action_set_sensitive (action, !is_recent && GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), "can-paste-according-to-clipboard")) && GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), "can-paste-according-to-destination"))); gtk_action_set_visible (action, !is_recent); show_delete = TRUE; if (file != NULL && nemo_file_is_in_trash (file)) { if (nemo_file_is_self_owned (file)) { show_delete = FALSE; } label = _("_Delete Permanently"); tip = _("Delete the open folder permanently"); show_separate_delete_command = FALSE; } else { label = _("Mo_ve to Trash"); tip = _("Move the open folder to the Trash"); show_separate_delete_command = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE); } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_TRASH); g_object_set (action, "label", label, "tooltip", tip, "icon-name", (file != NULL && nemo_file_is_in_trash (file)) ? NEMO_ICON_DELETE : NEMO_ICON_SYMBOLIC_TRASH_FULL, NULL); gtk_action_set_sensitive (action, can_delete_file); gtk_action_set_visible (action, show_delete); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_DELETE); gtk_action_set_visible (action, show_separate_delete_command); if (show_separate_delete_command) { gtk_action_set_sensitive (action, can_delete_file); g_object_set (action, "icon-name", NEMO_ICON_DELETE, "sensitive", can_delete_file, NULL); } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_LOCATION_RESTORE_FROM_TRASH); l.prev = NULL; l.next = NULL; l.data = file; update_restore_from_trash_action (action, &l, TRUE); real_update_location_menu_volumes (view); } static void clipboard_changed_callback (NemoClipboardMonitor *monitor, NemoView *view) { GList *selection; gint selection_count; if (!view->details->active) { return; } selection = nemo_file_list_ref (nemo_view_peek_selection (view)); selection_count = nemo_view_get_selection_count (view); real_update_paste_menu (view, selection, selection_count); nemo_file_list_unref (selection); } static gboolean can_delete_all (GList *files) { NemoFile *file; GList *l; for (l = files; l != NULL; l = l->next) { file = l->data; if (!nemo_file_can_delete (file)) { return FALSE; } } return TRUE; } static gboolean has_writable_extra_pane (NemoView *view) { NemoView *other_view; other_view = get_directory_view_of_extra_pane (view); if (other_view != NULL) { return !nemo_view_is_read_only (other_view); } return FALSE; } static void update_configurable_context_menu_items (NemoView *view) { GtkUIManager *ui_manager; GtkWidget *item; GtkAction *action; gint i; ui_manager = nemo_window_get_ui_manager (view->details->window); for (i = 0; i < CONFIGURABLE_MENU_ITEM_COUNT; i++) { if (!CONFIGURABLE_MENU_ITEM_INFO[i].action_name) { continue; } item = gtk_ui_manager_get_widget (ui_manager, CONFIGURABLE_MENU_ITEM_INFO[i].ui_path); action = gtk_ui_manager_get_action (ui_manager, CONFIGURABLE_MENU_ITEM_INFO[i].ui_path); if (!item || !action) { DEBUG ("Configurable menu item widget or action not found (name: %s, path: %s)", CONFIGURABLE_MENU_ITEM_INFO[i].action_name, CONFIGURABLE_MENU_ITEM_INFO[i].ui_path); continue; } gboolean pref_visible = g_settings_get_boolean (nemo_menu_config_preferences, CONFIGURABLE_MENU_ITEM_INFO[i].settings_key); gtk_widget_set_visible (item, gtk_action_get_visible (action) && pref_visible); } } static void real_update_menus (NemoView *view) { GList *selection, *l; gint selection_count; const char *tip, *label; char *label_with_underscore; gboolean selection_contains_special_link; gboolean selection_contains_desktop_or_home_dir; gboolean selection_contains_recent; gboolean selection_contains_directory; gboolean can_create_files; gboolean can_delete_files; gboolean can_copy_files; gboolean can_link_files; gboolean can_duplicate_files; gboolean show_separate_delete_command; gboolean show_open_alternate; gboolean show_open_in_new_tab; gboolean can_open; gboolean show_app; gboolean showing_search; gboolean show_save_search; gboolean save_search_sensitive; gboolean show_save_search_as; gboolean show_desktop_target; gboolean is_desktop_view; GtkAction *action; GAppInfo *app; GIcon *app_icon; gboolean next_pane_is_writable; gboolean show_properties; gboolean first_selected_is_pinned; selection = nemo_file_list_ref (nemo_view_peek_selection (view)); selection_count = nemo_view_get_selection_count (view); selection_contains_special_link = special_link_in_selection (view, selection); selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (view, selection); selection_contains_recent = showing_recent_directory (view); selection_contains_directory = directory_in_selection (view, selection); can_create_files = nemo_view_supports_creating_files (view); can_delete_files = can_delete_all (selection) && selection_count != 0 && !selection_contains_special_link && !selection_contains_desktop_or_home_dir; can_copy_files = selection_count != 0 && !selection_contains_special_link; can_duplicate_files = can_create_files && can_copy_files; can_link_files = can_create_files && can_copy_files; is_desktop_view = get_is_desktop_view (view); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_RENAME); /* rename sensitivity depending on selection */ if (selection_count > 1) { /* If multiple files are selected, sensitivity depends on whether a bulk renamer is registered. */ gtk_action_set_sensitive (action, have_bulk_rename_tool ()); } else { gtk_action_set_sensitive (action, selection_count == 1 && nemo_view_can_rename_file (view, selection->data)); } gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_special_link); gboolean no_selection_or_one_dir = ((selection_count == 1 && selection_contains_directory) || selection_count == 0); gboolean show_open_as_root = (geteuid() != 0) && no_selection_or_one_dir; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN_AS_ROOT); gtk_action_set_visible (action, show_open_as_root); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN_IN_TERMINAL); gtk_action_set_visible (action, no_selection_or_one_dir); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_NEW_FOLDER); gtk_action_set_sensitive (action, can_create_files); gtk_action_set_visible (action, !selection_contains_recent); can_open = show_app = selection_count != 0; for (l = selection; l != NULL; l = l->next) { NemoFile *file; file = NEMO_FILE (selection->data); if (!nemo_mime_file_opens_in_external_app (file)) { show_app = FALSE; } if (!show_app) { break; } } label_with_underscore = NULL; app = NULL; app_icon = NULL; if (can_open && show_app) { app = nemo_mime_get_default_application_for_files (selection); } if (app != NULL) { char *escaped_app; escaped_app = eel_str_double_underscores (g_app_info_get_name (app)); label_with_underscore = g_strdup_printf (_("_Open With %s"), escaped_app); app_icon = g_app_info_get_icon (app); if (app_icon != NULL) { g_object_ref (app_icon); } g_free (escaped_app); g_object_unref (app); } if (app_icon == NULL) { app_icon = g_themed_icon_new ("folder-open-symbolic"); } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN); gtk_action_set_sensitive (action, selection_count != 0); g_object_set (action, "label", label_with_underscore ? label_with_underscore : _("_Open"), NULL); gtk_action_set_gicon (action, app_icon); gtk_action_set_visible (action, can_open); g_object_unref (app_icon); g_free (label_with_underscore); menu_item_show_image (nemo_window_get_ui_manager (view->details->window), NEMO_VIEW_MENU_PATH_OPEN_PLACEHOLDER, NEMO_ACTION_OPEN, FALSE); show_open_alternate = file_list_all_are_folders (selection) && selection_count > 0 && g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER) && !is_desktop_view; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN_ALTERNATE); gtk_action_set_sensitive (action, selection_count != 0); gtk_action_set_visible (action, show_open_alternate); if (selection_count == 0 || selection_count == 1) { label_with_underscore = g_strdup (_("Open in New _Window")); } else { label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Window", "Open in %'d New _Windows", selection_count), selection_count); } g_object_set (action, "label", label_with_underscore, NULL); g_free (label_with_underscore); show_open_in_new_tab = show_open_alternate; action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN_IN_NEW_TAB); gtk_action_set_sensitive (action, selection_count != 0); gtk_action_set_visible (action, show_open_in_new_tab); if (selection_count == 0 || selection_count == 1) { label_with_underscore = g_strdup (_("Open in New _Tab")); } else { label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Tab", "Open in %'d New _Tabs", selection_count), selection_count); } g_object_set (action, "label", label_with_underscore, NULL); g_free (label_with_underscore); /* Broken into its own function just for convenience */ reset_open_with_menu (view, selection); reset_extension_actions_menu (view, selection); reset_move_copy_to_menu (view); if (all_selected_items_in_trash (view, selection)) { label = _("_Delete Permanently"); tip = _("Delete all selected items permanently"); show_separate_delete_command = FALSE; } else { label = _("Mo_ve to Trash"); tip = _("Move each selected item to the Trash"); show_separate_delete_command = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE); } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_TRASH); g_object_set (action, "label", label, "tooltip", tip, "icon-name", all_selected_items_in_trash (view, selection) ? NEMO_ICON_DELETE : NEMO_ICON_SYMBOLIC_TRASH_FULL, NULL); gtk_action_set_sensitive (action, can_delete_files); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_DELETE); gtk_action_set_visible (action, show_separate_delete_command); if (selection_contains_recent) { label = _("Remo_ve from Recent"); tip = _("Remove each selected item from the recently used list"); } else { label = _("_Delete"); tip = _("Delete each selected item, without moving to the Trash"); } if (show_separate_delete_command) { g_object_set (action, "label", label, "tooltip", tip, "icon-name", NEMO_ICON_DELETE, NULL); } gtk_action_set_sensitive (action, can_delete_files); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_RESTORE_FROM_TRASH); update_restore_from_trash_action (action, selection, FALSE); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_DUPLICATE); gtk_action_set_sensitive (action, can_duplicate_files); gtk_action_set_visible (action, !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_CREATE_LINK); gtk_action_set_sensitive (action, can_link_files); gtk_action_set_visible (action, !selection_contains_recent); g_object_set (action, "label", ngettext ("Ma_ke Link", "Ma_ke Links", selection_count), NULL); show_properties = (!is_desktop_view || selection_count > 0); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PROPERTIES); gtk_action_set_sensitive (action, show_properties); if (selection_count == 0) { gtk_action_set_tooltip (action, _("View or modify the properties of the open folder")); } else { gtk_action_set_tooltip (action, _("View or modify the properties of each selected item")); } gtk_action_set_visible (action, show_properties); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PROPERTIES_ACCEL); gtk_action_set_sensitive (action, show_properties); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_EMPTY_TRASH); g_object_set (action, "label", _("E_mpty Trash"), NULL); gtk_action_set_sensitive (action, !nemo_trash_monitor_is_empty ()); gtk_action_set_visible (action, should_show_empty_trash (view)); showing_search = view->details->model && NEMO_IS_SEARCH_DIRECTORY (view->details->model); show_save_search = FALSE; save_search_sensitive = FALSE; show_save_search_as = FALSE; if (showing_search) { NemoSearchDirectory *search; search = NEMO_SEARCH_DIRECTORY (view->details->model); if (nemo_search_directory_is_saved_search (search)) { show_save_search = TRUE; save_search_sensitive = nemo_search_directory_is_modified (search); } else { show_save_search_as = TRUE; } } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SAVE_SEARCH); gtk_action_set_visible (action, show_save_search); gtk_action_set_sensitive (action, save_search_sensitive); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SAVE_SEARCH_AS); gtk_action_set_visible (action, show_save_search_as); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELECT_ALL); gtk_action_set_sensitive (action, !nemo_view_is_empty (view)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SELECT_PATTERN); gtk_action_set_sensitive (action, !nemo_view_is_empty (view)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_INVERT_SELECTION); gtk_action_set_sensitive (action, !nemo_view_is_empty (view)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_CUT); gtk_action_set_sensitive (action, can_delete_files); gtk_action_set_visible (action, !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY); gtk_action_set_sensitive (action, can_copy_files); real_update_paste_menu (view, selection, selection_count); real_update_menus_volumes (view, selection, selection_count); update_undo_actions (view); if (view->details->scripts_invalid) { update_scripts_menu (view); } action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_NEW_DOCUMENTS); gtk_action_set_sensitive (action, can_create_files); gtk_action_set_visible (action, !selection_contains_recent); if (can_create_files && view->details->templates_invalid) { update_templates_menu (view); } if (view->details->actions_invalid) { update_actions_menu (view); } update_actions_visibility (view, selection); next_pane_is_writable = has_writable_extra_pane (view); /* next pane: works if file is copyable, and next pane is writable */ action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_NEXT_PANE); gtk_action_set_visible (action, can_copy_files && next_pane_is_writable); /* move to next pane: works if file is cuttable, and next pane is writable */ action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_NEXT_PANE); gtk_action_set_visible (action, can_delete_files && next_pane_is_writable && !selection_contains_recent); show_desktop_target = g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_SHOW_DESKTOP) && !g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_HOME); gtk_action_set_sensitive (action, can_copy_files); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_DESKTOP); gtk_action_set_sensitive (action, can_copy_files); gtk_action_set_visible (action, show_desktop_target); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_HOME); gtk_action_set_sensitive (action, can_delete_files); gtk_action_set_visible (action, !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_DESKTOP); gtk_action_set_sensitive (action, can_delete_files); gtk_action_set_visible (action, show_desktop_target && !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, "CopyToMenu"); gtk_action_set_sensitive (action, can_copy_files); action = gtk_action_group_get_action (view->details->dir_action_group, "MoveToMenu"); gtk_action_set_sensitive (action, can_delete_files); gtk_action_set_visible (action, !selection_contains_recent); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_FOLLOW_SYMLINK); gtk_action_set_visible (action, selection_count == 1 && nemo_file_is_symbolic_link (selection->data)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_OPEN_CONTAINING_FOLDER); gtk_action_set_visible (action, selection_count == 1 && (selection_contains_recent || showing_search)); first_selected_is_pinned = selection_count > 0 && nemo_file_get_pinning (NEMO_FILE (selection->data)); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_PIN_FILE); gtk_action_set_visible (action, !is_desktop_view && !first_selected_is_pinned); action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_UNPIN_FILE); gtk_action_set_visible (action, !is_desktop_view && first_selected_is_pinned); update_configurable_context_menu_items (view); nemo_file_list_unref (selection); } /** * nemo_view_pop_up_selection_context_menu * * Pop up a context menu appropriate to the selected items. * @view: NemoView of interest. * @event: The event that triggered this context menu. * * Return value: NemoDirectory for this view. * **/ void nemo_view_pop_up_selection_context_menu (NemoView *view, GdkEventButton *event) { g_assert (NEMO_IS_VIEW (view)); /* Make the context menu items not flash as they update to proper disabled, * etc. states by forcing menus to update now. */ update_menus_if_pending (view); update_context_menu_position_from_event (view, event); eel_pop_up_context_menu (create_popup_menu (view, NEMO_VIEW_POPUP_PATH_SELECTION), event); } /** * nemo_view_pop_up_background_context_menu * * Pop up a context menu appropriate to the view globally at the last right click location. * @view: NemoView of interest. * * Return value: NemoDirectory for this view. * **/ void nemo_view_pop_up_background_context_menu (NemoView *view, GdkEventButton *event) { g_assert (NEMO_IS_VIEW (view)); /* Make the context menu items not flash as they update to proper disabled, * etc. states by forcing menus to update now. */ update_menus_if_pending (view); update_context_menu_position_from_event (view, event); eel_pop_up_context_menu (create_popup_menu (view, NEMO_VIEW_POPUP_PATH_BACKGROUND), event); } static void real_pop_up_location_context_menu (NemoView *view) { /* always update the menu before showing it. Shouldn't be too expensive. */ real_update_location_menu (view); update_context_menu_position_from_event (view, view->details->location_popup_event); eel_pop_up_context_menu (create_popup_menu (view, NEMO_VIEW_POPUP_PATH_LOCATION), view->details->location_popup_event); } static void location_popup_file_attributes_ready (NemoFile *file, gpointer data) { NemoView *view; view = NEMO_VIEW (data); g_assert (NEMO_IS_VIEW (view)); g_assert (file == view->details->location_popup_directory_as_file); real_pop_up_location_context_menu (view); } static void unschedule_pop_up_location_context_menu (NemoView *view) { if (view->details->location_popup_directory_as_file != NULL) { g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file)); nemo_file_cancel_call_when_ready (view->details->location_popup_directory_as_file, location_popup_file_attributes_ready, view); nemo_file_unref (view->details->location_popup_directory_as_file); view->details->location_popup_directory_as_file = NULL; } } static void schedule_pop_up_location_context_menu (NemoView *view, GdkEventButton *event, NemoFile *file) { g_assert (NEMO_IS_FILE (file)); if (view->details->location_popup_event != NULL) { gdk_event_free ((GdkEvent *) view->details->location_popup_event); } view->details->location_popup_event = (GdkEventButton *) gdk_event_copy ((GdkEvent *)event); if (file == view->details->location_popup_directory_as_file) { if (nemo_file_check_if_ready (file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO)) { real_pop_up_location_context_menu (view); } } else { unschedule_pop_up_location_context_menu (view); view->details->location_popup_directory_as_file = nemo_file_ref (file); nemo_file_call_when_ready (view->details->location_popup_directory_as_file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO, location_popup_file_attributes_ready, view); } } /** * nemo_view_pop_up_location_context_menu * * Pop up a context menu appropriate to the view globally. * @view: NemoView of interest. * @event: GdkEventButton triggering the popup. * @location: The location the popup-menu should be created for, * or NULL for the currently displayed location. * **/ void nemo_view_pop_up_location_context_menu (NemoView *view, GdkEventButton *event, const char *location) { NemoFile *file; g_assert (NEMO_IS_VIEW (view)); if (location != NULL) { file = nemo_file_get_by_uri (location); } else { file = nemo_file_ref (view->details->directory_as_file); } if (file != NULL) { schedule_pop_up_location_context_menu (view, event, file); nemo_file_unref (file); } } static void schedule_update_menus (NemoView *view) { g_assert (NEMO_IS_VIEW (view)); /* Don't schedule updates after destroy (#349551), * or if we are not active. */ if (view->details->window == NULL || !view->details->active) { return; } view->details->menu_states_untrustworthy = TRUE; /* Schedule a menu update with the current update interval */ if (view->details->update_menus_timeout_id != 0) { g_source_remove (view->details->update_menus_timeout_id); view->details->update_menus_timeout_id = 0; } view->details->update_menus_timeout_id = g_timeout_add (view->details->update_interval, update_menus_timeout_callback, view); } static void remove_update_status_idle_callback (NemoView *view) { if (view->details->update_status_idle_id != 0) { g_source_remove (view->details->update_status_idle_id); view->details->update_status_idle_id = 0; } } static gboolean update_status_idle_callback (gpointer data) { NemoView *view; view = NEMO_VIEW (data); nemo_view_display_selection_info (view); view->details->update_status_idle_id = 0; return FALSE; } static void schedule_update_status (NemoView *view) { g_assert (NEMO_IS_VIEW (view)); /* Make sure we haven't already destroyed it */ if (view->details->window == NULL) { return; } if (view->details->loading) { /* Don't update status bar while loading the dir */ return; } if (view->details->update_status_idle_id == 0) { view->details->update_status_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, update_status_idle_callback, view, NULL); } } /** * nemo_view_notify_selection_changed: * * Notify this view that the selection has changed. This is normally * called only by subclasses. * @view: NemoView whose selection has changed. * **/ void nemo_view_notify_selection_changed (NemoView *view) { GtkWindow *window; GList *selection; g_return_if_fail (NEMO_IS_VIEW (view)); selection = nemo_view_peek_selection (view); window = nemo_view_get_containing_window (view); DEBUG_FILES (selection, "Selection changed in window %p", window); view->details->selection_was_removed = FALSE; if (!view->details->selection_change_is_due_to_shell) { view->details->send_selection_change_to_shell = TRUE; } /* Schedule a display of the new selection. */ if (view->details->display_selection_idle_id != 0) { g_source_remove (view->details->display_selection_idle_id); view->details->display_selection_idle_id = 0; nemo_window_slot_set_status (view->details->slot, "", ""); } view->details->display_selection_idle_id = g_timeout_add (100, display_selection_info_idle_callback, view); if (view->details->batching_selection_level != 0) { view->details->selection_changed_while_batched = TRUE; } else { /* Here is the work we do only when we're not * batching selection changes. In other words, it's the slower * stuff that we don't want to slow down selection techniques * such as rubberband-selecting in icon view. */ /* Schedule an update of menu item states to match selection */ schedule_update_menus (view); } } static void file_changed_callback (NemoFile *file, gpointer callback_data) { NemoView *view = NEMO_VIEW (callback_data); schedule_changes (view); schedule_update_menus (view); schedule_update_status (view); } /** * load_directory: * * Switch the displayed location to a new uri. If the uri is not valid, * the location will not be switched; user feedback will be provided instead. * @view: NemoView whose location will be changed. * @uri: A string representing the uri to switch to. * **/ static void load_directory (NemoView *view, NemoDirectory *directory) { NemoDirectory *old_directory; NemoFile *old_file; NemoFileAttributes attributes; g_assert (NEMO_IS_VIEW (view)); g_assert (NEMO_IS_DIRECTORY (directory)); nemo_view_stop_loading (view); g_signal_emit (view, signals[CLEAR], 0); view->details->loading = TRUE; /* Update menus when directory is empty, before going to new * location, so they won't have any false lingering knowledge * of old selection. */ schedule_update_menus (view); while (view->details->subdirectory_list != NULL) { nemo_view_remove_subdirectory (view, view->details->subdirectory_list->data); } disconnect_model_handlers (view); old_directory = view->details->model; nemo_directory_ref (directory); view->details->model = directory; nemo_directory_unref (old_directory); old_file = view->details->directory_as_file; view->details->directory_as_file = nemo_directory_get_corresponding_file (directory); nemo_file_unref (old_file); view->details->reported_load_error = FALSE; /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as * well as doing a call when ready), in case external forces * change the directory's file metadata. */ attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO; view->details->metadata_for_directory_as_file_pending = TRUE; view->details->metadata_for_files_in_directory_pending = TRUE; nemo_file_call_when_ready (view->details->directory_as_file, attributes, metadata_for_directory_as_file_ready_callback, view); nemo_directory_call_when_ready (view->details->model, attributes, FALSE, metadata_for_files_in_directory_ready_callback, view); /* If capabilities change, then we need to update the menus * because of New Folder, and relative emblems. */ attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO; nemo_file_monitor_add (view->details->directory_as_file, &view->details->directory_as_file, attributes); view->details->file_changed_handler_id = g_signal_connect (view->details->directory_as_file, "changed", G_CALLBACK (file_changed_callback), view); } static void finish_loading (NemoView *view) { NemoFileAttributes attributes; nemo_window_report_load_underway (view->details->window, NEMO_VIEW (view)); g_timer_start (view->details->load_timer); /* Tell interested parties that we've begun loading this directory now. * Subclasses use this to know that the new metadata is now available. */ g_signal_emit (view, signals[BEGIN_LOADING], 0); /* Assume we have now all information to show window */ nemo_window_view_visible (view->details->window, NEMO_VIEW (view)); if (nemo_directory_are_all_files_seen (view->details->model)) { /* Unschedule a pending update and schedule a new one with the minimal * update interval. This gives the view a short chance at gathering the * (cached) deep counts. */ unschedule_display_of_pending_files (view); schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); } /* Start loading. */ /* Connect handlers to learn about loading progress. */ view->details->done_loading_handler_id = g_signal_connect (view->details->model, "done_loading", G_CALLBACK (done_loading_callback), view); view->details->load_error_handler_id = g_signal_connect (view->details->model, "load_error", G_CALLBACK (load_error_callback), view); /* Monitor the things needed to get the right icon. Also * monitor a directory's item count because the "size" * attribute is based on that, and the file's metadata * and possible custom name. */ attributes = NEMO_FILE_ATTRIBUTES_FOR_ICON | NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO | NEMO_FILE_ATTRIBUTE_MOUNT | NEMO_FILE_ATTRIBUTE_EXTENSION_INFO | NEMO_FILE_ATTRIBUTE_BTIME; nemo_directory_file_monitor_add (view->details->model, &view->details->model, view->details->show_hidden_files, attributes, files_added_callback, view); view->details->files_added_handler_id = g_signal_connect (view->details->model, "files_added", G_CALLBACK (files_added_callback), view); view->details->files_changed_handler_id = g_signal_connect (view->details->model, "files_changed", G_CALLBACK (files_changed_callback), view); } static void finish_loading_if_all_metadata_loaded (NemoView *view) { if (!view->details->metadata_for_directory_as_file_pending && !view->details->metadata_for_files_in_directory_pending) { finish_loading (view); } } static void metadata_for_directory_as_file_ready_callback (NemoFile *file, gpointer callback_data) { NemoView *view; view = callback_data; g_assert (NEMO_IS_VIEW (view)); g_assert (view->details->directory_as_file == file); g_assert (view->details->metadata_for_directory_as_file_pending); view->details->metadata_for_directory_as_file_pending = FALSE; finish_loading_if_all_metadata_loaded (view); } static void metadata_for_files_in_directory_ready_callback (NemoDirectory *directory, GList *files, gpointer callback_data) { NemoView *view; view = callback_data; g_assert (NEMO_IS_VIEW (view)); g_assert (view->details->model == directory); g_assert (view->details->metadata_for_files_in_directory_pending); view->details->metadata_for_files_in_directory_pending = FALSE; finish_loading_if_all_metadata_loaded (view); } static void disconnect_handler (GObject *object, guint *id) { if (*id != 0) { g_signal_handler_disconnect (object, *id); *id = 0; } } static void disconnect_directory_handler (NemoView *view, guint *id) { disconnect_handler (G_OBJECT (view->details->model), id); } static void disconnect_directory_as_file_handler (NemoView *view, guint *id) { disconnect_handler (G_OBJECT (view->details->directory_as_file), id); } static void disconnect_model_handlers (NemoView *view) { if (view->details->model == NULL) { return; } disconnect_directory_handler (view, &view->details->files_added_handler_id); disconnect_directory_handler (view, &view->details->files_changed_handler_id); disconnect_directory_handler (view, &view->details->done_loading_handler_id); disconnect_directory_handler (view, &view->details->load_error_handler_id); disconnect_directory_as_file_handler (view, &view->details->file_changed_handler_id); nemo_file_cancel_call_when_ready (view->details->directory_as_file, metadata_for_directory_as_file_ready_callback, view); nemo_directory_cancel_callback (view->details->model, metadata_for_files_in_directory_ready_callback, view); nemo_directory_file_monitor_remove (view->details->model, &view->details->model); nemo_file_monitor_remove (view->details->directory_as_file, &view->details->directory_as_file); } static void nemo_view_select_file (NemoView *view, NemoFile *file) { GList file_list; file_list.data = file; file_list.next = NULL; file_list.prev = NULL; nemo_view_call_set_selection (view, &file_list); } /** * nemo_view_stop_loading: * * Stop the current ongoing process, such as switching to a new uri. * @view: NemoView in question. * **/ void nemo_view_stop_loading (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); unschedule_display_of_pending_files (view); reset_update_interval (view); /* Free extra undisplayed files */ file_and_directory_list_free (view->details->new_added_files); view->details->new_added_files = NULL; file_and_directory_list_free (view->details->new_changed_files); view->details->new_changed_files = NULL; g_hash_table_remove_all (view->details->non_ready_files); file_and_directory_list_free (view->details->old_added_files); view->details->old_added_files = NULL; file_and_directory_list_free (view->details->old_changed_files); view->details->old_changed_files = NULL; g_list_free_full (view->details->pending_selection, g_object_unref); view->details->pending_selection = NULL; if (view->details->model != NULL) { nemo_directory_file_monitor_remove (view->details->model, view); } done_loading (view, FALSE); } gboolean nemo_view_is_editable (NemoView *view) { NemoDirectory *directory; directory = nemo_view_get_model (view); if (directory != NULL) { return nemo_directory_is_editable (directory); } return TRUE; } static gboolean real_is_read_only (NemoView *view) { NemoFile *file; if (showing_recent_directory (view)) { return TRUE; } if (!nemo_view_is_editable (view)) { return TRUE; } file = nemo_view_get_directory_as_file (view); if (file != NULL) { if (nemo_file_is_in_admin (file)) { return TRUE; } return !nemo_file_can_write (file); } return FALSE; } /** * nemo_view_should_show_file * * Returns whether or not this file should be displayed based on * current filtering options. */ gboolean nemo_view_should_show_file (NemoView *view, NemoFile *file) { return nemo_file_should_show (file, view->details->show_hidden_files, view->details->show_foreign_files); } static gboolean real_using_manual_layout (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE); return FALSE; } static void schedule_update_menus_callback (gpointer callback_data) { schedule_update_menus (NEMO_VIEW (callback_data)); } void nemo_view_ignore_hidden_file_preferences (NemoView *view) { g_return_if_fail (view->details->model == NULL); if (view->details->ignore_hidden_file_preferences) { return; } view->details->show_hidden_files = FALSE; view->details->ignore_hidden_file_preferences = TRUE; } void nemo_view_set_show_foreign (NemoView *view, gboolean show_foreign) { view->details->show_foreign_files = show_foreign; } char * nemo_view_get_uri (NemoView *view) { g_return_val_if_fail (NEMO_IS_VIEW (view), NULL); if (view->details->model == NULL) { return NULL; } return nemo_directory_get_uri (view->details->model); } void nemo_view_move_copy_items (NemoView *view, const GList *item_uris, GArray *relative_item_points, const char *target_uri, int copy_action, int x, int y) { NemoFile *target_file; g_assert (relative_item_points == NULL || relative_item_points->len == 0 || g_list_length ((GList *)item_uris) == relative_item_points->len); /* add the drop location to the icon offsets */ offset_drop_points (relative_item_points, x, y); target_file = nemo_file_get_existing_by_uri (target_uri); /* special-case "command:" here instead of starting a move/copy */ if (target_file != NULL && nemo_file_is_launcher (target_file)) { nemo_file_unref (target_file); nemo_launch_desktop_file ( gtk_widget_get_screen (GTK_WIDGET (view)), target_uri, item_uris, nemo_view_get_containing_window (view)); return; } else if (copy_action == GDK_ACTION_COPY && nemo_is_file_roller_installed () && target_file != NULL && nemo_file_is_archive (target_file)) { char *command, *quoted_uri, *unescaped, *tmp; const GList *l; GdkScreen *screen; /* Handle dropping onto a file-roller archiver file, instead of starting a move/copy */ nemo_file_unref (target_file); unescaped = g_uri_unescape_string (target_uri, ""); quoted_uri = g_shell_quote (unescaped); command = g_strconcat ("file-roller -a ", quoted_uri, NULL); g_clear_pointer ("ed_uri, g_free); g_clear_pointer (&unescaped, g_free); for (l = item_uris; l != NULL; l = l->next) { unescaped = g_uri_unescape_string ((char *) l->data, ""); quoted_uri = g_shell_quote (unescaped); tmp = g_strconcat (command, " ", quoted_uri, NULL); g_free (command); command = tmp; g_clear_pointer ("ed_uri, g_free); g_clear_pointer (&unescaped, g_free); } screen = gtk_widget_get_screen (GTK_WIDGET (view)); if (screen == NULL) { screen = gdk_screen_get_default (); } nemo_launch_application_from_command (screen, command, FALSE, NULL); g_free (command); return; } nemo_file_unref (target_file); nemo_file_operations_copy_move (item_uris, relative_item_points, target_uri, copy_action, GTK_WIDGET (view), copy_move_done_callback, pre_copy_move (view)); } static void nemo_view_trash_state_changed_callback (NemoTrashMonitor *trash_monitor, gboolean state, gpointer callback_data) { NemoView *view; view = (NemoView *) callback_data; g_assert (NEMO_IS_VIEW (view)); schedule_update_menus (view); } void nemo_view_start_batching_selection_changes (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); ++view->details->batching_selection_level; view->details->selection_changed_while_batched = FALSE; } void nemo_view_stop_batching_selection_changes (NemoView *view) { g_return_if_fail (NEMO_IS_VIEW (view)); g_return_if_fail (view->details->batching_selection_level > 0); if (--view->details->batching_selection_level == 0) { if (view->details->selection_changed_while_batched) { nemo_view_notify_selection_changed (view); } } } gboolean nemo_view_get_active (NemoView *view) { g_assert (NEMO_IS_VIEW (view)); return view->details->active; } static GArray * real_get_selected_icon_locations (NemoView *view) { /* By default, just return an empty list. */ return g_array_new (FALSE, TRUE, sizeof (GdkPoint)); } static void nemo_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoView *directory_view; NemoWindowSlot *slot; NemoWindow *window; directory_view = NEMO_VIEW (object); switch (prop_id) { case PROP_WINDOW_SLOT: g_assert (directory_view->details->slot == NULL); slot = NEMO_WINDOW_SLOT (g_value_get_object (value)); window = nemo_window_slot_get_window (slot); directory_view->details->slot = slot; directory_view->details->window = window; g_signal_connect_object (directory_view->details->slot, "active", G_CALLBACK (slot_active), directory_view, 0); g_signal_connect_object (directory_view->details->slot, "inactive", G_CALLBACK (slot_inactive), directory_view, 0); g_signal_connect_object (directory_view->details->slot, "changed-pane", G_CALLBACK (slot_changed_pane), directory_view, 0); g_signal_connect_object (directory_view->details->window, "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed), directory_view, 0); nemo_view_init_show_hidden_files (directory_view); break; case PROP_SUPPORTS_ZOOMING: directory_view->details->supports_zooming = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } gboolean nemo_view_handle_scroll_event (NemoView *directory_view, GdkEventScroll *event) { static gdouble total_delta_y = 0; gdouble delta_x, delta_y; if (event->state & GDK_CONTROL_MASK) { switch (event->direction) { case GDK_SCROLL_UP: /* Zoom In */ nemo_view_bump_zoom_level (directory_view, 1); return TRUE; case GDK_SCROLL_DOWN: /* Zoom Out */ nemo_view_bump_zoom_level (directory_view, -1); return TRUE; case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas ((const GdkEvent *) event, &delta_x, &delta_y); /* try to emulate a normal scrolling event by summing deltas */ total_delta_y += delta_y; if (total_delta_y >= 1) { total_delta_y = 0; /* emulate scroll down */ nemo_view_bump_zoom_level (directory_view, -1); return TRUE; } else if (total_delta_y <= - 1) { total_delta_y = 0; /* emulate scroll up */ nemo_view_bump_zoom_level (directory_view, 1); return TRUE; } else { /* eat event */ return TRUE; } case GDK_SCROLL_LEFT: case GDK_SCROLL_RIGHT: break; default: g_assert_not_reached (); } } return FALSE; } /* handle Shift+Scroll, which will cause a zoom-in/out */ static gboolean nemo_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) { NemoView *directory_view; directory_view = NEMO_VIEW (widget); if (!get_is_desktop_view (directory_view) && nemo_view_handle_scroll_event (directory_view, event)) { return TRUE; } return GTK_WIDGET_CLASS (parent_class)->scroll_event (widget, event); } static void nemo_view_parent_set (GtkWidget *widget, GtkWidget *old_parent) { NemoView *view; GtkWidget *parent; view = NEMO_VIEW (widget); parent = gtk_widget_get_parent (widget); g_assert (parent == NULL || old_parent == NULL); if (GTK_WIDGET_CLASS (parent_class)->parent_set != NULL) { GTK_WIDGET_CLASS (parent_class)->parent_set (widget, old_parent); } if (parent != NULL) { g_assert (old_parent == NULL); if (view->details->slot == nemo_window_get_active_slot (view->details->window)) { view->details->active = TRUE; nemo_view_merge_menus (view); schedule_update_menus (view); } } else { nemo_view_unmerge_menus (view); remove_update_menus_timeout_callback (view); } } static void nemo_view_class_init (NemoViewClass *klass) { GObjectClass *oclass; GtkWidgetClass *widget_class; GtkScrolledWindowClass *scrolled_window_class; GtkBindingSet *binding_set; widget_class = GTK_WIDGET_CLASS (klass); scrolled_window_class = GTK_SCROLLED_WINDOW_CLASS (klass); oclass = G_OBJECT_CLASS (klass); oclass->finalize = nemo_view_finalize; oclass->set_property = nemo_view_set_property; widget_class->destroy = nemo_view_destroy; widget_class->scroll_event = nemo_view_scroll_event; widget_class->parent_set = nemo_view_parent_set; g_type_class_add_private (klass, sizeof (NemoViewDetails)); /* Get rid of the strange 3-pixel gap that GtkScrolledWindow * uses by default. It does us no good. */ scrolled_window_class->scrollbar_spacing = 0; signals[ADD_FILE] = g_signal_new ("add_file", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, add_file), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY); signals[BEGIN_FILE_CHANGES] = g_signal_new ("begin_file_changes", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, begin_file_changes), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[BEGIN_LOADING] = g_signal_new ("begin_loading", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, begin_loading), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[CLEAR] = g_signal_new ("clear", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, clear), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[END_FILE_CHANGES] = g_signal_new ("end_file_changes", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, end_file_changes), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[END_LOADING] = g_signal_new ("end_loading", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, end_loading), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); signals[FILE_CHANGED] = g_signal_new ("file_changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, file_changed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY); signals[LOAD_ERROR] = g_signal_new ("load_error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, load_error), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[REMOVE_FILE] = g_signal_new ("remove_file", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoViewClass, remove_file), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY); signals[ZOOM_LEVEL_CHANGED] = g_signal_new ("zoom-level-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[SELECTION_CHANGED] = g_signal_new ("selection-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[TRASH] = g_signal_new ("trash", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoViewClass, trash), g_signal_accumulator_true_handled, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 0); signals[DELETE] = g_signal_new ("delete", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoViewClass, delete), g_signal_accumulator_true_handled, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 0); klass->get_selected_icon_locations = real_get_selected_icon_locations; klass->is_read_only = real_is_read_only; klass->load_error = real_load_error; klass->can_rename_file = can_rename_file; klass->start_renaming_file = start_renaming_file; klass->get_backing_uri = real_get_backing_uri; klass->using_manual_layout = real_using_manual_layout; klass->merge_menus = real_merge_menus; klass->unmerge_menus = real_unmerge_menus; klass->update_menus = real_update_menus; klass->trash = real_trash; klass->delete = real_delete; copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); properties[PROP_WINDOW_SLOT] = g_param_spec_object ("window-slot", "Window Slot", "The parent window slot reference", NEMO_TYPE_WINDOW_SLOT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_SUPPORTS_ZOOMING] = g_param_spec_boolean ("supports-zooming", "Supports zooming", "Whether the view supports zooming", TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); binding_set = gtk_binding_set_by_class (klass); gboolean swap_keys = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SWAP_TRASH_DELETE); if (swap_keys) { gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "trash", 0); } else { gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "trash", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, "delete", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "delete", 0); } } nemo-4.4.2/src/nemo-view.h000066400000000000000000000451351357442400300153370ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* nemo-view.h * * Copyright (C) 1999, 2000 Free Software Foundaton * Copyright (C) 2000, 2001 Eazel, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Ettore Perazzoli * Darin Adler * John Sullivan * Pavel Cisler */ #ifndef NEMO_VIEW_H #define NEMO_VIEW_H #include #include #include #include #include #include typedef struct NemoView NemoView; typedef struct NemoViewClass NemoViewClass; #include "nemo-window.h" #include "nemo-window-slot.h" #define NEMO_TYPE_VIEW nemo_view_get_type() #define NEMO_VIEW(obj)\ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_VIEW, NemoView)) #define NEMO_VIEW_CLASS(klass)\ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_VIEW, NemoViewClass)) #define NEMO_IS_VIEW(obj)\ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_VIEW)) #define NEMO_IS_VIEW_CLASS(klass)\ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_VIEW)) #define NEMO_VIEW_GET_CLASS(obj)\ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_VIEW, NemoViewClass)) typedef struct NemoViewDetails NemoViewDetails; struct NemoView { GtkScrolledWindow parent; NemoViewDetails *details; }; struct NemoViewClass { GtkScrolledWindowClass parent_class; /* The 'clear' signal is emitted to empty the view of its contents. * It must be replaced by each subclass. */ void (* clear) (NemoView *view); /* The 'begin_file_changes' signal is emitted before a set of files * are added to the view. It can be replaced by a subclass to do any * necessary preparation for a set of new files. The default * implementation does nothing. */ void (* begin_file_changes) (NemoView *view); /* The 'add_file' signal is emitted to add one file to the view. * It must be replaced by each subclass. */ void (* add_file) (NemoView *view, NemoFile *file, NemoDirectory *directory); void (* remove_file) (NemoView *view, NemoFile *file, NemoDirectory *directory); /* The 'file_changed' signal is emitted to signal a change in a file, * including the file being removed. * It must be replaced by each subclass. */ void (* file_changed) (NemoView *view, NemoFile *file, NemoDirectory *directory); /* The 'end_file_changes' signal is emitted after a set of files * are added to the view. It can be replaced by a subclass to do any * necessary cleanup (typically, cleanup for code in begin_file_changes). * The default implementation does nothing. */ void (* end_file_changes) (NemoView *view); /* The 'begin_loading' signal is emitted before any of the contents * of a directory are added to the view. It can be replaced by a * subclass to do any necessary preparation to start dealing with a * new directory. The default implementation does nothing. */ void (* begin_loading) (NemoView *view); /* The 'end_loading' signal is emitted after all of the contents * of a directory are added to the view. It can be replaced by a * subclass to do any necessary clean-up. The default implementation * does nothing. * * If all_files_seen is true, the handler may assume that * no load error ocurred, and all files of the underlying * directory were loaded. * * Otherwise, end_loading was emitted due to cancellation, * which usually means that not all files are available. */ void (* end_loading) (NemoView *view, gboolean all_files_seen); /* The 'load_error' signal is emitted when the directory model * reports an error in the process of monitoring the directory's * contents. The load error indicates that the process of * loading the contents has ended, but the directory is still * being monitored. The default implementation handles common * load failures like ACCESS_DENIED. */ void (* load_error) (NemoView *view, GError *error); /* Function pointers that don't have corresponding signals */ /* reset_to_defaults is a function pointer that subclasses must * override to set sort order, zoom level, etc to match default * values. */ void (* reset_to_defaults) (NemoView *view); /* get_backing uri is a function pointer for subclasses to * override. Subclasses may replace it with a function that * returns the URI for the location where to create new folders, * files, links and paste the clipboard to. */ char * (* get_backing_uri) (NemoView *view); /* get_selection is not a signal; it is just a function pointer for * subclasses to replace (override). Subclasses must replace it * with a function that returns a newly-allocated GList of * NemoFile pointers. */ GList * (* get_selection) (NemoView *view); /* peek_selection is not a signal; it is just a function pointer for * subclasses to replace (override). Subclasses must replace it * with a function that returns a pointer to the existing container * selection list. */ GList * (* peek_selection) (NemoView *view); /* get_selection_count is not a signal; it is just a function pointer for * subclasses to replace (override). Subclasses must replace it * with a function that returns the current selection count. */ gint (* get_selection_count) (NemoView *view); /* get_selection_for_file_transfer is a function pointer for * subclasses to replace (override). Subclasses must replace it * with a function that returns a newly-allocated GList of * NemoFile pointers. The difference from get_selection is * that any files in the selection that also has a parent folder * in the selection is not included. */ GList * (* get_selection_for_file_transfer)(NemoView *view); /* select_all is a function pointer that subclasses must override to * select all of the items in the view */ void (* select_all) (NemoView *view); /* set_selection is a function pointer that subclasses must * override to select the specified items (and unselect all * others). The argument is a list of NemoFiles. */ void (* set_selection) (NemoView *view, GList *selection); /* invert_selection is a function pointer that subclasses must * override to invert selection. */ void (* invert_selection) (NemoView *view); /* Return an array of locations of selected icons in their view. */ GArray * (* get_selected_icon_locations) (NemoView *view); guint (* get_item_count) (NemoView *view); /* bump_zoom_level is a function pointer that subclasses must override * to change the zoom level of an object. */ void (* bump_zoom_level) (NemoView *view, int zoom_increment); /* zoom_to_level is a function pointer that subclasses must override * to set the zoom level of an object to the specified level. */ void (* zoom_to_level) (NemoView *view, NemoZoomLevel level); NemoZoomLevel (* get_zoom_level) (NemoView *view); /* restore_default_zoom_level is a function pointer that subclasses must override * to restore the zoom level of an object to a default setting. */ void (* restore_default_zoom_level) (NemoView *view); /* return the default zoom level for the current view */ NemoZoomLevel (* get_default_zoom_level) (NemoView *view); /* can_zoom_in is a function pointer that subclasses must override to * return whether the view is at maximum size (furthest-in zoom level) */ gboolean (* can_zoom_in) (NemoView *view); /* can_zoom_out is a function pointer that subclasses must override to * return whether the view is at minimum size (furthest-out zoom level) */ gboolean (* can_zoom_out) (NemoView *view); /* reveal_selection is a function pointer that subclasses may * override to make sure the selected items are sufficiently * apparent to the user (e.g., scrolled into view). By default, * this does nothing. */ void (* reveal_selection) (NemoView *view); /* merge_menus is a function pointer that subclasses can override to * add their own menu items to the window's menu bar. * If overridden, subclasses must call parent class's function. */ void (* merge_menus) (NemoView *view); void (* unmerge_menus) (NemoView *view); /* update_menus is a function pointer that subclasses can override to * update the sensitivity or wording of menu items in the menu bar. * It is called (at least) whenever the selection changes. If overridden, * subclasses must call parent class's function. */ void (* update_menus) (NemoView *view); /* sort_files is a function pointer that subclasses can override * to provide a sorting order to determine which files should be * presented when only a partial list is provided. */ int (* compare_files) (NemoView *view, NemoFile *a, NemoFile *b); /* using_manual_layout is a function pointer that subclasses may * override to control whether or not items can be freely positioned * on the user-visible area. * Note that this value is not guaranteed to be constant within the * view's lifecycle. */ gboolean (* using_manual_layout) (NemoView *view); /* is_read_only is a function pointer that subclasses may * override to control whether or not the user is allowed to * change the contents of the currently viewed directory. The * default implementation checks the permissions of the * directory. */ gboolean (* is_read_only) (NemoView *view); /* is_empty is a function pointer that subclasses must * override to report whether the view contains any items. */ gboolean (* is_empty) (NemoView *view); gboolean (* can_rename_file) (NemoView *view, NemoFile *file); /* select_all specifies whether the whole filename should be selected * or only its basename (i.e. everything except the extension) * */ void (* start_renaming_file) (NemoView *view, NemoFile *file, gboolean select_all); /* convert *point from widget's coordinate system to a coordinate * system used for specifying file operation positions, which is view-specific. * * This is used by the the icon view, which converts the screen position to a zoom * level-independent coordinate system. */ void (* widget_to_file_operation_position) (NemoView *view, GdkPoint *position); /* Preference change callbacks, overriden by icon and list views. * Icon and list views respond by synchronizing to the new preference * values and forcing an update if appropriate. */ void (* click_policy_changed) (NemoView *view); void (* click_to_rename_mode_changed) (NemoView *view); void (* sort_directories_first_changed) (NemoView *view); /* Get the id string for this view. Its a constant string, not memory managed */ const char * (* get_view_id) (NemoView *view); /* Return the uri of the first visible file */ char * (* get_first_visible_file) (NemoView *view); /* Scroll the view so that the file specified by the uri is at the top of the view */ void (* scroll_to_file) (NemoView *view, const char *uri); /* Signals used only for keybindings */ gboolean (* trash) (NemoView *view); gboolean (* delete) (NemoView *view); }; /* GObject support */ GType nemo_view_get_type (void); /* Functions callable from the user interface and elsewhere. */ NemoWindow *nemo_view_get_nemo_window (NemoView *view); NemoWindowSlot *nemo_view_get_nemo_window_slot (NemoView *view); char * nemo_view_get_uri (NemoView *view); void nemo_view_display_selection_info (NemoView *view); GdkAtom nemo_view_get_copied_files_atom (NemoView *view); gboolean nemo_view_get_active (NemoView *view); /* Wrappers for signal emitters. These are normally called * only by NemoView itself. They have corresponding signals * that observers might want to connect with. */ gboolean nemo_view_get_loading (NemoView *view); /* Hooks for subclasses to call. These are normally called only by * NemoView and its subclasses */ void nemo_view_activate_files (NemoView *view, GList *files, NemoWindowOpenFlags flags, gboolean confirm_multiple); void nemo_view_activate_file (NemoView *view, NemoFile *file, NemoWindowOpenFlags flags); void nemo_view_preview_files (NemoView *view, GList *files, GArray *locations); void nemo_view_start_batching_selection_changes (NemoView *view); void nemo_view_stop_batching_selection_changes (NemoView *view); void nemo_view_notify_selection_changed (NemoView *view); GtkUIManager * nemo_view_get_ui_manager (NemoView *view); NemoDirectory *nemo_view_get_model (NemoView *view); NemoFile *nemo_view_get_directory_as_file (NemoView *view); void nemo_view_pop_up_background_context_menu (NemoView *view, GdkEventButton *event); void nemo_view_pop_up_selection_context_menu (NemoView *view, GdkEventButton *event); gboolean nemo_view_should_show_file (NemoView *view, NemoFile *file); gboolean nemo_view_should_sort_directories_first (NemoView *view); void nemo_view_ignore_hidden_file_preferences (NemoView *view); void nemo_view_set_show_foreign (NemoView *view, gboolean show_foreign); gboolean nemo_view_handle_scroll_event (NemoView *view, GdkEventScroll *event); void nemo_view_freeze_updates (NemoView *view); void nemo_view_unfreeze_updates (NemoView *view); gboolean nemo_view_get_is_renaming (NemoView *view); void nemo_view_set_is_renaming (NemoView *view, gboolean renaming); void nemo_view_add_subdirectory (NemoView *view, NemoDirectory*directory); void nemo_view_remove_subdirectory (NemoView *view, NemoDirectory*directory); gboolean nemo_view_is_editable (NemoView *view); /* NemoView methods */ const char * nemo_view_get_view_id (NemoView *view); /* file operations */ char * nemo_view_get_backing_uri (NemoView *view); void nemo_view_move_copy_items (NemoView *view, const GList *item_uris, GArray *relative_item_points, const char *target_uri, int copy_action, int x, int y); void nemo_view_new_file_with_initial_contents (NemoView *view, const char *parent_uri, const char *filename, const char *initial_contents, int length, GdkPoint *pos); /* selection handling */ int nemo_view_get_selection_count (NemoView *view); GList * nemo_view_get_selection (NemoView *view); GList * nemo_view_peek_selection (NemoView *view); gint nemo_view_get_selection_count (NemoView *view); void nemo_view_set_selection (NemoView *view, GList *selection); void nemo_view_load_location (NemoView *view, GFile *location); void nemo_view_stop_loading (NemoView *view); char ** nemo_view_get_emblem_names_to_exclude (NemoView *view); char * nemo_view_get_first_visible_file (NemoView *view); void nemo_view_scroll_to_file (NemoView *view, const char *uri); char * nemo_view_get_title (NemoView *view); gboolean nemo_view_supports_zooming (NemoView *view); void nemo_view_bump_zoom_level (NemoView *view, int zoom_increment); void nemo_view_zoom_to_level (NemoView *view, NemoZoomLevel level); void nemo_view_restore_default_zoom_level (NemoView *view); gboolean nemo_view_can_zoom_in (NemoView *view); gboolean nemo_view_can_zoom_out (NemoView *view); NemoZoomLevel nemo_view_get_zoom_level (NemoView *view); void nemo_view_pop_up_location_context_menu (NemoView *view, GdkEventButton *event, const char *location); void nemo_view_grab_focus (NemoView *view); void nemo_view_update_menus (NemoView *view); void nemo_view_new_folder (NemoView *view); #endif /* NEMO_VIEW_H */ nemo-4.4.2/src/nemo-window-bookmarks.c000066400000000000000000000266071357442400300176600ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2005 Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: John Sullivan * Alexander Larsson */ #include #include #include "nemo-actions.h" #include "nemo-bookmark-list.h" #include "nemo-bookmarks-window.h" #include "nemo-window-bookmarks.h" #include "nemo-window-private.h" #include #include #include #include #include #include #include #define MENU_ITEM_MAX_WIDTH_CHARS 32 #define MENU_PATH_BOOKMARKS_PLACEHOLDER "/MenuBar/Other Menus/Bookmarks/Bookmarks Placeholder" static GtkWindow *bookmarks_window = NULL; static void refresh_bookmarks_menu (NemoWindow *window); static void remove_bookmarks_for_uri_if_yes (GtkDialog *dialog, int response, gpointer callback_data) { const char *uri; NemoWindow *window; g_assert (GTK_IS_DIALOG (dialog)); g_assert (callback_data != NULL); window = callback_data; if (response == GTK_RESPONSE_YES) { uri = g_object_get_data (G_OBJECT (dialog), "uri"); nemo_bookmark_list_delete_items_with_uri (window->details->bookmark_list, uri); } gtk_widget_destroy (GTK_WIDGET (dialog)); } static void show_bogus_bookmark_window (NemoWindow *window, NemoBookmark *bookmark) { GtkDialog *dialog; GFile *location; char *uri_for_display; char *prompt; char *detail; location = nemo_bookmark_get_location (bookmark); uri_for_display = g_file_get_parse_name (location); prompt = _("Do you want to remove any bookmarks with the " "non-existing location from your list?"); detail = g_strdup_printf (_("The location \"%s\" does not exist."), uri_for_display); dialog = eel_show_yes_no_dialog (prompt, detail, _("Bookmark for Nonexistent Location"), GTK_STOCK_CANCEL, GTK_WINDOW (window)); g_signal_connect (dialog, "response", G_CALLBACK (remove_bookmarks_for_uri_if_yes), window); g_object_set_data_full (G_OBJECT (dialog), "uri", g_file_get_uri (location), g_free); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_NO); g_object_unref (location); g_free (uri_for_display); g_free (detail); } static GtkWindow * get_or_create_bookmarks_window (NemoWindow *window) { GObject *undo_manager_source; undo_manager_source = G_OBJECT (window); if (bookmarks_window == NULL) { bookmarks_window = create_bookmarks_window (window->details->bookmark_list, undo_manager_source); } else { edit_bookmarks_dialog_set_signals (undo_manager_source); } return bookmarks_window; } /** * nemo_bookmarks_exiting: * * Last chance to save state before app exits. * Called when application exits; don't call from anywhere else. **/ void nemo_bookmarks_exiting (void) { if (bookmarks_window != NULL) { nemo_bookmarks_window_save_geometry (bookmarks_window); gtk_widget_destroy (GTK_WIDGET (bookmarks_window)); } } /** * add_bookmark_for_current_location * * Add a bookmark for the displayed location to the bookmarks menu. * Does nothing if there's already a bookmark for the displayed location. */ void nemo_window_add_bookmark_for_current_location (NemoWindow *window) { NemoBookmark *bookmark; NemoWindowSlot *slot; NemoBookmarkList *list; slot = nemo_window_get_active_slot (window); bookmark = slot->current_location_bookmark; list = window->details->bookmark_list; if (!nemo_bookmark_list_contains (list, bookmark)) { nemo_bookmark_list_append (list, bookmark); } } void nemo_window_edit_bookmarks (NemoWindow *window) { GtkWindow *dialog; dialog = get_or_create_bookmarks_window (window); gtk_window_set_screen ( dialog, gtk_window_get_screen (GTK_WINDOW (window))); gtk_window_present (dialog); } static void remove_bookmarks_menu_items (NemoWindow *window) { GtkUIManager *ui_manager; ui_manager = nemo_window_get_ui_manager (window); if (window->details->bookmarks_merge_id != 0) { gtk_ui_manager_remove_ui (ui_manager, window->details->bookmarks_merge_id); window->details->bookmarks_merge_id = 0; } if (window->details->bookmarks_action_group != NULL) { gtk_ui_manager_remove_action_group (ui_manager, window->details->bookmarks_action_group); window->details->bookmarks_action_group = NULL; } } static void connect_proxy_cb (GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, gpointer dummy) { GtkLabel *label; const gchar *icon_name; if (!GTK_IS_MENU_ITEM (proxy)) return; label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (proxy))); gtk_label_set_use_underline (label, FALSE); gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); gtk_label_set_max_width_chars (label, MENU_ITEM_MAX_WIDTH_CHARS); icon_name = g_object_get_data (G_OBJECT (action), "menu-icon-name"); if (icon_name != NULL) { gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU)); } } /* Struct that stores all the info necessary to activate a bookmark. */ typedef struct { NemoBookmark *bookmark; NemoWindow *window; GCallback refresh_callback; NemoBookmarkFailedCallback failed_callback; } BookmarkHolder; static BookmarkHolder * bookmark_holder_new (NemoBookmark *bookmark, NemoWindow *window, GCallback refresh_callback, NemoBookmarkFailedCallback failed_callback) { BookmarkHolder *new_bookmark_holder; new_bookmark_holder = g_new (BookmarkHolder, 1); new_bookmark_holder->window = window; new_bookmark_holder->bookmark = bookmark; new_bookmark_holder->failed_callback = failed_callback; new_bookmark_holder->refresh_callback = refresh_callback; /* Ref the bookmark because it might be unreffed away while * we're holding onto it (not an issue for window). */ g_object_ref (bookmark); g_signal_connect_object (bookmark, "notify::icon", refresh_callback, window, G_CONNECT_SWAPPED); g_signal_connect_object (bookmark, "notify::name", refresh_callback, window, G_CONNECT_SWAPPED); return new_bookmark_holder; } static void bookmark_holder_free (BookmarkHolder *bookmark_holder) { g_signal_handlers_disconnect_by_func (bookmark_holder->bookmark, bookmark_holder->refresh_callback, bookmark_holder->window); g_object_unref (bookmark_holder->bookmark); g_free (bookmark_holder); } static void bookmark_holder_free_cover (gpointer callback_data, GClosure *closure) { bookmark_holder_free (callback_data); } static void activate_bookmark_in_menu_item (GtkAction *action, gpointer user_data) { NemoWindowSlot *slot; BookmarkHolder *holder; GFile *location; holder = (BookmarkHolder *)user_data; location = nemo_bookmark_get_location (holder->bookmark); slot = nemo_window_get_active_slot (holder->window); nemo_window_slot_open_location (slot, location, nemo_event_get_window_open_flags ()); g_object_unref (location); } void nemo_menus_append_bookmark_to_menu (NemoWindow *window, NemoBookmark *bookmark, const char *parent_path, const char *parent_id, guint index_in_parent, GtkActionGroup *action_group, guint merge_id, GCallback refresh_callback, NemoBookmarkFailedCallback failed_callback) { BookmarkHolder *bookmark_holder; char action_name[128]; const char *name; gchar *icon_name; GtkAction *action; g_assert (NEMO_IS_WINDOW (window)); g_assert (NEMO_IS_BOOKMARK (bookmark)); bookmark_holder = bookmark_holder_new (bookmark, window, refresh_callback, failed_callback); name = nemo_bookmark_get_name (bookmark); /* Create menu item with pixbuf */ icon_name = nemo_bookmark_get_icon_name (bookmark); g_snprintf (action_name, sizeof (action_name), "%s%d", parent_id, index_in_parent); action = gtk_action_new (action_name, name, _("Go to the location specified by this bookmark"), NULL); g_object_set_data_full (G_OBJECT (action), "menu-icon-name", icon_name, g_free); g_signal_connect_data (action, "activate", G_CALLBACK (activate_bookmark_in_menu_item), bookmark_holder, bookmark_holder_free_cover, 0); gtk_action_group_add_action (action_group, GTK_ACTION (action)); g_object_unref (action); gtk_ui_manager_add_ui (window->details->ui_manager, merge_id, parent_path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, FALSE); } static void update_bookmarks (NemoWindow *window) { NemoBookmarkList *bookmarks; NemoBookmark *bookmark; guint bookmark_count; guint index; GtkUIManager *ui_manager; g_assert (NEMO_IS_WINDOW (window)); g_assert (window->details->bookmarks_merge_id == 0); g_assert (window->details->bookmarks_action_group == NULL); if (window->details->bookmark_list == NULL) { window->details->bookmark_list = nemo_bookmark_list_get_default (); } bookmarks = window->details->bookmark_list; ui_manager = nemo_window_get_ui_manager (NEMO_WINDOW (window)); window->details->bookmarks_merge_id = gtk_ui_manager_new_merge_id (ui_manager); window->details->bookmarks_action_group = gtk_action_group_new ("BookmarksGroup"); g_signal_connect (window->details->bookmarks_action_group, "connect-proxy", G_CALLBACK (connect_proxy_cb), NULL); gtk_ui_manager_insert_action_group (ui_manager, window->details->bookmarks_action_group, -1); g_object_unref (window->details->bookmarks_action_group); /* append new set of bookmarks */ bookmark_count = nemo_bookmark_list_length (bookmarks); for (index = 0; index < bookmark_count; ++index) { bookmark = nemo_bookmark_list_item_at (bookmarks, index); nemo_menus_append_bookmark_to_menu (NEMO_WINDOW (window), bookmark, MENU_PATH_BOOKMARKS_PLACEHOLDER, "dynamic", index, window->details->bookmarks_action_group, window->details->bookmarks_merge_id, G_CALLBACK (refresh_bookmarks_menu), show_bogus_bookmark_window); } } static void refresh_bookmarks_menu (NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); remove_bookmarks_menu_items (window); update_bookmarks (window); } /** * nemo_window_initialize_bookmarks_menu * * Fill in bookmarks menu with stored bookmarks, and wire up signals * so we'll be notified when bookmark list changes. */ void nemo_window_initialize_bookmarks_menu (NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); refresh_bookmarks_menu (window); /* Recreate dynamic part of menu if bookmark list changes */ g_signal_connect_object (window->details->bookmark_list, "changed", G_CALLBACK (refresh_bookmarks_menu), window, G_CONNECT_SWAPPED); } nemo-4.4.2/src/nemo-window-bookmarks.h000066400000000000000000000025671357442400300176640ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2005 Red Hat, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Alexander Larsson */ #ifndef NEMO_WINDOW_BOOKMARKS_H #define NEMO_WINDOW_BOOKMARKS_H #include #include #include "nemo-bookmark-list.h" void nemo_bookmarks_exiting (void); void nemo_window_add_bookmark_for_current_location (NemoWindow *window); void nemo_window_edit_bookmarks (NemoWindow *window); void nemo_window_initialize_bookmarks_menu (NemoWindow *window); #endif nemo-4.4.2/src/nemo-window-manage-views.c000066400000000000000000001702151357442400300202460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee * John Sullivan * Darin Adler */ #include #include "nemo-window-manage-views.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-floating-bar.h" #include "nemo-location-bar.h" #include "nemo-pathbar.h" #include "nemo-window-private.h" #include "nemo-window-slot.h" #include "nemo-trash-bar.h" #include "nemo-view-factory.h" #include "nemo-x-content-bar.h" #include "nemo-interesting-folder-bar.h" #include "nemo-thumbnail-problem-bar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_WINDOW #include /* FIXME bugzilla.gnome.org 41243: * We should use inheritance instead of these special cases * for the desktop window. */ #include "nemo-desktop-window.h" /* This number controls a maximum character count for a URL that is * displayed as part of a dialog. It's fairly arbitrary -- big enough * to allow most "normal" URIs to display in full, but small enough to * prevent the dialog from getting insanely wide. */ #define MAX_URI_IN_DIALOG_LENGTH 60 static void begin_location_change (NemoWindowSlot *slot, GFile *location, GFile *previous_location, GList *new_selection, NemoLocationChangeType type, guint distance, const char *scroll_pos, gboolean mount, NemoWindowGoToCallback callback, gpointer user_data); static void free_location_change (NemoWindowSlot *slot); static void end_location_change (NemoWindowSlot *slot); static void cancel_location_change (NemoWindowSlot *slot); static void got_file_info_for_view_selection_callback (NemoFile *file, gpointer callback_data); static void create_content_view (NemoWindowSlot *slot, const char *view_id); static void display_view_selection_failure (NemoWindow *window, NemoFile *file, GFile *location, GError *error); static void load_new_location (NemoWindowSlot *slot, GFile *location, GList *selection, gboolean tell_current_content_view, gboolean tell_new_content_view); static void location_has_really_changed (NemoWindowSlot *slot); static void update_for_new_location (NemoWindowSlot *slot); /* set_displayed_location: */ static void set_displayed_location (NemoWindowSlot *slot, GFile *location) { GFile *bookmark_location; gboolean recreate; if (slot->current_location_bookmark == NULL || location == NULL) { recreate = TRUE; } else { bookmark_location = nemo_bookmark_get_location (slot->current_location_bookmark); recreate = !g_file_equal (bookmark_location, location); g_object_unref (bookmark_location); } if (recreate) { /* We've changed locations, must recreate bookmark for current location. */ g_clear_object (&slot->last_location_bookmark); slot->last_location_bookmark = slot->current_location_bookmark; slot->current_location_bookmark = (location == NULL) ? NULL : nemo_bookmark_new (location, NULL, NULL, NULL); } } static void check_bookmark_location_matches (NemoBookmark *bookmark, GFile *location) { GFile *bookmark_location; char *bookmark_uri, *uri; bookmark_location = nemo_bookmark_get_location (bookmark); if (!g_file_equal (location, bookmark_location)) { bookmark_uri = g_file_get_uri (bookmark_location); uri = g_file_get_uri (location); g_warning ("bookmark uri is %s, but expected %s", bookmark_uri, uri); g_free (uri); g_free (bookmark_uri); } g_object_unref (bookmark_location); } /* Debugging function used to verify that the last_location_bookmark * is in the state we expect when we're about to use it to update the * Back or Forward list. */ static void check_last_bookmark_location_matches_slot (NemoWindowSlot *slot) { check_bookmark_location_matches (slot->last_location_bookmark, slot->location); } static void handle_go_back (NemoWindowSlot *slot, GFile *location) { guint i; GList *link; NemoBookmark *bookmark; /* Going back. Move items from the back list to the forward list. */ g_assert (g_list_length (slot->back_list) > slot->location_change_distance); check_bookmark_location_matches (NEMO_BOOKMARK (g_list_nth_data (slot->back_list, slot->location_change_distance)), location); g_assert (slot->location != NULL); /* Move current location to Forward list */ check_last_bookmark_location_matches_slot (slot); /* Use the first bookmark in the history list rather than creating a new one. */ slot->forward_list = g_list_prepend (slot->forward_list, slot->last_location_bookmark); g_object_ref (slot->forward_list->data); /* Move extra links from Back to Forward list */ for (i = 0; i < slot->location_change_distance; ++i) { bookmark = NEMO_BOOKMARK (slot->back_list->data); slot->back_list = g_list_remove (slot->back_list, bookmark); slot->forward_list = g_list_prepend (slot->forward_list, bookmark); } /* One bookmark falls out of back/forward lists and becomes viewed location */ link = slot->back_list; slot->back_list = g_list_remove_link (slot->back_list, link); g_object_unref (link->data); g_list_free_1 (link); } static void handle_go_forward (NemoWindowSlot *slot, GFile *location) { guint i; GList *link; NemoBookmark *bookmark; /* Going forward. Move items from the forward list to the back list. */ g_assert (g_list_length (slot->forward_list) > slot->location_change_distance); check_bookmark_location_matches (NEMO_BOOKMARK (g_list_nth_data (slot->forward_list, slot->location_change_distance)), location); g_assert (slot->location != NULL); /* Move current location to Back list */ check_last_bookmark_location_matches_slot (slot); /* Use the first bookmark in the history list rather than creating a new one. */ slot->back_list = g_list_prepend (slot->back_list, slot->last_location_bookmark); g_object_ref (slot->back_list->data); /* Move extra links from Forward to Back list */ for (i = 0; i < slot->location_change_distance; ++i) { bookmark = NEMO_BOOKMARK (slot->forward_list->data); slot->forward_list = g_list_remove (slot->back_list, bookmark); slot->back_list = g_list_prepend (slot->forward_list, bookmark); } /* One bookmark falls out of back/forward lists and becomes viewed location */ link = slot->forward_list; slot->forward_list = g_list_remove_link (slot->forward_list, link); g_object_unref (link->data); g_list_free_1 (link); } static void handle_go_elsewhere (NemoWindowSlot *slot, GFile *location) { /* Clobber the entire forward list, and move displayed location to back list */ nemo_window_slot_clear_forward_list (slot); if (slot->location != NULL) { /* If we're returning to the same uri somehow, don't put this uri on back list. * This also avoids a problem where set_displayed_location * didn't update last_location_bookmark since the uri didn't change. */ if (!g_file_equal (slot->location, location)) { /* Store bookmark for current location in back list, unless there is no current location */ check_last_bookmark_location_matches_slot (slot); /* Use the first bookmark in the history list rather than creating a new one. */ slot->back_list = g_list_prepend (slot->back_list, slot->last_location_bookmark); g_object_ref (slot->back_list->data); } } } static void viewed_file_changed_callback (NemoFile *file, NemoWindowSlot *slot) { GFile *new_location; gboolean is_in_trash, was_in_trash; g_assert (NEMO_IS_FILE (file)); g_assert (NEMO_IS_WINDOW_PANE (slot->pane)); g_assert (file == slot->viewed_file); if (!nemo_file_is_not_yet_confirmed (file)) { slot->viewed_file_seen = TRUE; } was_in_trash = slot->viewed_file_in_trash; slot->viewed_file_in_trash = is_in_trash = nemo_file_is_in_trash (file); /* Close window if the file it's viewing has been deleted or moved to trash. */ if (nemo_file_is_gone (file) || (is_in_trash && !was_in_trash)) { if (slot->back_list == NULL) { end_location_change (slot); gtk_widget_destroy (GTK_WIDGET (slot->content_view)); nemo_window_close (nemo_window_slot_get_window (slot)); return; } /* Don't close the window in the case where the * file was never seen in the first place. */ if (slot->viewed_file_seen) { /* auto-show existing parent. */ GFile *go_to_file, *parent, *location; /* Detecting a file is gone may happen in the * middle of a pending location change, we * need to cancel it before closing the window * or things break. */ /* FIXME: It makes no sense that this call is * needed. When the window is destroyed, it * calls nemo_window_manage_views_destroy, * which calls free_location_change, which * should be sufficient. Also, if this was * really needed, wouldn't it be needed for * all other nemo_window_close callers? */ end_location_change (slot); go_to_file = NULL; location = nemo_file_get_location (file); parent = g_file_get_parent (location); g_object_unref (location); if (parent) { go_to_file = nemo_find_existing_uri_in_hierarchy (parent); g_object_unref (parent); } if (go_to_file != NULL) { /* the path bar URI will be set to go_to_uri immediately * in begin_location_change, but we don't want the * inexistant children to show up anymore */ if (slot == slot->pane->active_slot) { /* multiview-TODO also update NemoWindowSlot * [which as of writing doesn't save/store any path bar state] */ nemo_path_bar_clear_buttons (NEMO_PATH_BAR (slot->pane->path_bar)); } nemo_window_slot_open_location (slot, go_to_file, 0); g_object_unref (go_to_file); } else { nemo_window_slot_go_home (slot, FALSE); } } } else { new_location = nemo_file_get_location (file); /* If the file was renamed, update location and/or * title. */ if (!g_file_equal (new_location, slot->location)) { g_object_unref (slot->location); slot->location = new_location; if (slot == slot->pane->active_slot) { nemo_window_pane_sync_location_widgets (slot->pane); } } else { /* TODO? * why do we update title & icon at all in this case? */ g_object_unref (new_location); } nemo_window_slot_update_title (slot); nemo_window_slot_update_icon (slot); } } static void update_history (NemoWindowSlot *slot, NemoLocationChangeType type, GFile *new_location) { switch (type) { case NEMO_LOCATION_CHANGE_STANDARD: handle_go_elsewhere (slot, new_location); return; case NEMO_LOCATION_CHANGE_RELOAD: /* for reload there is no work to do */ return; case NEMO_LOCATION_CHANGE_BACK: handle_go_back (slot, new_location); return; case NEMO_LOCATION_CHANGE_FORWARD: handle_go_forward (slot, new_location); return; default: break; } g_return_if_fail (FALSE); } static void cancel_viewed_file_changed_callback (NemoWindowSlot *slot) { NemoFile *file; file = slot->viewed_file; if (file != NULL) { g_signal_handlers_disconnect_by_func (G_OBJECT (file), G_CALLBACK (viewed_file_changed_callback), slot); nemo_file_monitor_remove (file, &slot->viewed_file); } } static void new_window_show_callback (GtkWidget *widget, gpointer user_data){ NemoWindow *window; window = NEMO_WINDOW (user_data); nemo_window_close (window); g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (new_window_show_callback), user_data); } void nemo_window_slot_open_location_full (NemoWindowSlot *slot, GFile *location, NemoWindowOpenFlags flags, GList *new_selection, NemoWindowGoToCallback callback, gpointer user_data) { NemoWindow *window; NemoWindow *target_window; NemoWindowPane *pane; NemoWindowSlot *target_slot; NemoWindowOpenFlags slot_flags; GFile *old_location; char *old_uri, *new_uri; int new_slot_position; GList *l; gboolean use_same; gboolean is_desktop; NemoApplication *app; window = nemo_window_slot_get_window (slot); target_window = NULL; target_slot = NULL; use_same = FALSE; /* this happens at startup */ old_uri = nemo_window_slot_get_location_uri (slot); if (old_uri == NULL) { old_uri = g_strdup ("(none)"); use_same = TRUE; } new_uri = g_file_get_uri (location); DEBUG ("Opening location, old: %s, new: %s", old_uri, new_uri); g_free (old_uri); g_free (new_uri); is_desktop = NEMO_IS_DESKTOP_WINDOW (window); if (is_desktop) { use_same = !nemo_desktop_window_loaded (NEMO_DESKTOP_WINDOW (window)); /* if we're requested to open a new tab on the desktop, open a window * instead. */ if (flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) { flags ^= NEMO_WINDOW_OPEN_FLAG_NEW_TAB; flags |= NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } } else { use_same |= g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER); } g_assert (!((flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0 && (flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0)); /* and if the flags specify so, this is overridden */ if ((flags & NEMO_WINDOW_OPEN_FLAG_SEARCH) != 0) { use_same = TRUE; } else if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0) { use_same = FALSE; } /* now get/create the window */ if (use_same) { target_window = window; } else { app = nemo_application_get_singleton (); target_window = nemo_application_create_window (app, gtk_window_get_screen (GTK_WINDOW (window))); } old_location = nemo_window_slot_get_location (slot); g_assert (target_window != NULL); /* if the flags say we want a new tab, open a slot in the current window */ if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0) { g_assert (target_window == window); slot_flags = 0; new_slot_position = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_NEW_TAB_POSITION); if (new_slot_position == NEMO_NEW_TAB_POSITION_END) { slot_flags = NEMO_WINDOW_OPEN_SLOT_APPEND; } target_slot = nemo_window_pane_open_slot (nemo_window_get_active_pane (window), slot_flags); } /* close the current window if the flags say so */ if ((flags & NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0) { if (!is_desktop) { if (gtk_widget_get_visible (GTK_WIDGET (target_window))) { nemo_window_close (window); } else { g_signal_connect_object (target_window, "show", G_CALLBACK (new_window_show_callback), window, G_CONNECT_AFTER); } } } if (target_slot == NULL) { if (target_window == window) { target_slot = slot; } else { target_slot = nemo_window_get_active_slot (target_window); } } if (target_window == window && target_slot == slot && old_location && g_file_equal (old_location, location) && !is_desktop) { if (callback != NULL) { callback (window, NULL, user_data); } g_object_unref (old_location); return; } begin_location_change (target_slot, location, old_location, new_selection, NEMO_LOCATION_CHANGE_STANDARD, 0, NULL, (flags & NEMO_WINDOW_OPEN_FLAG_MOUNT), callback, user_data); /* Additionally, load this in all slots that have no location, this means we load both panes in e.g. a newly opened dual pane window. */ for (l = target_window->details->panes; l != NULL; l = l->next) { pane = l->data; slot = pane->active_slot; if (slot->location == NULL && slot->pending_location == NULL) { begin_location_change (slot, location, old_location, new_selection, NEMO_LOCATION_CHANGE_STANDARD, 0, NULL, (flags & NEMO_WINDOW_OPEN_FLAG_MOUNT), NULL, NULL); } } g_clear_object (&old_location); } const char * nemo_window_slot_get_content_view_id (NemoWindowSlot *slot) { if (slot->content_view == NULL) { return NULL; } return nemo_view_get_view_id (slot->content_view); } gboolean nemo_window_slot_content_view_matches_iid (NemoWindowSlot *slot, const char *iid) { if (slot->content_view == NULL) { return FALSE; } return g_strcmp0 (nemo_view_get_view_id (slot->content_view), iid) == 0; } static gboolean report_callback (NemoWindowSlot *slot, GError *error) { if (slot->open_callback != NULL) { slot->open_callback (nemo_window_slot_get_window (slot), error, slot->open_callback_user_data); slot->open_callback = NULL; slot->open_callback_user_data = NULL; return TRUE; } return FALSE; } /* * begin_location_change * * Change a window slot's location. * @window: The NemoWindow whose location should be changed. * @location: A url specifying the location to load * @previous_location: The url that was previously shown in the window that initialized the change, if any * @new_selection: The initial selection to present after loading the location * @type: Which type of location change is this? Standard, back, forward, or reload? * @distance: If type is back or forward, the index into the back or forward chain. If * type is standard or reload, this is ignored, and must be 0. * @scroll_pos: The file to scroll to when the location is loaded. * @mount: is a mount (always force a reload). * @callback: function to be called when the location is changed. * @user_data: data for @callback. * * This is the core function for changing the location of a window. Every change to the * location begins here. */ static void begin_location_change (NemoWindowSlot *slot, GFile *location, GFile *previous_location, GList *new_selection, NemoLocationChangeType type, guint distance, const char *scroll_pos, gboolean mount, NemoWindowGoToCallback callback, gpointer user_data) { NemoDirectory *directory; NemoFile *file; gboolean force_reload; char *current_pos; GFile *from_folder, *parent; GList *parent_selection = NULL; g_assert (slot != NULL); g_assert (location != NULL); g_assert (type == NEMO_LOCATION_CHANGE_BACK || type == NEMO_LOCATION_CHANGE_FORWARD || distance == 0); /* If there is no new selection and the new location is * a (grand)parent of the old location then we automatically * select the folder the previous location was in */ if (new_selection == NULL && previous_location != NULL && g_file_has_prefix (previous_location, location)) { from_folder = g_object_ref (previous_location); parent = g_file_get_parent (from_folder); while (parent != NULL && !g_file_equal (parent, location)) { g_object_unref (from_folder); from_folder = parent; parent = g_file_get_parent (from_folder); } if (parent != NULL) { new_selection = parent_selection = g_list_prepend (NULL, nemo_file_get (from_folder)); g_object_unref (parent); } g_object_unref (from_folder); } end_location_change (slot); nemo_window_slot_set_allow_stop (slot, TRUE); nemo_window_slot_set_status (slot, " ", NULL); g_assert (slot->pending_location == NULL); g_assert (slot->pending_selection == NULL); slot->pending_location = g_object_ref (location); slot->location_change_type = type; slot->location_change_distance = distance; slot->tried_mount = FALSE; slot->pending_selection = eel_g_object_list_copy (new_selection); slot->pending_scroll_to = g_strdup (scroll_pos); slot->open_callback = callback; slot->open_callback_user_data = user_data; directory = nemo_directory_get (location); /* The code to force a reload is here because if we do it * after determining an initial view (in the components), then * we end up fetching things twice. */ if (type == NEMO_LOCATION_CHANGE_RELOAD || mount) { force_reload = TRUE; } else if (!nemo_monitor_active ()) { force_reload = TRUE; } else { force_reload = !nemo_directory_is_local (directory); } if (force_reload) { file = nemo_directory_get_corresponding_file (directory); nemo_file_invalidate_all_attributes (file); nemo_file_unref (file); nemo_directory_force_reload (directory); } nemo_directory_unref (directory); if (parent_selection != NULL) { g_list_free_full (parent_selection, g_object_unref); } /* Set current_bookmark scroll pos */ if (slot->current_location_bookmark != NULL && slot->content_view != NULL) { current_pos = nemo_view_get_first_visible_file (slot->content_view); nemo_bookmark_set_scroll_pos (slot->current_location_bookmark, current_pos); g_free (current_pos); } /* Get the info needed for view selection */ slot->determine_view_file = nemo_file_get (location); g_assert (slot->determine_view_file != NULL); /* if the currently viewed file is marked gone while loading the new location, * this ensures that the window isn't destroyed */ cancel_viewed_file_changed_callback (slot); nemo_file_call_when_ready (slot->determine_view_file, NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_MOUNT, got_file_info_for_view_selection_callback, slot); } typedef struct { GCancellable *cancellable; NemoWindowSlot *slot; } MountNotMountedData; static void mount_not_mounted_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { MountNotMountedData *data; NemoWindowSlot *slot; GError *error; GCancellable *cancellable; data = user_data; slot = data->slot; cancellable = data->cancellable; g_free (data); if (g_cancellable_is_cancelled (cancellable)) { /* Cancelled, don't call back */ g_object_unref (cancellable); return; } slot->mount_cancellable = NULL; slot->determine_view_file = nemo_file_get (slot->pending_location); error = NULL; if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) { slot->mount_error = error; got_file_info_for_view_selection_callback (slot->determine_view_file, slot); slot->mount_error = NULL; g_error_free (error); } else { nemo_file_invalidate_all_attributes (slot->determine_view_file); nemo_file_call_when_ready (slot->determine_view_file, NEMO_FILE_ATTRIBUTE_INFO, got_file_info_for_view_selection_callback, slot); } g_object_unref (cancellable); } static void got_file_info_for_view_selection_callback (NemoFile *file, gpointer callback_data) { GError *error; char *view_id; char *mimetype; NemoWindow *window; NemoWindowSlot *slot; NemoFile *parent_file, *tmp; GFile *location; GMountOperation *mount_op; MountNotMountedData *data; NemoApplication *app; slot = callback_data; window = nemo_window_slot_get_window (slot); g_assert (slot->determine_view_file == file); slot->determine_view_file = NULL; if (slot->mount_error) { error = slot->mount_error; } else { error = nemo_file_get_file_info_error (file); } if (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED && !slot->tried_mount) { slot->tried_mount = TRUE; mount_op = gtk_mount_operation_new (GTK_WINDOW (window)); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); location = nemo_file_get_location (file); data = g_new0 (MountNotMountedData, 1); data->cancellable = g_cancellable_new (); data->slot = slot; slot->mount_cancellable = data->cancellable; g_file_mount_enclosing_volume (location, 0, mount_op, slot->mount_cancellable, mount_not_mounted_callback, data); g_object_unref (location); g_object_unref (mount_op); nemo_file_unref (file); return; } parent_file = nemo_file_get_parent (file); if ((parent_file != NULL) && nemo_file_get_file_type (file) == G_FILE_TYPE_REGULAR) { if (slot->pending_selection != NULL) { g_list_free_full (slot->pending_selection, (GDestroyNotify) nemo_file_unref); } g_clear_object (&slot->pending_location); g_free (slot->pending_scroll_to); slot->pending_location = nemo_file_get_parent_location (file); slot->pending_selection = g_list_prepend (NULL, nemo_file_ref (file)); slot->determine_view_file = parent_file; slot->pending_scroll_to = nemo_file_get_uri (file); nemo_file_invalidate_all_attributes (slot->determine_view_file); nemo_file_call_when_ready (slot->determine_view_file, NEMO_FILE_ATTRIBUTE_INFO, got_file_info_for_view_selection_callback, slot); nemo_file_unref (file); return; } nemo_file_unref (parent_file); location = slot->pending_location; view_id = NULL; if (error == NULL || (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED)) { /* We got the information we need, now pick what view to use: */ mimetype = nemo_file_get_mime_type (file); /* Look in metadata for view */ if (nemo_global_preferences_get_inherit_folder_viewer_preference ()) { if (nemo_global_preferences_get_ignore_view_metadata ()) { view_id = g_strdup (nemo_window_get_ignore_meta_view_id (window)); } else { parent_file = file; nemo_file_ref(parent_file); // Do this once for the initial file while (parent_file) { view_id = nemo_file_get_metadata (parent_file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL); tmp = nemo_file_get_parent (parent_file); nemo_file_unref(parent_file); if (view_id != NULL) { parent_file = NULL; } else { parent_file = tmp; } } } } else { view_id = nemo_global_preferences_get_ignore_view_metadata () ? g_strdup (nemo_window_get_ignore_meta_view_id (window)) : nemo_file_get_metadata (file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL); } if (view_id != NULL && !nemo_view_factory_view_supports_uri (view_id, location, nemo_file_get_file_type (file), mimetype)) { g_free (view_id); view_id = NULL; } /* Otherwise, use default */ if (view_id == NULL) { gchar *name, *uri; name = nemo_file_get_name (file); uri = nemo_file_get_uri (file); if (g_strcmp0 (name, "x-nemo-search") == 0) { view_id = g_strdup (NEMO_LIST_VIEW_IID); } else if (eel_uri_is_desktop (uri)) { view_id = nemo_global_preferences_get_desktop_iid (); } else { view_id = nemo_global_preferences_get_default_folder_viewer_preference_as_iid (); } g_free (uri); g_free (name); if (view_id != NULL && !nemo_view_factory_view_supports_uri (view_id, location, nemo_file_get_file_type (file), mimetype)) { g_free (view_id); view_id = NULL; } } g_free (mimetype); } if (view_id != NULL) { create_content_view (slot, view_id); g_free (view_id); report_callback (slot, NULL); } else { if (!report_callback (slot, error)) { display_view_selection_failure (window, file, location, error); } if (!gtk_widget_get_visible (GTK_WIDGET (window))) { /* Destroy never-had-a-chance-to-be-seen window. This case * happens when a new window cannot display its initial URI. */ /* if this is the only window, we don't want to quit, so we redirect it to home */ app = nemo_application_get_singleton (); if (g_list_length (gtk_application_get_windows (GTK_APPLICATION (app))) == 1) { /* the user could have typed in a home directory that doesn't exist, in which case going home would cause an infinite loop, so we better test for that */ if (!nemo_is_root_directory (location)) { if (!nemo_is_home_directory (location)) { nemo_window_slot_go_home (slot, FALSE); } else { GFile *root; root = g_file_new_for_path ("/"); /* the last fallback is to go to a known place that can't be deleted! */ nemo_window_slot_open_location (slot, location, 0); g_object_unref (root); } } else { gtk_widget_destroy (GTK_WIDGET (window)); } } else { /* Since this is a window, destroying it will also unref it. */ gtk_widget_destroy (GTK_WIDGET (window)); } } else { /* Clean up state of already-showing window */ end_location_change (slot); /* TODO? shouldn't we call * cancel_viewed_file_changed_callback (slot); * at this point, or in end_location_change() */ /* We're missing a previous location (if opened location * in a new tab) so close it and return */ if (slot->location == NULL) { nemo_window_pane_close_slot (slot->pane, slot); } else { /* We disconnected this, so we need to re-connect it */ NemoFile *viewed_file; viewed_file = nemo_file_get (slot->location); nemo_window_slot_set_viewed_file (slot, viewed_file); nemo_file_monitor_add (viewed_file, &slot->viewed_file, 0); g_signal_connect_object (viewed_file, "changed", G_CALLBACK (viewed_file_changed_callback), slot, 0); nemo_file_unref (viewed_file); /* Leave the location bar showing the bad location that the user * typed (or maybe achieved by dragging or something). Many times * the mistake will just be an easily-correctable typo. The user * can choose "Refresh" to get the original URI back in the location bar. */ } } } nemo_file_unref (file); } /* Load a view into the window, either reusing the old one or creating * a new one. This happens when you want to load a new location, or just * switch to a different view. * If pending_location is set we're loading a new location and * pending_location/selection will be used. If not, we're just switching * view, and the current location will be used. */ static void create_content_view (NemoWindowSlot *slot, const char *view_id) { NemoWindow *window; NemoView *view; GList *selection; window = nemo_window_slot_get_window (slot); if (slot->content_view != NULL && g_strcmp0 (nemo_view_get_view_id (slot->content_view), view_id) == 0) { /* reuse existing content view */ view = slot->content_view; slot->new_content_view = view; g_object_ref (view); } else { /* create a new content view */ view = nemo_view_factory_create (view_id, slot); slot->new_content_view = view; nemo_window_connect_content_view (window, slot->new_content_view); } if (NEMO_IS_DESKTOP_WINDOW (window)) { NemoDesktopDirectory *directory; directory = NEMO_DESKTOP_DIRECTORY (nemo_directory_get (slot->pending_location)); directory->display_number = nemo_desktop_window_get_monitor (NEMO_DESKTOP_WINDOW (window)); nemo_directory_unref (NEMO_DIRECTORY (directory)); } /* Actually load the pending location and selection: */ if (slot->pending_location != NULL) { load_new_location (slot, slot->pending_location, slot->pending_selection, FALSE, TRUE); g_list_free_full (slot->pending_selection, g_object_unref); slot->pending_selection = NULL; } else if (slot->location != NULL) { selection = nemo_view_get_selection (slot->content_view); load_new_location (slot, slot->location, selection, FALSE, TRUE); g_list_free_full (selection, g_object_unref); } else { /* Something is busted, there was no location to load. Just load the homedir. */ nemo_window_slot_go_home (slot, FALSE); } } static void load_new_location (NemoWindowSlot *slot, GFile *location, GList *selection, gboolean tell_current_content_view, gboolean tell_new_content_view) { GList *selection_copy; NemoView *view; g_assert (slot != NULL); g_assert (location != NULL); selection_copy = eel_g_object_list_copy (selection); view = NULL; /* Note, these may recurse into report_load_underway */ if (slot->content_view != NULL && tell_current_content_view) { view = slot->content_view; nemo_view_load_location (slot->content_view, location); } if (slot->new_content_view != NULL && tell_new_content_view && (!tell_current_content_view || slot->new_content_view != slot->content_view) ) { view = slot->new_content_view; nemo_view_load_location (slot->new_content_view, location); } if (view != NULL) { /* slot->new_content_view might have changed here if report_load_underway was called from load_location */ nemo_view_set_selection (view, selection_copy); } g_list_free_full (selection_copy, g_object_unref); } /* A view started to load the location its viewing, either due to * a load_location request, or some internal reason. Expect * a matching load_compete later */ void nemo_window_report_load_underway (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; g_assert (NEMO_IS_WINDOW (window)); if (window->details->temporarily_ignore_view_signals) { return; } slot = nemo_window_get_slot_for_view (window, view); g_assert (slot != NULL); if (view == slot->new_content_view) { location_has_really_changed (slot); } else { nemo_window_slot_set_allow_stop (slot, TRUE); } } static void nemo_window_emit_location_change (NemoWindow *window, GFile *location) { char *uri; uri = g_file_get_uri (location); g_signal_emit_by_name (window, "loading_uri", uri); g_free (uri); } static void nemo_window_slot_emit_location_change (NemoWindowSlot *slot, GFile *from, GFile *to) { char *from_uri = NULL; char *to_uri = NULL; if (from != NULL) from_uri = g_file_get_uri (from); if (to != NULL) to_uri = g_file_get_uri (to); g_signal_emit_by_name (slot, "location-changed", from_uri, to_uri); g_free (to_uri); g_free (from_uri); } /* reports location change to window's "loading-uri" clients, i.e. * sidebar panels [used when switching tabs]. It will emit the pending * location, or the existing location if none is pending. */ void nemo_window_report_location_change (NemoWindow *window) { NemoWindowSlot *slot; GFile *location; slot = nemo_window_get_active_slot (window); g_assert (NEMO_IS_WINDOW_SLOT (slot)); location = NULL; if (slot->pending_location != NULL) { location = slot->pending_location; } if (location == NULL && slot->location != NULL) { location = slot->location; } if (location != NULL) { nemo_window_emit_location_change (window, location); } } static void real_setup_loading_floating_bar (NemoWindowSlot *slot) { gboolean disable_chrome; g_object_get (nemo_window_slot_get_window (slot), "disable-chrome", &disable_chrome, NULL); if (disable_chrome) { gtk_widget_hide (slot->floating_bar); return; } nemo_floating_bar_set_label (NEMO_FLOATING_BAR (slot->floating_bar), NEMO_IS_SEARCH_DIRECTORY (nemo_view_get_model (slot->content_view)) ? _("Searching...") : _("Loading...")); nemo_floating_bar_set_show_spinner (NEMO_FLOATING_BAR (slot->floating_bar), TRUE); nemo_floating_bar_add_action (NEMO_FLOATING_BAR (slot->floating_bar), GTK_STOCK_STOP, NEMO_FLOATING_BAR_ACTION_ID_STOP); gtk_widget_set_halign (slot->floating_bar, GTK_ALIGN_END); gtk_widget_show (slot->floating_bar); } static gboolean setup_loading_floating_bar_timeout_cb (gpointer user_data) { NemoWindowSlot *slot = user_data; slot->loading_timeout_id = 0; real_setup_loading_floating_bar (slot); return FALSE; } static void setup_loading_floating_bar (NemoWindowSlot *slot) { /* setup loading overlay */ if (slot->set_status_timeout_id != 0) { g_source_remove (slot->set_status_timeout_id); slot->set_status_timeout_id = 0; } if (slot->loading_timeout_id != 0) { g_source_remove (slot->loading_timeout_id); slot->loading_timeout_id = 0; } slot->loading_timeout_id = g_timeout_add (500, setup_loading_floating_bar_timeout_cb, slot); } /* This is called when we have decided we can actually change to the new view/location situation. */ static void location_has_really_changed (NemoWindowSlot *slot) { NemoWindow *window; GtkWidget *widget; GFile *location_copy; window = nemo_window_slot_get_window (slot); if (slot->new_content_view != NULL) { widget = GTK_WIDGET (slot->new_content_view); /* Switch to the new content view. */ if (gtk_widget_get_parent (widget) == NULL) { nemo_window_slot_set_content_view_widget (slot, slot->new_content_view); } g_object_unref (slot->new_content_view); slot->new_content_view = NULL; } if (slot->pending_location != NULL) { /* Tell the window we are finished. */ update_for_new_location (slot); } location_copy = NULL; if (slot->location != NULL) { location_copy = g_object_ref (slot->location); } free_location_change (slot); if (location_copy != NULL) { if (slot == nemo_window_get_active_slot (window)) { nemo_window_emit_location_change (window, location_copy); } g_object_unref (location_copy); } setup_loading_floating_bar (slot); } static void slot_add_extension_extra_widgets (NemoWindowSlot *slot) { GList *providers, *l; GtkWidget *widget; char *uri; NemoWindow *window; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_LOCATION_WIDGET_PROVIDER); window = nemo_window_slot_get_window (slot); uri = g_file_get_uri (slot->location); for (l = providers; l != NULL; l = l->next) { NemoLocationWidgetProvider *provider; provider = NEMO_LOCATION_WIDGET_PROVIDER (l->data); widget = nemo_location_widget_provider_get_widget (provider, uri, GTK_WIDGET (window)); if (widget != NULL) { nemo_window_slot_add_extra_location_widget (slot, widget); } } g_free (uri); nemo_module_extension_list_free (providers); } static void nemo_window_slot_show_x_content_bar (NemoWindowSlot *slot, GMount *mount, const char **x_content_types) { unsigned int n; g_assert (NEMO_IS_WINDOW_SLOT (slot)); for (n = 0; x_content_types[n] != NULL; n++) { GAppInfo *default_app; /* skip blank media; the burn:/// location will provide it's own cluebar */ if (g_str_has_prefix (x_content_types[n], "x-content/blank-")) { continue; } /* don't show the cluebar for windows software */ if (g_content_type_is_a (x_content_types[n], "x-content/win32-software")) { continue; } /* only show the cluebar if a default app is available */ default_app = g_app_info_get_default_for_type (x_content_types[n], FALSE); if (default_app != NULL) { GtkWidget *bar; bar = nemo_x_content_bar_new (mount, x_content_types[n]); gtk_widget_show (bar); nemo_window_slot_add_extra_location_widget (slot, bar); g_object_unref (default_app); } } } static void nemo_window_slot_show_trash_bar (NemoWindowSlot *slot) { GtkWidget *bar; NemoView *view; view = nemo_window_slot_get_current_view (slot); bar = nemo_trash_bar_new (view); gtk_widget_show (bar); nemo_window_slot_add_extra_location_widget (slot, bar); } static void maybe_show_interesting_folder_bar (NemoWindowSlot *slot) { GtkWidget *bar = nemo_interesting_folder_bar_new_for_location (nemo_window_slot_get_current_view(slot), slot->location); if (bar) { gtk_widget_show (bar); nemo_window_slot_add_extra_location_widget (slot, bar); } } typedef struct { NemoWindowSlot *slot; GCancellable *cancellable; GMount *mount; } FindMountData; static void found_content_type_cb (const char **x_content_types, gpointer user_data) { NemoWindowSlot *slot; FindMountData *data = user_data; if (g_cancellable_is_cancelled (data->cancellable)) { goto out; } slot = data->slot; if (x_content_types != NULL && x_content_types[0] != NULL) { nemo_window_slot_show_x_content_bar (slot, data->mount, x_content_types); } slot->find_mount_cancellable = NULL; out: g_object_unref (data->mount); g_object_unref (data->cancellable); g_free (data); } static void found_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { FindMountData *data = user_data; GMount *mount; if (g_cancellable_is_cancelled (data->cancellable)) { goto out; } mount = g_file_find_enclosing_mount_finish (G_FILE (source_object), res, NULL); if (mount != NULL) { data->mount = mount; nemo_get_x_content_types_for_mount_async (mount, found_content_type_cb, data->cancellable, data); return; } data->slot->find_mount_cancellable = NULL; out: g_object_unref (data->cancellable); g_free (data); } /* Handle the changes for the NemoWindow itself. */ static void update_for_new_location (NemoWindowSlot *slot) { NemoWindow *window; GFile *new_location; NemoFile *file; NemoDirectory *directory; gboolean location_really_changed; FindMountData *data; window = nemo_window_slot_get_window (slot); new_location = slot->pending_location; slot->pending_location = NULL; set_displayed_location (slot, new_location); update_history (slot, slot->location_change_type, new_location); location_really_changed = slot->location == NULL || !g_file_equal (slot->location, new_location); nemo_window_slot_emit_location_change (slot, slot->location, new_location); /* Set the new location. */ g_clear_object (&slot->location); slot->location = new_location; /* Create a NemoFile for this location, so we can catch it * if it goes away. */ cancel_viewed_file_changed_callback (slot); file = nemo_file_get (slot->location); nemo_window_slot_set_viewed_file (slot, file); slot->viewed_file_seen = !nemo_file_is_not_yet_confirmed (file); slot->viewed_file_in_trash = nemo_file_is_in_trash (file); nemo_file_monitor_add (file, &slot->viewed_file, 0); g_signal_connect_object (file, "changed", G_CALLBACK (viewed_file_changed_callback), slot, 0); nemo_file_unref (file); if (slot == nemo_window_get_active_slot (window)) { /* Sync up and zoom action states */ nemo_window_sync_up_button (window); nemo_window_sync_zoom_widgets (window); nemo_window_sync_bookmark_action (window); nemo_window_sync_view_type (window); nemo_window_sync_thumbnail_action(window); /* Load menus from nemo extensions for this location */ nemo_window_load_extension_menus (window); } if (location_really_changed) { nemo_window_slot_remove_extra_location_widgets (slot); directory = nemo_directory_get (slot->location); if (nemo_directory_is_in_trash (directory)) { nemo_window_slot_show_trash_bar (slot); } maybe_show_interesting_folder_bar (slot); nemo_window_slot_check_bad_cache_bar (slot); /* need the mount to determine if we should put up the x-content cluebar */ if (slot->find_mount_cancellable != NULL) { g_cancellable_cancel (slot->find_mount_cancellable); slot->find_mount_cancellable = NULL; } data = g_new (FindMountData, 1); data->slot = slot; data->cancellable = g_cancellable_new (); data->mount = NULL; slot->find_mount_cancellable = data->cancellable; g_file_find_enclosing_mount_async (slot->location, G_PRIORITY_DEFAULT, data->cancellable, found_mount_cb, data); nemo_directory_unref (directory); slot_add_extension_extra_widgets (slot); } nemo_window_slot_update_title (slot); nemo_window_slot_update_icon (slot); if (slot == slot->pane->active_slot) { nemo_window_pane_sync_location_widgets (slot->pane); if (location_really_changed) { nemo_window_pane_sync_search_widgets (slot->pane); } } nemo_window_sync_menu_bar (window); } /* A location load previously announced by load_underway * has been finished */ void nemo_window_report_load_complete (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; g_assert (NEMO_IS_WINDOW (window)); if (window->details->temporarily_ignore_view_signals) { return; } slot = nemo_window_get_slot_for_view (window, view); g_assert (slot != NULL); /* Only handle this if we're expecting it. * Don't handle it if its from an old view we've switched from */ if (view == slot->content_view) { if (slot->pending_scroll_to != NULL) { nemo_view_scroll_to_file (slot->content_view, slot->pending_scroll_to); } end_location_change (slot); } } static void remove_loading_floating_bar (NemoWindowSlot *slot) { if (slot->loading_timeout_id != 0) { g_source_remove (slot->loading_timeout_id); slot->loading_timeout_id = 0; } gtk_widget_hide (slot->floating_bar); nemo_floating_bar_cleanup_actions (NEMO_FLOATING_BAR (slot->floating_bar)); } static void end_location_change (NemoWindowSlot *slot) { char *uri; uri = nemo_window_slot_get_location_uri (slot); if (uri) { DEBUG ("Finished loading window for uri %s", uri); g_free (uri); } nemo_window_slot_set_allow_stop (slot, FALSE); remove_loading_floating_bar (slot); /* Now we can free pending_scroll_to, since the load_complete * callback already has been emitted. */ g_free (slot->pending_scroll_to); slot->pending_scroll_to = NULL; free_location_change (slot); } static void free_location_change (NemoWindowSlot *slot) { NemoWindow *window; window = nemo_window_slot_get_window (slot); g_clear_object (&slot->pending_location); g_list_free_full (slot->pending_selection, g_object_unref); slot->pending_selection = NULL; /* Don't free pending_scroll_to, since thats needed until * the load_complete callback. */ if (slot->mount_cancellable != NULL) { g_cancellable_cancel (slot->mount_cancellable); slot->mount_cancellable = NULL; } if (slot->determine_view_file != NULL) { nemo_file_cancel_call_when_ready (slot->determine_view_file, got_file_info_for_view_selection_callback, slot); slot->determine_view_file = NULL; } if (slot->new_content_view != NULL) { window->details->temporarily_ignore_view_signals = TRUE; nemo_view_stop_loading (slot->new_content_view); window->details->temporarily_ignore_view_signals = FALSE; nemo_window_disconnect_content_view (window, slot->new_content_view); g_object_unref (slot->new_content_view); slot->new_content_view = NULL; } } static void cancel_location_change (NemoWindowSlot *slot) { GList *selection; if (slot->pending_location != NULL && slot->location != NULL && slot->content_view != NULL) { /* No need to tell the new view - either it is the * same as the old view, in which case it will already * be told, or it is the very pending change we wish * to cancel. */ selection = nemo_view_get_selection (slot->content_view); load_new_location (slot, slot->location, selection, TRUE, FALSE); g_list_free_full (selection, g_object_unref); } end_location_change (slot); } static void display_view_selection_failure (NemoWindow *window, NemoFile *file, GFile *location, GError *error) { char *full_uri_for_display; char *uri_for_display; char *error_message; char *detail_message; char *scheme_string; /* Some sort of failure occurred. How 'bout we tell the user? */ full_uri_for_display = g_file_get_parse_name (location); /* Truncate the URI so it doesn't get insanely wide. Note that even * though the dialog uses wrapped text, if the URI doesn't contain * white space then the text-wrapping code is too stupid to wrap it. */ uri_for_display = eel_str_middle_truncate (full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH); g_free (full_uri_for_display); error_message = NULL; detail_message = NULL; if (error == NULL) { if (nemo_file_is_directory (file)) { error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); detail_message = g_strdup (_("Nemo has no installed viewer capable of displaying the folder.")); } else { error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); detail_message = g_strdup (_("The location is not a folder.")); } } else if (error->domain == G_IO_ERROR) { switch (error->code) { case G_IO_ERROR_NOT_FOUND: error_message = g_strdup_printf (_("Could not find \"%s\"."), uri_for_display); detail_message = g_strdup (_("Please check the spelling and try again.")); break; case G_IO_ERROR_NOT_SUPPORTED: scheme_string = g_file_get_uri_scheme (location); error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); if (scheme_string != NULL) { detail_message = g_strdup_printf (_("Nemo cannot handle \"%s\" locations."), scheme_string); } else { detail_message = g_strdup (_("Nemo cannot handle this kind of location.")); } g_free (scheme_string); break; case G_IO_ERROR_NOT_MOUNTED: error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); detail_message = g_strdup (_("Unable to mount the location.")); break; case G_IO_ERROR_PERMISSION_DENIED: error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); detail_message = g_strdup (_("Access was denied.")); break; case G_IO_ERROR_HOST_NOT_FOUND: /* This case can be hit for user-typed strings like "foo" due to * the code that guesses web addresses when there's no initial "/". * But this case is also hit for legitimate web addresses when * the proxy is set up wrong. */ error_message = g_strdup_printf (_("Could not display \"%s\", because the host could not be found."), uri_for_display); detail_message = g_strdup (_("Check that the spelling is correct and that your proxy settings are correct.")); break; case G_IO_ERROR_CANCELLED: case G_IO_ERROR_FAILED_HANDLED: g_free (uri_for_display); return; default: break; } } if (error_message == NULL) { error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display); detail_message = g_strdup_printf (_("Error: %s\nPlease select another viewer and try again."), error->message); } eel_show_error_dialog (error_message, detail_message, NULL); g_free (uri_for_display); g_free (error_message); g_free (detail_message); } void nemo_window_slot_stop_loading (NemoWindowSlot *slot) { NemoWindow *window; window = nemo_window_slot_get_window (slot); nemo_view_stop_loading (slot->content_view); if (slot->new_content_view != NULL) { window->details->temporarily_ignore_view_signals = TRUE; nemo_view_stop_loading (slot->new_content_view); window->details->temporarily_ignore_view_signals = FALSE; } cancel_location_change (slot); } void nemo_window_slot_set_content_view (NemoWindowSlot *slot, const char *id) { NemoFile *file; char *uri; g_assert (slot != NULL); g_assert (slot->location != NULL); g_assert (id != NULL); uri = nemo_window_slot_get_location_uri (slot); DEBUG ("Change view of window %s to %s", uri, id); g_free (uri); if (nemo_window_slot_content_view_matches_iid (slot, id)) { return; } end_location_change (slot); file = nemo_file_get (slot->location); if (nemo_global_preferences_get_ignore_view_metadata ()) { nemo_window_set_ignore_meta_view_id (nemo_window_slot_get_window (slot), id); } else { nemo_file_set_metadata (file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL, id); } nemo_file_unref (file); nemo_window_slot_set_allow_stop (slot, TRUE); if (nemo_view_get_selection_count (slot->content_view) == 0) { /* If there is no selection, queue a scroll to the same icon that * is currently visible */ slot->pending_scroll_to = nemo_view_get_first_visible_file (slot->content_view); } slot->location_change_type = NEMO_LOCATION_CHANGE_RELOAD; create_content_view (slot, id); } void nemo_window_manage_views_close_slot (NemoWindowSlot *slot) { if (slot->content_view != NULL) { nemo_window_disconnect_content_view (nemo_window_slot_get_window (slot), slot->content_view); } free_location_change (slot); cancel_viewed_file_changed_callback (slot); } void nemo_window_back_or_forward (NemoWindow *window, gboolean back, guint distance, NemoWindowOpenFlags flags) { NemoWindowSlot *slot; GList *list; GFile *location; guint len; NemoBookmark *bookmark; GFile *old_location; slot = nemo_window_get_active_slot (window); list = back ? slot->back_list : slot->forward_list; len = (guint) g_list_length (list); /* If we can't move in the direction at all, just return. */ if (len == 0) return; /* If the distance to move is off the end of the list, go to the end of the list. */ if (distance >= len) distance = len - 1; bookmark = g_list_nth_data (list, distance); location = nemo_bookmark_get_location (bookmark); if (flags != 0) { nemo_window_slot_open_location (slot, location, flags); } else { char *scroll_pos; old_location = nemo_window_slot_get_location (slot); scroll_pos = nemo_bookmark_get_scroll_pos (bookmark); begin_location_change (slot, location, old_location, NULL, back ? NEMO_LOCATION_CHANGE_BACK : NEMO_LOCATION_CHANGE_FORWARD, distance, scroll_pos, FALSE, NULL, NULL); g_clear_object (&old_location); g_free (scroll_pos); } g_object_unref (location); } /* reload the contents of the window */ void nemo_window_slot_force_reload (NemoWindowSlot *slot) { GFile *location; char *current_pos; GList *selection; g_assert (NEMO_IS_WINDOW_SLOT (slot)); if (slot->location == NULL) { return; } /* peek_slot_field (window, location) can be free'd during the processing * of begin_location_change, so make a copy */ location = g_object_ref (slot->location); current_pos = NULL; selection = NULL; if (slot->content_view != NULL) { current_pos = nemo_view_get_first_visible_file (slot->content_view); selection = nemo_view_get_selection (slot->content_view); } begin_location_change (slot, location, location, selection, NEMO_LOCATION_CHANGE_RELOAD, 0, current_pos, FALSE, NULL, NULL); g_free (current_pos); g_object_unref (location); g_list_free_full (selection, g_object_unref); } static void clear_thumbnails_for_view (NemoView *view) { NemoDirectory *directory; GList *file_list, *l; directory = nemo_view_get_model (view); file_list = nemo_directory_get_file_list (directory); for (l = file_list; l != NULL; l = l->next) { NemoFile *file = NEMO_FILE (l->data); nemo_file_delete_thumbnail (file); } nemo_file_list_free (file_list); nemo_icon_info_clear_caches (); } void nemo_window_slot_queue_reload (NemoWindowSlot *slot, gboolean clear_thumbs) { g_assert (NEMO_IS_WINDOW_SLOT (slot)); if (slot->location == NULL) { return; } if (slot->pending_location != NULL || slot->content_view == NULL || nemo_view_get_loading (slot->content_view)) { /* there is a reload in flight */ slot->needs_reload = TRUE; return; } if (clear_thumbs) { clear_thumbnails_for_view (slot->content_view); } nemo_window_slot_force_reload (slot); } void nemo_window_slot_check_bad_cache_bar (NemoWindowSlot *slot) { int show_image_thumbs; if (NEMO_IS_DESKTOP_WINDOW (nemo_window_slot_get_window (slot))) return; show_image_thumbs = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS); if (show_image_thumbs != NEMO_SPEED_TRADEOFF_NEVER && nemo_application_get_cache_bad (nemo_application_get_singleton ()) && !nemo_application_get_cache_problem_ignored (nemo_application_get_singleton ())) { if (slot->cache_bar != NULL) { gtk_widget_show (slot->cache_bar); } else { GtkWidget *bad_bar = nemo_thumbnail_problem_bar_new (nemo_window_slot_get_current_view (slot)); if (bad_bar) { gtk_widget_show (bad_bar); nemo_window_slot_add_extra_location_widget (slot, bad_bar); slot->cache_bar = bad_bar; g_object_add_weak_pointer (G_OBJECT (bad_bar), (gpointer) &slot->cache_bar); } } } else { if (slot->cache_bar != NULL) { gtk_widget_hide (slot->cache_bar); } } } nemo-4.4.2/src/nemo-window-manage-views.h000066400000000000000000000024071357442400300202500ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: Darin Adler * */ #ifndef NEMO_WINDOW_MANAGE_VIEWS_H #define NEMO_WINDOW_MANAGE_VIEWS_H #include "nemo-window.h" #include "nemo-window-pane.h" void nemo_window_manage_views_close_slot (NemoWindowSlot *slot); /* NemoWindowInfo implementation: */ void nemo_window_report_location_change (NemoWindow *window); #endif /* NEMO_WINDOW_MANAGE_VIEWS_H */ nemo-4.4.2/src/nemo-window-menus.c000066400000000000000000002030311357442400300170030ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Nemo * * Copyright (C) 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Author: John Sullivan */ /* nemo-window-menus.h - implementation of nemo window menu operations, * split into separate file just for convenience. */ #include #include #include "nemo-window-menus.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-connect-server-dialog.h" #include "nemo-file-management-properties.h" #include "nemo-navigation-action.h" #include "nemo-notebook.h" #include "nemo-window-manage-views.h" #include "nemo-window-bookmarks.h" #include "nemo-window-private.h" #include "nemo-desktop-window.h" #include "nemo-location-bar.h" #include "nemo-icon-view.h" #include "nemo-list-view.h" #include "nemo-toolbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MENU_PATH_EXTENSION_ACTIONS "/MenuBar/File/Extension Actions" #define POPUP_PATH_EXTENSION_ACTIONS "/background/Before Zoom Items/Extension Actions" #define NETWORK_URI "network:" #define COMPUTER_URI "computer:" static void set_content_view_type(NemoWindow *window, const gchar *view_id); enum { NULL_VIEW, ICON_VIEW, LIST_VIEW, COMPACT_VIEW, SIDEBAR_PLACES, SIDEBAR_TREE }; static void action_close_window_slot_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); nemo_window_pane_close_slot (slot->pane, slot); } static void action_connect_to_server_callback (GtkAction *action, gpointer user_data) { NemoWindow *window = NEMO_WINDOW (user_data); GtkWidget *dialog; dialog = nemo_connect_server_dialog_new (window); gtk_widget_show (dialog); } static void action_stop_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); nemo_window_slot_stop_loading (slot); } #ifdef TEXT_CHANGE_UNDO static void action_undo_callback (GtkAction *action, gpointer user_data) { NemoApplication *app; app = nemo_application_get_singleton (); nemo_undo_manager_undo (app->undo_manager); } #endif static void action_home_callback (GtkAction *action, gpointer user_data) { if (!NEMO_IS_DESKTOP_WINDOW (user_data)) { NemoWindow *window; NemoWindowSlot *slot; window = NEMO_WINDOW (user_data); g_printerr ("what\n"); slot = nemo_window_get_active_slot (window); nemo_window_slot_go_home (slot, nemo_event_get_window_open_flags ()); } } static void action_go_to_computer_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; GFile *computer; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); computer = g_file_new_for_uri (COMPUTER_URI); nemo_window_slot_open_location (slot, computer, nemo_event_get_window_open_flags ()); g_object_unref (computer); } static void action_go_to_network_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; GFile *network; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); network = g_file_new_for_uri (NETWORK_URI); nemo_window_slot_open_location (slot, network, nemo_event_get_window_open_flags ()); g_object_unref (network); } static void action_go_to_templates_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; char *path; GFile *location; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); path = nemo_get_templates_directory (); location = g_file_new_for_path (path); g_free (path); nemo_window_slot_open_location (slot, location, nemo_event_get_window_open_flags ()); g_object_unref (location); } static void action_go_to_trash_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowSlot *slot; GFile *trash; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); trash = g_file_new_for_uri ("trash:///"); nemo_window_slot_open_location (slot, trash, nemo_event_get_window_open_flags ()); g_object_unref (trash); } static void action_reload_callback (GtkAction *action, gpointer user_data) { NemoWindowSlot *slot; slot = nemo_window_get_active_slot (NEMO_WINDOW (user_data)); nemo_window_slot_queue_reload (slot, TRUE); } static NemoView * get_current_view (NemoWindow *window) { NemoWindowSlot *slot; NemoView *view; slot = nemo_window_get_active_slot (window); view = nemo_window_slot_get_current_view (slot); return view; } static void action_zoom_in_callback (GtkAction *action, gpointer user_data) { if (!NEMO_IS_DESKTOP_WINDOW (user_data)) { nemo_view_bump_zoom_level (get_current_view (user_data), 1); } } static void action_zoom_out_callback (GtkAction *action, gpointer user_data) { if (!NEMO_IS_DESKTOP_WINDOW (user_data)) { nemo_view_bump_zoom_level (get_current_view (user_data), -1); } } static void action_zoom_normal_callback (GtkAction *action, gpointer user_data) { if (!NEMO_IS_DESKTOP_WINDOW (user_data)) { nemo_view_restore_default_zoom_level (get_current_view (user_data)); } } static void action_show_hidden_files_callback (GtkAction *action, gpointer callback_data) { NemoWindow *window; NemoWindowShowHiddenFilesMode mode; window = NEMO_WINDOW (callback_data); if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { mode = NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE; } else { mode = NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE; } nemo_window_set_hidden_files_mode (window, mode); } static void action_preferences_callback (GtkAction *action, gpointer user_data) { GtkWindow *window; window = GTK_WINDOW (user_data); nemo_file_management_properties_dialog_show (window, NULL); } static void action_plugins_callback (GtkAction *action, gpointer user_data) { GtkWindow *window; window = GTK_WINDOW (user_data); nemo_file_management_properties_dialog_show (window, "plugins"); } static void action_about_nemo_callback (GtkAction *action, gpointer user_data) { const gchar *license[] = { N_("Nemo 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."), N_("Nemo 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."), N_("You should have received a copy of the GNU General Public License " "along with Nemo; if not, write to the Free Software Foundation, Inc., " "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA") }; gchar *license_trans; GDateTime *date; license_trans = g_strjoin ("\n\n", _(license[0]), _(license[1]), _(license[2]), NULL); date = g_date_time_new_now_local (); gtk_show_about_dialog (GTK_WINDOW (user_data), "program-name", _("Nemo"), "version", VERSION, "comments", _("Nemo lets you organize " "files and folders, both on " "your computer and online."), "license", license_trans, "wrap-license", TRUE, "logo-icon-name", "folder", NULL); g_free (license_trans); g_date_time_unref (date); } static void action_up_callback (GtkAction *action, gpointer user_data) { NemoWindow *window = user_data; NemoWindowSlot *slot; slot = nemo_window_get_active_slot (window); nemo_window_slot_go_up (slot, nemo_event_get_window_open_flags ()); } static void action_nemo_manual_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; GError *error; GtkWidget *dialog; const char* helpuri; const char* name = gtk_action_get_name (action); error = NULL; window = NEMO_WINDOW (user_data); if (g_str_equal (name, "NemoHelpSearch")) { helpuri = "help:gnome-help/files-search"; } else if (g_str_equal (name,"NemoHelpSort")) { helpuri = "help:gnome-help/files-sort"; } else if (g_str_equal (name, "NemoHelpLost")) { helpuri = "help:gnome-help/files-lost"; } else if (g_str_equal (name, "NemoHelpShare")) { helpuri = "help:gnome-help/files-share"; } else { helpuri = "help:gnome-help/files"; } if (NEMO_IS_DESKTOP_WINDOW (window)) { nemo_launch_application_from_command (gtk_window_get_screen (GTK_WINDOW (window)), "gnome-help", FALSE, NULL); } else { gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (window)), helpuri, gtk_get_current_event_time (), &error); } if (error) { dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("There was an error displaying help: \n%s"), error->message); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_widget_show (dialog); g_error_free (error); } } static void action_show_shortcuts_window (GtkAction *action, gpointer user_data) { NemoWindow *window; static GtkWidget *shortcuts_window; window = NEMO_WINDOW (user_data); if (shortcuts_window == NULL) { GtkBuilder *builder; builder = gtk_builder_new_from_resource ("/org/nemo/nemo-shortcuts.ui"); shortcuts_window = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_shortcuts")); gtk_window_set_position (GTK_WINDOW (shortcuts_window), GTK_WIN_POS_CENTER); g_signal_connect (shortcuts_window, "destroy", G_CALLBACK (gtk_widget_destroyed), &shortcuts_window); g_object_unref (builder); } if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (shortcuts_window))) { gtk_window_set_transient_for (GTK_WINDOW (shortcuts_window), GTK_WINDOW (window)); } gtk_widget_show_all (shortcuts_window); gtk_window_present (GTK_WINDOW (shortcuts_window)); } static void menu_item_select_cb (GtkMenuItem *proxy, NemoWindow *window) { GtkAction *action; char *message; action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy)); g_return_if_fail (action != NULL); g_object_get (G_OBJECT (action), "tooltip", &message, NULL); if (message) { gtk_statusbar_push (GTK_STATUSBAR (window->details->statusbar), window->details->help_message_cid, message); g_free (message); } } static void menu_item_deselect_cb (GtkMenuItem *proxy, NemoWindow *window) { gtk_statusbar_pop (GTK_STATUSBAR (window->details->statusbar), window->details->help_message_cid); } static void disconnect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, NemoWindow *window) { if (GTK_IS_MENU_ITEM (proxy)) { g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (menu_item_select_cb), window); g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (menu_item_deselect_cb), window); } } static void trash_state_changed_cb (NemoTrashMonitor *monitor, gboolean state, NemoWindow *window) { GtkActionGroup *action_group; GtkAction *action; gchar *icon_name; action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, "Go to Trash"); icon_name = nemo_trash_monitor_get_symbolic_icon_name (); if (icon_name) { g_object_set (action, "icon-name", icon_name, NULL); g_clear_pointer (&icon_name, g_free); } } static void nemo_window_initialize_trash_icon_monitor (NemoWindow *window) { NemoTrashMonitor *monitor; monitor = nemo_trash_monitor_get (); trash_state_changed_cb (monitor, TRUE, window); g_signal_connect (monitor, "trash_state_changed", G_CALLBACK (trash_state_changed_cb), window); } #define MENU_ITEM_MAX_WIDTH_CHARS 32 static void action_close_all_windows_callback (GtkAction *action, gpointer user_data) { nemo_application_close_all_windows (nemo_application_get_singleton ()); } static void action_back_callback (GtkAction *action, gpointer user_data) { nemo_window_back_or_forward (NEMO_WINDOW (user_data), TRUE, 0, nemo_event_get_window_open_flags ()); } static void action_forward_callback (GtkAction *action, gpointer user_data) { nemo_window_back_or_forward (NEMO_WINDOW (user_data), FALSE, 0, nemo_event_get_window_open_flags ()); } static void action_split_view_switch_next_pane_callback(GtkAction *action, gpointer user_data) { nemo_window_pane_grab_focus (nemo_window_get_next_pane (NEMO_WINDOW (user_data))); } static void action_split_view_same_location_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; NemoWindowPane *next_pane; GFile *location; window = NEMO_WINDOW (user_data); next_pane = nemo_window_get_next_pane (window); if (!next_pane) { return; } location = nemo_window_slot_get_location (next_pane->active_slot); if (location) { nemo_window_slot_open_location (nemo_window_get_active_slot (window), location, 0); g_object_unref (location); } } static void action_show_hide_sidebar_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; window = NEMO_WINDOW (user_data); if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { nemo_window_show_sidebar (window); } else { nemo_window_hide_sidebar (window); } } static void action_split_view_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; gboolean is_active; if (NEMO_IS_DESKTOP_WINDOW (user_data)) { return; } window = NEMO_WINDOW (user_data); is_active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); if (is_active != nemo_window_split_view_showing (window)) { NemoWindowSlot *slot; if (is_active) { nemo_window_split_view_on (window); } else { nemo_window_split_view_off (window); } slot = nemo_window_get_active_slot (window); if (slot != NULL) { nemo_view_update_menus (slot->content_view); } } } static void nemo_window_update_split_view_actions_sensitivity (NemoWindow *window) { GtkActionGroup *action_group; GtkAction *action; gboolean have_multiple_panes; gboolean next_pane_is_in_same_location; GFile *active_pane_location; GFile *next_pane_location; NemoWindowPane *next_pane; NemoWindowSlot *active_slot; active_slot = nemo_window_get_active_slot (window); action_group = nemo_window_get_main_action_group (window); /* collect information */ have_multiple_panes = nemo_window_split_view_showing (window); if (active_slot != NULL) { active_pane_location = nemo_window_slot_get_location (active_slot); } else { active_pane_location = NULL; } next_pane = nemo_window_get_next_pane (window); if (next_pane && next_pane->active_slot) { next_pane_location = nemo_window_slot_get_location (next_pane->active_slot); next_pane_is_in_same_location = (active_pane_location && next_pane_location && g_file_equal (active_pane_location, next_pane_location)); } else { next_pane_location = NULL; next_pane_is_in_same_location = FALSE; } /* switch to next pane */ action = gtk_action_group_get_action (action_group, "SplitViewNextPane"); gtk_action_set_sensitive (action, have_multiple_panes); /* same location */ action = gtk_action_group_get_action (action_group, "SplitViewSameLocation"); gtk_action_set_sensitive (action, have_multiple_panes && !next_pane_is_in_same_location); /* clean up */ g_clear_object (&active_pane_location); g_clear_object (&next_pane_location); } static void sidebar_radio_entry_changed_cb (GtkAction *action, GtkRadioAction *current, gpointer user_data) { gint current_value; NemoWindow *window = NEMO_WINDOW (user_data); current_value = gtk_radio_action_get_current_value (current); switch (current_value) { case SIDEBAR_PLACES: nemo_window_set_sidebar_id (window, NEMO_WINDOW_SIDEBAR_PLACES); break; case SIDEBAR_TREE: nemo_window_set_sidebar_id (window, NEMO_WINDOW_SIDEBAR_TREE); break; default: ; break; } } static void view_radio_entry_changed_cb (GtkAction *action, GtkRadioAction *current, gpointer user_data) { gint current_value; NemoWindow *window = NEMO_WINDOW (user_data); if (NEMO_IS_DESKTOP_WINDOW (window)) { return; } current_value = gtk_radio_action_get_current_value (current); switch (current_value) { case ICON_VIEW: set_content_view_type (window, NEMO_ICON_VIEW_ID); break; case LIST_VIEW: set_content_view_type (window, NEMO_LIST_VIEW_ID); break; case COMPACT_VIEW: set_content_view_type (window, FM_COMPACT_VIEW_ID); break; default: ; break; } } /* TODO: bind all of this with g_settings_bind and GBinding */ static guint sidebar_id_to_value (const gchar *sidebar_id) { guint retval = SIDEBAR_PLACES; if (g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0) retval = SIDEBAR_TREE; return retval; } static void update_side_bar_radio_buttons (NemoWindow *window) { GtkActionGroup *action_group; GtkAction *action; guint current_value; action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, "Sidebar Places"); current_value = sidebar_id_to_value (nemo_window_get_sidebar_id (window)); g_signal_handlers_block_by_func (action, sidebar_radio_entry_changed_cb, window); gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), current_value); g_signal_handlers_unblock_by_func (action, sidebar_radio_entry_changed_cb, window); } void nemo_window_update_show_hide_menu_items (NemoWindow *window) { GtkActionGroup *action_group; GtkAction *action; action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDE_EXTRA_PANE); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), nemo_window_split_view_showing (window)); nemo_window_update_split_view_actions_sensitivity (window); update_side_bar_radio_buttons (window); } static void action_add_bookmark_callback (GtkAction *action, gpointer user_data) { nemo_window_add_bookmark_for_current_location (NEMO_WINDOW (user_data)); } static void action_edit_bookmarks_callback (GtkAction *action, gpointer user_data) { nemo_window_edit_bookmarks (NEMO_WINDOW (user_data)); } static void connect_proxy_cb (GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NemoWindow *window) { GtkWidget *label; if (!GTK_IS_MENU_ITEM (proxy)) return; label = gtk_bin_get_child (GTK_BIN (proxy)); if (GTK_IS_LABEL (label)) { gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); gtk_label_set_max_width_chars (GTK_LABEL (label), MENU_ITEM_MAX_WIDTH_CHARS); } g_signal_connect (proxy, "select", G_CALLBACK (menu_item_select_cb), window); g_signal_connect (proxy, "deselect", G_CALLBACK (menu_item_deselect_cb), window); } static void action_new_window_callback (GtkAction *action, gpointer user_data) { NemoWindow *current_window; current_window = NEMO_WINDOW (user_data); if (NEMO_IS_DESKTOP_WINDOW (current_window)) { NemoFile *file; NemoView *view; gchar *desktop_uri; desktop_uri = nemo_get_desktop_directory_uri (); file = nemo_file_get_existing_by_uri (desktop_uri); view = nemo_window_slot_get_current_view (nemo_window_get_active_slot (current_window)); nemo_view_activate_file (view, file, 0); g_free (desktop_uri); nemo_file_unref (file); } else { NemoApplication *application; NemoWindow *new_window; gchar *uri; GFile *loc; uri = nemo_window_slot_get_current_uri (nemo_window_get_active_slot (current_window)); loc = g_file_new_for_uri (uri); application = nemo_application_get_singleton (); new_window = nemo_application_create_window (application, gtk_window_get_screen (GTK_WINDOW (current_window))); nemo_window_slot_open_location (nemo_window_get_active_slot (new_window), loc, 0); g_object_unref (loc); g_free (uri); } } static void action_new_tab_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; window = NEMO_WINDOW (user_data); nemo_window_new_tab (window); } void action_toggle_location_entry_callback (GtkToggleAction *action, gpointer user_data); static void toggle_location_entry_setting (NemoWindow *window, NemoWindowPane *pane, gboolean from_accel_or_menu) { gboolean current_view, temp_toolbar_visible, default_toolbar_visible, grab_focus_only, already_has_focus; GtkToggleAction *button_action; GtkActionGroup *action_group; current_view = nemo_toolbar_get_show_location_entry (NEMO_TOOLBAR (pane->tool_bar)); temp_toolbar_visible = pane->temporary_navigation_bar; default_toolbar_visible = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR); already_has_focus = nemo_location_bar_has_focus (NEMO_LOCATION_BAR (pane->location_bar)); grab_focus_only = from_accel_or_menu && (pane->last_focus_widget == NULL || !already_has_focus) && current_view; if ((temp_toolbar_visible || default_toolbar_visible) && !grab_focus_only) { nemo_toolbar_set_show_location_entry (NEMO_TOOLBAR (pane->tool_bar), !current_view); g_settings_set_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_LOCATION_ENTRY, !current_view); action_group = pane->toolbar_action_group; button_action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (action_group, NEMO_ACTION_TOGGLE_LOCATION)); g_signal_handlers_block_by_func (button_action, action_toggle_location_entry_callback, window); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (button_action), !current_view); g_signal_handlers_unblock_by_func (button_action, action_toggle_location_entry_callback, window); } else { nemo_window_pane_ensure_location_bar (pane); } } void action_toggle_location_entry_callback (GtkToggleAction *action, gpointer user_data) { NemoWindow *window = user_data; NemoWindowPane *pane; pane = nemo_window_get_active_pane (window); toggle_location_entry_setting(window, pane, FALSE); } void nemo_window_show_location_entry (NemoWindow *window) { NemoWindowPane *pane; pane = nemo_window_get_active_pane (window); toggle_location_entry_setting(window, pane, TRUE); } static void action_menu_edit_location_callback (GtkAction *action, gpointer user_data) { NemoWindow *window = user_data; NemoWindowPane *pane; pane = nemo_window_get_active_pane (window); toggle_location_entry_setting(window, pane, TRUE); } static void action_show_thumbnails_callback (GtkAction * action, gpointer user_data) { NemoWindowSlot *slot; NemoWindowPane *pane; NemoWindow *window; gboolean value; window = NEMO_WINDOW (user_data); slot = nemo_window_get_active_slot (window); pane = nemo_window_get_active_pane(window); value = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); nemo_window_slot_set_show_thumbnails(slot, value); toolbar_set_show_thumbnails_button (value, pane); menu_set_show_thumbnails_action(value, window); } static void set_content_view_type(NemoWindow *window, const gchar *view_id) { NemoWindowSlot *slot; slot = nemo_window_get_active_slot (window); nemo_window_slot_set_content_view (slot, view_id); } static void action_icon_view_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; window = NEMO_WINDOW (user_data); set_content_view_type (window, NEMO_ICON_VIEW_ID); toolbar_set_view_button (ICON_VIEW, nemo_window_get_active_pane(window)); } static void action_list_view_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; window = NEMO_WINDOW (user_data); set_content_view_type (window, NEMO_LIST_VIEW_ID); toolbar_set_view_button (LIST_VIEW, nemo_window_get_active_pane(window)); } static void action_compact_view_callback (GtkAction *action, gpointer user_data) { NemoWindow *window; window = NEMO_WINDOW (user_data); set_content_view_type (window, FM_COMPACT_VIEW_ID); toolbar_set_view_button (COMPACT_VIEW, nemo_window_get_active_pane(window)); } guint action_for_view_id (const char *view_id) { if (g_strcmp0(view_id, NEMO_ICON_VIEW_ID) == 0) { return ICON_VIEW; } else if (g_strcmp0(view_id, NEMO_LIST_VIEW_ID) == 0) { return LIST_VIEW; } else if (g_strcmp0(view_id, FM_COMPACT_VIEW_ID) == 0) { return COMPACT_VIEW; } else { return NULL_VIEW; } } void toolbar_set_view_button (guint action_id, NemoWindowPane *pane) { GtkAction *action, *action1, *action2; GtkActionGroup *action_group; if (action_id == NULL_VIEW) { return; } action_group = nemo_window_pane_get_toolbar_action_group (pane); action = gtk_action_group_get_action(action_group, NEMO_ACTION_ICON_VIEW); action1 = gtk_action_group_get_action(action_group, NEMO_ACTION_LIST_VIEW); action2 = gtk_action_group_get_action(action_group, NEMO_ACTION_COMPACT_VIEW); g_signal_handlers_block_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_icon_view_callback, NULL); g_signal_handlers_block_matched (action1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_list_view_callback, NULL); g_signal_handlers_block_matched (action2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_compact_view_callback, NULL); if (action_id != ICON_VIEW) { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE); } else { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE); } if (action_id != LIST_VIEW) { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action1), FALSE); } else { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action1), TRUE); } if (action_id != COMPACT_VIEW) { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action2), FALSE); } else { gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action2), TRUE); } g_signal_handlers_unblock_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_icon_view_callback, NULL); g_signal_handlers_unblock_matched (action1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_list_view_callback, NULL); g_signal_handlers_unblock_matched (action2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_compact_view_callback, NULL); } void toolbar_set_show_thumbnails_button (gboolean value, NemoWindowPane *pane) { GtkAction *action; GtkActionGroup *action_group; action_group = nemo_window_pane_get_toolbar_action_group (pane); action = gtk_action_group_get_action(action_group, NEMO_ACTION_SHOW_THUMBNAILS); g_signal_handlers_block_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_show_thumbnails_callback, NULL); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), value); g_signal_handlers_unblock_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_show_thumbnails_callback, NULL); } void menu_set_show_thumbnails_action (gboolean value, NemoWindow *window) { GtkAction *action; action = gtk_action_group_get_action (window->details->main_action_group, NEMO_ACTION_SHOW_THUMBNAILS); g_signal_handlers_block_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_show_thumbnails_callback, NULL); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), value); g_signal_handlers_unblock_matched (action, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, action_show_thumbnails_callback, NULL); } void menu_set_view_selection (guint action_id, NemoWindow *window) { GtkAction *action; if (action_id == NULL_VIEW) { return; } g_signal_handlers_block_by_func (window->details->main_action_group, view_radio_entry_changed_cb, window); action = gtk_action_group_get_action (window->details->main_action_group, NEMO_ACTION_ICON_VIEW); gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), action_id); g_signal_handlers_unblock_by_func (window->details->main_action_group, view_radio_entry_changed_cb, window); } static void action_tabs_previous_callback (GtkAction *action, gpointer user_data) { NemoWindowPane *pane; NemoWindow *window = user_data; pane = nemo_window_get_active_pane (window); nemo_notebook_set_current_page_relative (NEMO_NOTEBOOK (pane->notebook), -1); } static void action_tabs_next_callback (GtkAction *action, gpointer user_data) { NemoWindowPane *pane; NemoWindow *window = user_data; pane = nemo_window_get_active_pane (window); nemo_notebook_set_current_page_relative (NEMO_NOTEBOOK (pane->notebook), 1); } static void reorder_tab (NemoWindowPane *pane, int offset) { int page_num; g_return_if_fail (pane != NULL); page_num = gtk_notebook_get_current_page ( GTK_NOTEBOOK (pane->notebook)); g_return_if_fail (page_num != -1); nemo_notebook_reorder_child_relative ( NEMO_NOTEBOOK (pane->notebook), page_num, offset); } static void action_tabs_move_left_callback (GtkAction *action, gpointer user_data) { NemoWindow *window = user_data; reorder_tab (nemo_window_get_active_pane (window), -1); } static void action_tabs_move_right_callback (GtkAction *action, gpointer user_data) { NemoWindow *window = user_data; reorder_tab (nemo_window_get_active_pane (window), 1); } static void action_tab_change_action_activate_callback (GtkAction *action, gpointer user_data) { NemoWindowPane *pane; NemoWindow *window = user_data; GtkNotebook *notebook; int num; pane = nemo_window_get_active_pane (window); notebook = GTK_NOTEBOOK (pane->notebook); num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), "num")); if (num < gtk_notebook_get_n_pages (notebook)) { gtk_notebook_set_current_page (notebook, num); } } static void action_new_folder_callback (GtkAction *action, gpointer user_data) { g_assert (NEMO_IS_WINDOW (user_data)); NemoWindow *window = user_data; NemoView *view = get_current_view (window); nemo_view_new_folder (view); } static void open_in_terminal_other (const gchar *path) { gchar *argv[2]; argv[0] = g_settings_get_string (gnome_terminal_preferences, GNOME_DESKTOP_TERMINAL_EXEC); argv[1] = NULL; g_spawn_async(path, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); } static void action_open_terminal_callback(GtkAction *action, gpointer callback_data) { NemoWindow *window; NemoView *view; window = NEMO_WINDOW(callback_data); view = get_current_view (window); gchar *path; gchar *uri = nemo_view_get_uri (view); GFile *gfile = g_file_new_for_uri (uri); path = g_file_get_path (gfile); open_in_terminal_other (path); g_free (uri); g_free (path); g_object_unref (gfile); } static const GtkActionEntry main_entries[] = { /* name, stock id, label */ { "File", NULL, N_("_File") }, /* name, stock id, label */ { "Edit", NULL, N_("_Edit") }, /* name, stock id, label */ { "View", NULL, N_("_View") }, /* name, stock id, label */ { "Help", NULL, N_("_Help") }, /* name, stock id */ { "Close", "window-close-symbolic", /* label, accelerator */ N_("_Close"), "W", /* tooltip */ N_("Close this folder"), G_CALLBACK (action_close_window_slot_callback) }, { "Preferences", "preferences-other-symbolic", N_("Prefere_nces"), NULL, N_("Edit Nemo preferences"), G_CALLBACK (action_preferences_callback) }, { NEMO_ACTION_PLUGIN_MANAGER, NULL, N_("Plugins"), "p", N_("Manage extensions, actions and scripts"), G_CALLBACK (action_plugins_callback) }, #ifdef TEXT_CHANGE_UNDO /* name, stock id, label */ { "Undo", NULL, N_("_Undo"), "Z", N_("Undo the last text change"), G_CALLBACK (action_undo_callback) }, #endif /* name, stock id, label */ { "Up", "go-up-symbolic", N_("Open _Parent"), "Up", N_("Open the parent folder"), G_CALLBACK (action_up_callback) }, /* name, stock id, label */ { "UpAccel", NULL, "UpAccel", "", NULL, G_CALLBACK (action_up_callback) }, /* name, stock id */ { "Stop", "process-stop-symbolic", /* label, accelerator */ N_("_Stop"), NULL, /* tooltip */ N_("Stop loading the current location"), G_CALLBACK (action_stop_callback) }, /* name, stock id */ { "Reload", "view-refresh-symbolic", /* label, accelerator */ N_("_Reload"), "R", /* tooltip */ N_("Reload the current location"), G_CALLBACK (action_reload_callback) }, /* name, stock id */ { "NemoHelp", "help-contents-symbolic", /* label, accelerator */ N_("_All Topics"), "F1", /* tooltip */ N_("Display Nemo help"), G_CALLBACK (action_nemo_manual_callback) }, { "NemoShortcuts", "preferences-desktop-keyboard-shortcuts-symbolic", N_("_Keyboard Shortcuts"), "F1", N_("Display keyboard shortcuts"), G_CALLBACK (action_show_shortcuts_window) }, /** name, stock id { "NemoHelpSearch", NULL, label, accelerator N_("Search for files"), NULL, tooltip N_("Locate files based on file name and type. Save your searches for later use."), G_CALLBACK (action_nemo_manual_callback) }, name, stock id { "NemoHelpSort", NULL, label, accelerator N_("Sort files and folders"), NULL, tooltip N_("Arrange files by name, size, type, or when they were changed."), G_CALLBACK (action_nemo_manual_callback) }, name, stock id { "NemoHelpLost", NULL, label, accelerator N_("Find a lost file"), NULL, tooltip N_("Follow these tips if you can't find a file you created or downloaded."), G_CALLBACK (action_nemo_manual_callback) }, name, stock id { "NemoHelpShare", NULL, label, accelerator N_("Share and transfer files"), NULL, tooltip N_("Easily transfer files to your contacts and devices from the file manager."), G_CALLBACK (action_nemo_manual_callback) }, **/ /* name, stock id */ { "About Nemo", "help-about-symbolic", /* label, accelerator */ N_("_About"), NULL, /* tooltip */ N_("Display credits for the creators of Nemo"), G_CALLBACK (action_about_nemo_callback) }, /* name, stock id */ { "Zoom In", "zoom-in-symbolic", /* label, accelerator */ N_("Zoom _In"), "plus", /* tooltip */ N_("Increase the view size"), G_CALLBACK (action_zoom_in_callback) }, /* name, stock id */ { "ZoomInAccel", NULL, /* label, accelerator */ "ZoomInAccel", "equal", /* tooltip */ NULL, G_CALLBACK (action_zoom_in_callback) }, /* name, stock id */ { "ZoomInAccel2", NULL, /* label, accelerator */ "ZoomInAccel2", "KP_Add", /* tooltip */ NULL, G_CALLBACK (action_zoom_in_callback) }, /* name, stock id */ { "Zoom Out", "zoom-out-symbolic", /* label, accelerator */ N_("Zoom _Out"), "minus", /* tooltip */ N_("Decrease the view size"), G_CALLBACK (action_zoom_out_callback) }, /* name, stock id */ { "ZoomOutAccel", NULL, /* label, accelerator */ "ZoomOutAccel", "KP_Subtract", /* tooltip */ NULL, G_CALLBACK (action_zoom_out_callback) }, /* name, stock id */ { "Zoom Normal", "zoom-original-symbolic", /* label, accelerator */ N_("Normal Si_ze"), "0", /* tooltip */ N_("Use the normal view size"), G_CALLBACK (action_zoom_normal_callback) }, /* name, stock id */ { "Connect to Server", NULL, /* label, accelerator */ N_("Connect to _Server..."), NULL, /* tooltip */ N_("Connect to a remote computer or shared disk"), G_CALLBACK (action_connect_to_server_callback) }, /* name, stock id */ { "Home", NEMO_ICON_SYMBOLIC_HOME, /* label, accelerator */ N_("_Home"), "Home", /* tooltip */ N_("Open your personal folder"), G_CALLBACK (action_home_callback) }, /* name, stock id */ { "Go to Computer", NEMO_ICON_SYMBOLIC_COMPUTER, /* label, accelerator */ N_("_Computer"), NULL, /* tooltip */ N_("Browse all local and remote disks and folders accessible from this computer"), G_CALLBACK (action_go_to_computer_callback) }, /* name, stock id */ { "Go to Network", NEMO_ICON_SYMBOLIC_NETWORK, /* label, accelerator */ N_("_Network"), NULL, /* tooltip */ N_("Browse bookmarked and local network locations"), G_CALLBACK (action_go_to_network_callback) }, /* name, stock id */ { "Go to Templates", NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES, /* label, accelerator */ N_("T_emplates"), NULL, /* tooltip */ N_("Open your personal templates folder"), G_CALLBACK (action_go_to_templates_callback) }, /* name, stock id */ { "Go to Trash", NEMO_ICON_SYMBOLIC_TRASH, /* label, accelerator */ N_("_Trash"), NULL, /* tooltip */ N_("Open your personal trash folder"), G_CALLBACK (action_go_to_trash_callback) }, /* name, stock id, label */ { "Go", NULL, N_("_Go") }, /* name, stock id, label */ { "Bookmarks", NULL, N_("_Bookmarks") }, /* name, stock id, label */ { "Tabs", NULL, N_("_Tabs") }, /* name, stock id, label */ { "New Window", NULL, N_("New _Window"), "N", N_("Open another Nemo window for the displayed location"), G_CALLBACK (action_new_window_callback) }, /* name, stock id, label */ { "New Tab", "tab-new-symbolic", N_("New _Tab"), "T", N_("Open another tab for the displayed location"), G_CALLBACK (action_new_tab_callback) }, /* name, stock id, label */ { "Close All Windows", NULL, N_("Close _All Windows"), "Q", N_("Close all Navigation windows"), G_CALLBACK (action_close_all_windows_callback) }, /* name, stock id, label */ { NEMO_ACTION_BACK, "go-previous-symbolic", N_("_Back"), "Left", N_("Go to the previous visited location"), G_CALLBACK (action_back_callback) }, /* name, stock id, label */ { NEMO_ACTION_FORWARD, "go-next-symbolic", N_("_Forward"), "Right", N_("Go to the next visited location"), G_CALLBACK (action_forward_callback) }, /* name, stock id, label */ { NEMO_ACTION_EDIT_LOCATION, NULL, N_("Toggle _Location Entry"), "L", N_("Switch between location entry and breadcrumbs"), G_CALLBACK (action_menu_edit_location_callback) }, /* name, stock id, label */ { "SplitViewNextPane", NULL, N_("S_witch to Other Pane"), "F6", N_("Move focus to the other pane in a split view window"), G_CALLBACK (action_split_view_switch_next_pane_callback) }, /* name, stock id, label */ { "SplitViewSameLocation", NULL, N_("Sa_me Location as Other Pane"), NULL, N_("Go to the same location as in the extra pane"), G_CALLBACK (action_split_view_same_location_callback) }, /* name, stock id, label */ { "Add Bookmark", "bookmark-new-symbolic", N_("_Add Bookmark"), "d", N_("Add a bookmark for the current location to this menu"), G_CALLBACK (action_add_bookmark_callback) }, /* name, stock id, label */ { "Edit Bookmarks", NULL, N_("_Edit Bookmarks..."), "b", N_("Display a window that allows editing the bookmarks in this menu"), G_CALLBACK (action_edit_bookmarks_callback) }, { "TabsPrevious", NULL, N_("_Previous Tab"), "Page_Up", N_("Activate previous tab"), G_CALLBACK (action_tabs_previous_callback) }, { "TabsNext", NULL, N_("_Next Tab"), "Page_Down", N_("Activate next tab"), G_CALLBACK (action_tabs_next_callback) }, { "TabsMoveLeft", NULL, N_("Move Tab _Left"), "Page_Up", N_("Move current tab to left"), G_CALLBACK (action_tabs_move_left_callback) }, { "TabsMoveRight", NULL, N_("Move Tab _Right"), "Page_Down", N_("Move current tab to right"), G_CALLBACK (action_tabs_move_right_callback) }, { "Sidebar List", NULL, N_("Sidebar") } }; static const GtkToggleActionEntry main_toggle_entries[] = { /* name, stock id */ { "Show Hidden Files", NULL, /* label, accelerator */ N_("Show _Hidden Files"), "H", /* tooltip */ N_("Toggle the display of hidden files in the current window"), G_CALLBACK (action_show_hidden_files_callback), TRUE }, /* name, stock id */ { "Show Hide Toolbar", NULL, /* label, accelerator */ N_("_Main Toolbar"), NULL, /* tooltip */ N_("Change the visibility of this window's main toolbar"), NULL, /* is_active */ TRUE }, /* name, stock id */ { "Show Hide Sidebar", NULL, /* label, accelerator */ N_("_Show Sidebar"), "F9", /* tooltip */ N_("Change the visibility of this window's side pane"), G_CALLBACK (action_show_hide_sidebar_callback), /* is_active */ TRUE }, /* name, stock id */ { "Show Hide Statusbar", NULL, /* label, accelerator */ N_("St_atusbar"), NULL, /* tooltip */ N_("Change the visibility of this window's statusbar"), NULL, /* is_active */ TRUE }, /* name, stock id */ { NEMO_ACTION_SHOW_HIDE_MENUBAR, NULL, /* label, accelerator */ N_("M_enubar"), NULL, /* tooltip */ N_("Change the default visibility of the menubar"), NULL, /* is_active */ TRUE }, /* name, stock id */ { "Search", "edit-find-symbolic", /* label, accelerator */ N_("_Search for Files..."), "f", /* tooltip */ N_("Search documents and folders by name"), NULL, /* is_active */ FALSE }, /* name, stock id */ { NEMO_ACTION_SHOW_HIDE_EXTRA_PANE, NULL, /* label, accelerator */ N_("E_xtra Pane"), "F3", /* tooltip */ N_("Open an extra folder view side-by-side"), G_CALLBACK (action_split_view_callback), /* is_active */ FALSE }, /* name, stock id */ { NEMO_ACTION_SHOW_THUMBNAILS, NULL, /* label, accelerator */ N_("Show _Thumbnails"), NULL, /* tooltip */ N_("Toggle the display of thumbnails in the current directory"), /* callback */ G_CALLBACK (action_show_thumbnails_callback), /* default */ FALSE }, }; static const GtkRadioActionEntry sidebar_radio_entries[] = { { "Sidebar Places", NULL, N_("Places"), NULL, N_("Select Places as the default sidebar"), SIDEBAR_PLACES }, { "Sidebar Tree", NULL, N_("Tree"), NULL, N_("Select Tree as the default sidebar"), SIDEBAR_TREE } }; static const GtkRadioActionEntry view_radio_entries[] = { { "IconView", NULL, N_("Icon View"), "1", N_("Icon View"), ICON_VIEW }, { "ListView", NULL, N_("List View"), "2", N_("List View"), LIST_VIEW }, { "CompactView", NULL, N_("Compact View"), "3", N_("Compact View"), COMPACT_VIEW } }; GtkActionGroup * nemo_window_create_toolbar_action_group (NemoWindow *window) { gboolean show_location_entry_initially; NemoNavigationState *navigation_state; GtkActionGroup *action_group; GtkAction *action; action_group = gtk_action_group_new ("ToolbarActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_BACK, "label", _("_Back"), "icon_name", "go-previous-symbolic", "tooltip", _("Go to the previous visited location"), "arrow-tooltip", _("Back history"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_BACK, "sensitive", FALSE, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_back_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_FORWARD, "label", _("_Forward"), "icon_name", "go-next-symbolic", "tooltip", _("Go to the next visited location"), "arrow-tooltip", _("Forward history"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_FORWARD, "sensitive", FALSE, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_forward_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); /** * Nemo 2.30/2.32 type actions */ action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_UP, "label", _("_Up"), "icon_name", "go-up-symbolic", "tooltip", _("Go to parent folder"), "arrow-tooltip", _("Forward history"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_UP, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_up_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_RELOAD, "label", _("_Reload"), "icon_name", "view-refresh-symbolic", "tooltip", _("Reload the current location"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_RELOAD, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_reload_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_HOME, "label", _("_Home"), "icon_name", "go-home-symbolic", "tooltip", _("Go to home directory"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_HOME, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_home_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); action = g_object_new (NEMO_TYPE_NAVIGATION_ACTION, "name", NEMO_ACTION_COMPUTER, "label", _("_Computer"), "icon_name", "computer-symbolic", "tooltip", _("Go to Computer"), "window", window, "direction", NEMO_NAVIGATION_DIRECTION_COMPUTER, NULL); g_signal_connect (action, "activate", G_CALLBACK (action_go_to_computer_callback), window); gtk_action_group_add_action (action_group, action); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_TOGGLE_LOCATION, _("Location"), _("Toggle Location Entry"), NULL)); gtk_action_group_add_action (action_group, GTK_ACTION (action)); show_location_entry_initially = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_LOCATION_ENTRY); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), show_location_entry_initially); g_signal_connect (action, "activate", G_CALLBACK (action_toggle_location_entry_callback), window); gtk_action_set_icon_name (GTK_ACTION (action), "location-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_action_new (NEMO_ACTION_NEW_FOLDER, _("New folder"), _("Create a new folder"), NULL)); gtk_action_group_add_action (action_group, GTK_ACTION (action)); g_signal_connect (action, "activate", G_CALLBACK (action_new_folder_callback), window); gtk_action_set_icon_name (GTK_ACTION (action), "folder-new-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_action_new (NEMO_ACTION_OPEN_IN_TERMINAL, _("Open in Terminal"), _("Open a terminal in the active folder"), NULL)); gtk_action_group_add_action (action_group, GTK_ACTION (action)); g_signal_connect (action, "activate", G_CALLBACK (action_open_terminal_callback), window); gtk_action_set_icon_name (GTK_ACTION (action), "utilities-terminal-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_ICON_VIEW, _("Icons"), _("Icon View"), NULL)); g_signal_connect (action, "activate", G_CALLBACK (action_icon_view_callback), window); gtk_action_group_add_action (action_group, action); gtk_action_set_icon_name (GTK_ACTION (action), "view-grid-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_LIST_VIEW, _("List"), _("List View"), NULL)); g_signal_connect (action, "activate", G_CALLBACK (action_list_view_callback), window); gtk_action_group_add_action (action_group, action); gtk_action_set_icon_name (GTK_ACTION (action), "view-list-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_COMPACT_VIEW, _("Compact"), _("Compact View"), NULL)); g_signal_connect (action, "activate", G_CALLBACK (action_compact_view_callback), window); gtk_action_group_add_action (action_group, action); gtk_action_set_icon_name (GTK_ACTION (action), "view-compact-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_SEARCH, _("Search"),_("Search documents and folders by name"), NULL)); gtk_action_group_add_action (action_group, action); gtk_action_set_icon_name (GTK_ACTION (action), "edit-find-symbolic"); g_object_unref (action); action = GTK_ACTION (gtk_toggle_action_new (NEMO_ACTION_SHOW_THUMBNAILS, _("Show Thumbnails"), _("Show Thumbnails"), NULL)); g_signal_connect (action, "activate", G_CALLBACK (action_show_thumbnails_callback), window); gtk_action_group_add_action (action_group, action); gtk_action_set_icon_name (GTK_ACTION (action), "xapp-prefs-preview-symbolic"); g_object_unref (action); navigation_state = nemo_window_get_navigation_state (window); nemo_navigation_state_add_group (navigation_state, action_group); return action_group; } static void window_menus_set_bindings (NemoWindow *window) { GtkActionGroup *action_group; GtkAction *action; action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDE_TOOLBAR); g_settings_bind (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR, action, "active", G_SETTINGS_BIND_DEFAULT); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDE_STATUSBAR); g_settings_bind (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_STATUS_BAR, action, "active", G_SETTINGS_BIND_DEFAULT); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDE_MENUBAR); g_settings_bind (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR, action, "active", G_SETTINGS_BIND_DEFAULT); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDE_SIDEBAR); g_object_bind_property (window, "show-sidebar", action, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } void nemo_window_initialize_actions (NemoWindow *window) { GtkActionGroup *action_group; const gchar *nav_state_actions[] = { NEMO_ACTION_BACK, NEMO_ACTION_FORWARD, NEMO_ACTION_UP, NEMO_ACTION_RELOAD, NEMO_ACTION_COMPUTER, NEMO_ACTION_HOME, NEMO_ACTION_EDIT_LOCATION, NEMO_ACTION_TOGGLE_LOCATION, NEMO_ACTION_SEARCH, NULL }; action_group = nemo_window_get_main_action_group (window); window->details->nav_state = nemo_navigation_state_new (action_group, nav_state_actions); window_menus_set_bindings (window); nemo_window_update_show_hide_menu_items (window); g_signal_connect (window, "loading_uri", G_CALLBACK (nemo_window_update_split_view_actions_sensitivity), NULL); } /** * nemo_window_initialize_menus * * Create and install the set of menus for this window. * @window: A recently-created NemoWindow. */ void nemo_window_initialize_menus (NemoWindow *window) { GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkAction *action; gint i; if (window->details->ui_manager == NULL){ window->details->ui_manager = gtk_ui_manager_new (); } ui_manager = window->details->ui_manager; /* shell actions */ action_group = gtk_action_group_new ("ShellActions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); window->details->main_action_group = action_group; gtk_action_group_add_actions (action_group, main_entries, G_N_ELEMENTS (main_entries), window); gtk_action_group_add_toggle_actions (action_group, main_toggle_entries, G_N_ELEMENTS (main_toggle_entries), window); gtk_action_group_add_radio_actions (action_group, sidebar_radio_entries, G_N_ELEMENTS (sidebar_radio_entries), 0, G_CALLBACK (sidebar_radio_entry_changed_cb), window); gtk_action_group_add_radio_actions (action_group, view_radio_entries, G_N_ELEMENTS (view_radio_entries), 0, G_CALLBACK (view_radio_entry_changed_cb), window); action = gtk_action_group_get_action (action_group, NEMO_ACTION_UP); g_object_set (action, "short_label", _("_Up"), NULL); action = gtk_action_group_get_action (action_group, NEMO_ACTION_HOME); g_object_set (action, "short_label", _("_Home"), NULL); action = gtk_action_group_get_action (action_group, NEMO_ACTION_EDIT_LOCATION); g_object_set (action, "short_label", _("_Location"), NULL); action = gtk_action_group_get_action (action_group, NEMO_ACTION_SHOW_HIDDEN_FILES); if (NEMO_IS_DESKTOP_WINDOW (window)) { gtk_action_set_visible (action, FALSE); } else { g_signal_handlers_block_by_func (action, action_show_hidden_files_callback, window); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES)); g_signal_handlers_unblock_by_func (action, action_show_hidden_files_callback, window); } g_signal_connect_object ( NEMO_WINDOW (window), "notify::sidebar-view-id", G_CALLBACK (update_side_bar_radio_buttons), window, 0); /* Alt+N for the first 10 tabs */ for (i = 0; i < 10; ++i) { gchar action_name[80]; gchar accelerator[80]; snprintf(action_name, sizeof (action_name), "Tab%d", i); action = gtk_action_new (action_name, NULL, NULL, NULL); g_object_set_data (G_OBJECT (action), "num", GINT_TO_POINTER (i)); g_signal_connect (action, "activate", G_CALLBACK (action_tab_change_action_activate_callback), window); snprintf(accelerator, sizeof (accelerator), "%d", (i+1)%10); gtk_action_group_add_action_with_accel (action_group, action, accelerator); g_object_unref (action); gtk_ui_manager_add_ui (ui_manager, gtk_ui_manager_new_merge_id (ui_manager), "/", action_name, action_name, GTK_UI_MANAGER_ACCELERATOR, FALSE); } gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui_manager */ gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui_manager)); g_signal_connect (ui_manager, "connect_proxy", G_CALLBACK (connect_proxy_cb), window); g_signal_connect (ui_manager, "disconnect_proxy", G_CALLBACK (disconnect_proxy_cb), window); /* add the UI */ gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-shell-ui.xml", NULL); nemo_window_initialize_trash_icon_monitor (window); } void nemo_window_finalize_menus (NemoWindow *window) { g_signal_handlers_disconnect_by_func (nemo_trash_monitor_get(), trash_state_changed_cb, window); } static GList * get_extension_menus (NemoWindow *window) { NemoWindowSlot *slot; GList *providers; GList *items; GList *l; providers = nemo_module_get_extensions_for_type (NEMO_TYPE_MENU_PROVIDER); items = NULL; slot = nemo_window_get_active_slot (window); for (l = providers; l != NULL; l = l->next) { NemoMenuProvider *provider; GList *file_items; provider = NEMO_MENU_PROVIDER (l->data); file_items = nemo_menu_provider_get_background_items (provider, GTK_WIDGET (window), slot->viewed_file); items = g_list_concat (items, file_items); } nemo_module_extension_list_free (providers); return items; } static void add_extension_menu_items (NemoWindow *window, guint merge_id, GtkActionGroup *action_group, GList *menu_items, const char *subdirectory) { GtkUIManager *ui_manager; GList *l; ui_manager = window->details->ui_manager; for (l = menu_items; l; l = l->next) { NemoMenuItem *item; NemoMenu *menu; GtkAction *action; char *path; item = NEMO_MENU_ITEM (l->data); g_object_get (item, "menu", &menu, NULL); action = nemo_action_from_menu_item (item, GTK_WIDGET (window)); gtk_action_group_add_action_with_accel (action_group, action, NULL); path = g_build_path ("/", POPUP_PATH_EXTENSION_ACTIONS, subdirectory, NULL); gtk_ui_manager_add_ui (ui_manager, merge_id, path, gtk_action_get_name (action), gtk_action_get_name (action), (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE); g_free (path); path = g_build_path ("/", MENU_PATH_EXTENSION_ACTIONS, subdirectory, NULL); gtk_ui_manager_add_ui (ui_manager, merge_id, path, gtk_action_get_name (action), gtk_action_get_name (action), (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE); g_free (path); /* recursively fill the menu */ if (menu != NULL) { char *subdir; GList *children; children = nemo_menu_get_items (menu); subdir = g_build_path ("/", subdirectory, "/", gtk_action_get_name (action), NULL); add_extension_menu_items (window, merge_id, action_group, children, subdir); nemo_menu_item_list_free (children); g_free (subdir); } } } void nemo_window_load_extension_menus (NemoWindow *window) { GtkActionGroup *action_group; GList *items; guint merge_id; if (window->details->extensions_menu_merge_id != 0) { gtk_ui_manager_remove_ui (window->details->ui_manager, window->details->extensions_menu_merge_id); window->details->extensions_menu_merge_id = 0; } if (window->details->extensions_menu_action_group != NULL) { gtk_ui_manager_remove_action_group (window->details->ui_manager, window->details->extensions_menu_action_group); window->details->extensions_menu_action_group = NULL; } merge_id = gtk_ui_manager_new_merge_id (window->details->ui_manager); window->details->extensions_menu_merge_id = merge_id; action_group = gtk_action_group_new ("ExtensionsMenuGroup"); window->details->extensions_menu_action_group = action_group; gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); gtk_ui_manager_insert_action_group (window->details->ui_manager, action_group, 0); g_object_unref (action_group); /* owned by ui manager */ items = get_extension_menus (window); if (items != NULL) { add_extension_menu_items (window, merge_id, action_group, items, ""); g_list_foreach (items, (GFunc) g_object_unref, NULL); g_list_free (items); } } nemo-4.4.2/src/nemo-window-menus.h000066400000000000000000000030511357442400300170100ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-window-pane.h: Nemo window pane Copyright (C) 2008 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Holger Berndt */ #ifndef NEMO_WINDOW_MENUS_H #define NEMO_WINDOW_MENUS_H #include "nemo-window.h" #include "nemo-window-pane.h" #include guint action_for_view_id (const char *view_id ); void toolbar_set_view_button (guint action_id, NemoWindowPane *pane); void toolbar_set_show_thumbnails_button (gboolean value, NemoWindowPane *pane); void menu_set_show_thumbnails_action (gboolean value, NemoWindow *window); void menu_set_view_selection (guint action_id, NemoWindow *window); #endif /* NEMO_WINDOW_PANE_H */ nemo-4.4.2/src/nemo-window-pane.c000066400000000000000000001032611357442400300166030ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * nemo-window-pane.c: Nemo window pane * * Copyright (C) 2008 Free Software Foundation, Inc. * Copyright (C) 2011 Red Hat, 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 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 - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Holger Berndt * Cosimo Cecchi * */ #include "nemo-window-pane.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-location-bar.h" #include "nemo-notebook.h" #include "nemo-pathbar.h" #include "nemo-toolbar.h" #include "nemo-window-manage-views.h" #include "nemo-window-private.h" #include "nemo-window-menus.h" #include "nemo-icon-view.h" #include "nemo-list-view.h" #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_WINDOW #include // For: NEMO_IS_DESKTOP_WINDOW #include "nemo-desktop-window.h" enum { PROP_WINDOW = 1, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoWindowPane, nemo_window_pane, GTK_TYPE_BOX) static gboolean widget_is_in_temporary_bars (GtkWidget *widget, NemoWindowPane *pane) { gboolean res = FALSE; if (gtk_widget_get_ancestor (widget, NEMO_TYPE_LOCATION_BAR) != NULL && pane->temporary_navigation_bar) res = TRUE; return res; } static void unset_focus_widget (NemoWindowPane *pane) { if (pane->last_focus_widget != NULL) { g_object_remove_weak_pointer (G_OBJECT (pane->last_focus_widget), (gpointer *) &pane->last_focus_widget); pane->last_focus_widget = NULL; } } static void remember_focus_widget (NemoWindowPane *pane) { GtkWidget *focus_widget; focus_widget = gtk_window_get_focus (GTK_WINDOW (pane->window)); if (focus_widget != NULL && !widget_is_in_temporary_bars (focus_widget, pane)) { unset_focus_widget (pane); pane->last_focus_widget = focus_widget; g_object_add_weak_pointer (G_OBJECT (focus_widget), (gpointer *) &(pane->last_focus_widget)); } } static void restore_focus_widget (NemoWindowPane *pane) { if (pane->last_focus_widget != NULL) { if (NEMO_IS_VIEW (pane->last_focus_widget)) { nemo_view_grab_focus (NEMO_VIEW (pane->last_focus_widget)); } else { gtk_widget_grab_focus (pane->last_focus_widget); } unset_focus_widget (pane); } } static NemoWindowSlot * get_next_or_previous_slot (NemoWindowPane *pane) { GtkNotebook *gnotebook; gint page_num; GtkWidget *page; g_return_val_if_fail (pane != NULL, NULL); gnotebook = GTK_NOTEBOOK (pane->notebook); page = NULL; /* If we don't have an active slot, return the first page in the * notebook. */ if (!pane->active_slot) { page = gtk_notebook_get_nth_page (gnotebook, 0); } else { /* Otherwise, return the next or previous slot that appears in * the notebook. We don't use pane->slots to select the next * slot as the list does not represent the order in which slots * are actually displayed in the pane. */ page_num = gtk_notebook_page_num ( gnotebook, GTK_WIDGET (pane->active_slot)); if (page_num != -1) { page = gtk_notebook_get_nth_page ( gnotebook, page_num+1); /* Get the previous page if there is no next one. */ if (!page) { page = gtk_notebook_get_nth_page ( gnotebook, page_num-1); } } } if (page) return NEMO_WINDOW_SLOT (page); return NULL; } static int bookmark_list_get_uri_index (GList *list, GFile *location) { NemoBookmark *bookmark; GList *l; GFile *tmp; int i; g_return_val_if_fail (location != NULL, -1); for (i = 0, l = list; l != NULL; i++, l = l->next) { bookmark = NEMO_BOOKMARK (l->data); tmp = nemo_bookmark_get_location (bookmark); if (g_file_equal (location, tmp)) { g_object_unref (tmp); return i; } g_object_unref (tmp); } return -1; } static void nemo_window_pane_hide_temporary_bars (NemoWindowPane *pane) { NemoWindowSlot *slot; NemoDirectory *directory; slot = pane->active_slot; if (pane->temporary_navigation_bar) { directory = nemo_directory_get (slot->location); pane->temporary_navigation_bar = FALSE; /* if we're in a search directory, hide the main bar, and show the search * bar again; otherwise, just hide the whole toolbar. */ if (NEMO_IS_SEARCH_DIRECTORY (directory)) { nemo_toolbar_set_show_main_bar (NEMO_TOOLBAR (pane->tool_bar), FALSE); } else { gtk_widget_hide (pane->tool_bar); } nemo_directory_unref (directory); } } static void location_entry_changed_cb (NemoToolbar *toolbar, gboolean val, gpointer data) { NemoWindowPane *pane = NEMO_WINDOW_PANE (data); nemo_window_pane_ensure_location_bar (pane); } static void navigation_bar_cancel_callback (GtkWidget *widget, NemoWindowPane *pane) { GtkAction *location; location = gtk_action_group_get_action (pane->action_group, NEMO_ACTION_TOGGLE_LOCATION); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (location), FALSE); nemo_window_pane_hide_temporary_bars (pane); restore_focus_widget (pane); } static void navigation_bar_location_changed_callback (GtkWidget *widget, GFile *location, NemoWindowPane *pane) { nemo_window_pane_hide_temporary_bars (pane); restore_focus_widget (pane); nemo_window_slot_open_location (pane->active_slot, location, 0); } static gboolean toolbar_focus_in_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { NemoWindowPane *pane = user_data; nemo_window_set_active_pane (pane->window, pane); return FALSE; } static void path_bar_location_changed_callback (GtkWidget *widget, GFile *location, NemoWindowPane *pane) { NemoWindowSlot *slot; int i; slot = pane->active_slot; nemo_window_set_active_pane (pane->window, pane); /* check whether we already visited the target location */ i = bookmark_list_get_uri_index (slot->back_list, location); if (i >= 0) { nemo_window_back_or_forward (pane->window, TRUE, i, 0); } else { nemo_window_slot_open_location (pane->active_slot, location, 0); } } static gboolean path_bar_button_pressed_callback (GtkWidget *widget, GdkEventButton *event, NemoWindowPane *pane) { NemoWindowSlot *slot; NemoView *view; GFile *location; char *uri; g_object_set_data (G_OBJECT (widget), "handle-button-release", GINT_TO_POINTER (TRUE)); if (event->button == 3) { slot = nemo_window_get_active_slot (pane->window); view = slot->content_view; if (view != NULL) { location = nemo_path_bar_get_path_for_button ( NEMO_PATH_BAR (pane->path_bar), widget); if (location != NULL) { uri = g_file_get_uri (location); nemo_view_pop_up_location_context_menu ( view, event, uri); g_object_unref (location); g_free (uri); return TRUE; } } } if (event->button == 2) return TRUE; return FALSE; } static gboolean path_bar_button_released_callback (GtkWidget *widget, GdkEventButton *event, NemoWindowPane *pane) { NemoWindowSlot *slot; NemoWindowOpenFlags flags; GFile *location; int mask; gboolean handle_button_release; mask = event->state & gtk_accelerator_get_default_mod_mask (); flags = 0; handle_button_release = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "handle-button-release")); if (event->type == GDK_BUTTON_RELEASE && handle_button_release) { location = nemo_path_bar_get_path_for_button (NEMO_PATH_BAR (pane->path_bar), widget); if (event->button == 2 && mask == 0) { flags = NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } else if (event->button == 1 && mask == GDK_CONTROL_MASK) { flags = NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW; } if (flags != 0) { slot = nemo_window_get_active_slot (pane->window); nemo_window_slot_open_location (slot, location, flags); g_object_unref (location); return TRUE; } g_object_unref (location); } return FALSE; } static void path_bar_button_drag_begin_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { g_object_set_data (G_OBJECT (widget), "handle-button-release", GINT_TO_POINTER (FALSE)); } static void notebook_popup_menu_new_tab_cb (GtkMenuItem *menuitem, gpointer user_data) { NemoWindowPane *pane; pane = user_data; nemo_window_new_tab (pane->window); } static void path_bar_path_set_callback (GtkWidget *widget, GFile *location, NemoWindowPane *pane) { GList *children, *l; GtkWidget *child; children = gtk_container_get_children (GTK_CONTAINER (widget)); for (l = children; l != NULL; l = l->next) { child = GTK_WIDGET (l->data); if (!GTK_IS_TOGGLE_BUTTON (child)) { continue; } if (!g_signal_handler_find (child, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, path_bar_button_pressed_callback, pane)) { g_signal_connect (child, "button-press-event", G_CALLBACK (path_bar_button_pressed_callback), pane); g_signal_connect (child, "button-release-event", G_CALLBACK (path_bar_button_released_callback), pane); g_signal_connect (child, "drag-begin", G_CALLBACK (path_bar_button_drag_begin_callback), pane); } } g_list_free (children); } static void reorder_tab (NemoWindowPane *pane, int offset) { int num_target_tab; g_return_if_fail (pane != NULL); num_target_tab = GPOINTER_TO_INT ( g_object_get_data (G_OBJECT (pane), "num_target_tab")); nemo_notebook_reorder_child_relative ( NEMO_NOTEBOOK (pane->notebook), num_target_tab, offset); } static void notebook_popup_menu_move_left_cb (GtkMenuItem *menuitem, gpointer user_data) { reorder_tab (NEMO_WINDOW_PANE (user_data), -1); } static void notebook_popup_menu_move_right_cb (GtkMenuItem *menuitem, gpointer user_data) { reorder_tab (NEMO_WINDOW_PANE (user_data), 1); } /* emitted when the user clicks the "close" button of tabs */ static void notebook_tab_close_requested (NemoNotebook *notebook, NemoWindowSlot *slot, NemoWindowPane *pane) { nemo_window_pane_close_slot (pane, slot); } static void notebook_popup_menu_close_cb (GtkMenuItem *menuitem, gpointer user_data) { NemoWindowPane *pane; NemoNotebook *notebook; int num_target_tab; GtkWidget *page; pane = NEMO_WINDOW_PANE (user_data); g_return_if_fail (pane != NULL); notebook = NEMO_NOTEBOOK (pane->notebook); num_target_tab = GPOINTER_TO_INT ( g_object_get_data (G_OBJECT (pane), "num_target_tab")); page = gtk_notebook_get_nth_page ( GTK_NOTEBOOK (notebook), num_target_tab); notebook_tab_close_requested ( notebook, NEMO_WINDOW_SLOT (page), pane); } static void notebook_popup_menu_show (NemoWindowPane *pane, GdkEventButton *event, int num_target_tab) { GtkWidget *popup; GtkWidget *item; GtkWidget *image; int button, event_time; gboolean can_move_left, can_move_right; NemoNotebook *notebook; notebook = NEMO_NOTEBOOK (pane->notebook); can_move_left = nemo_notebook_can_reorder_child_relative ( notebook, num_target_tab, -1); can_move_right = nemo_notebook_can_reorder_child_relative ( notebook, num_target_tab, 1); popup = gtk_menu_new(); item = gtk_menu_item_new_with_mnemonic (_("_New Tab")); g_signal_connect (item, "activate", G_CALLBACK (notebook_popup_menu_new_tab_cb), pane); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_menu_shell_append (GTK_MENU_SHELL (popup), gtk_separator_menu_item_new ()); /* Store the target tab index in the pane object so we don't have to * wrap user data in a custom struct which may leak if none of the * callbacks which would free it again is invoked. */ g_object_set_data (G_OBJECT (pane), "num_target_tab", GINT_TO_POINTER (num_target_tab)); item = gtk_menu_item_new_with_mnemonic (_("Move Tab _Left")); g_signal_connect (item, "activate", G_CALLBACK (notebook_popup_menu_move_left_cb), pane); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_set_sensitive (item, can_move_left); item = gtk_menu_item_new_with_mnemonic (_("Move Tab _Right")); g_signal_connect (item, "activate", G_CALLBACK (notebook_popup_menu_move_right_cb), pane); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_set_sensitive (item, can_move_right); gtk_menu_shell_append (GTK_MENU_SHELL (popup), gtk_separator_menu_item_new ()); item = gtk_image_menu_item_new_with_mnemonic (_("_Close Tab")); image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); g_signal_connect (item, "activate", G_CALLBACK (notebook_popup_menu_close_cb), pane); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_show_all (popup); if (event) { button = event->button; event_time = event->time; } else { button = 0; event_time = gtk_get_current_event_time (); } /* TODO is this correct? */ gtk_menu_attach_to_widget (GTK_MENU (popup), pane->notebook, NULL); gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, button, event_time); } static gboolean notebook_button_press_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { NemoWindowPane *pane; NemoNotebook *notebook; int tab_clicked; if (event->type != GDK_BUTTON_PRESS) return FALSE; /* Not a button event we actually care about, so just bail */ if (event->button != 1 && event->button != 2 && event->button != 3) return FALSE; pane = NEMO_WINDOW_PANE (user_data); notebook = NEMO_NOTEBOOK (pane->notebook); tab_clicked = nemo_notebook_find_tab_num_at_pos ( notebook, event->x_root, event->y_root); /* Do not change the current page on middle-click events. Close the * clicked tab instead. */ if (event->button == 2) { if (tab_clicked != -1) { GtkWidget *page = gtk_notebook_get_nth_page ( GTK_NOTEBOOK (notebook), tab_clicked); notebook_tab_close_requested ( notebook, NEMO_WINDOW_SLOT (page), pane); } } else { if (event->button == 3) { notebook_popup_menu_show (pane, event, tab_clicked); } else { gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), tab_clicked); } } return FALSE; } static gboolean notebook_popup_menu_cb (GtkWidget *widget, gpointer user_data) { NemoWindowPane *pane; int page_num; pane = NEMO_WINDOW_PANE (user_data); page_num = gtk_notebook_get_current_page ( GTK_NOTEBOOK (pane->notebook)); if (page_num == -1) return FALSE; notebook_popup_menu_show (pane, NULL, page_num); return TRUE; } static gboolean notebook_switch_page_cb (GtkNotebook *notebook, GtkWidget *page, unsigned int page_num, NemoWindowPane *pane) { NemoWindowSlot *slot; GtkWidget *widget; widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (pane->notebook), page_num); g_assert (widget != NULL); /* find slot corresponding to the target page */ slot = NEMO_WINDOW_SLOT (widget); g_assert (slot != NULL); nemo_window_set_active_slot (nemo_window_slot_get_window (slot), slot); return FALSE; } static void notebook_page_removed_cb (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) { NemoWindowPane *pane = user_data; NemoWindowSlot *slot = NEMO_WINDOW_SLOT (page), *next_slot; gboolean dnd_slot; dnd_slot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (slot), "dnd-window-slot")); if (!dnd_slot) { return; } if (pane->active_slot == slot) { next_slot = get_next_or_previous_slot (pane); nemo_window_set_active_slot (pane->window, next_slot); } nemo_window_manage_views_close_slot (slot); pane->slots = g_list_remove (pane->slots, slot); } static void notebook_page_added_cb (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) { NemoWindowPane *pane; NemoWindowSlot *slot; NemoWindowSlot *dummy_slot; gboolean dnd_slot; pane = NEMO_WINDOW_PANE (user_data); slot = NEMO_WINDOW_SLOT (page); //Slot has been dropped onto another pane (new window or tab bar of other window) //So reassociate the pane if needed. if (slot->pane != pane) { slot->pane->slots = g_list_remove (slot->pane->slots, slot); slot->pane = pane; pane->slots = g_list_append (pane->slots, slot); g_signal_emit_by_name (slot, "changed-pane"); nemo_window_set_active_slot (nemo_window_slot_get_window (slot), slot); } dnd_slot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (slot), "dnd-window-slot")); if (!dnd_slot) { //Slot does not come from dnd window creation. return; } g_object_set_data (G_OBJECT (page), "dnd-window-slot", GINT_TO_POINTER (FALSE)); dummy_slot = g_list_nth_data (pane->slots, 0); if (dummy_slot != NULL) { nemo_window_pane_remove_slot_unsafe ( dummy_slot->pane, dummy_slot); } gtk_widget_show (GTK_WIDGET (pane)); gtk_widget_show (GTK_WIDGET (pane->window)); } static GtkNotebook * notebook_create_window_cb (GtkNotebook *notebook, GtkWidget *page, gint x, gint y, gpointer user_data) { NemoApplication *app; NemoWindow *new_window; NemoWindowPane *new_pane; NemoWindowSlot *slot; if (!NEMO_IS_WINDOW_SLOT (page)) { return NULL; } app = NEMO_APPLICATION (g_application_get_default ()); new_window = nemo_application_create_window (app, gtk_widget_get_screen (GTK_WIDGET (notebook))); slot = NEMO_WINDOW_SLOT (page); g_object_set_data (G_OBJECT (slot), "dnd-window-slot", GINT_TO_POINTER (TRUE)); gtk_window_set_position (GTK_WINDOW (new_window), GTK_WIN_POS_MOUSE); new_pane = nemo_window_get_active_pane (new_window); return GTK_NOTEBOOK (new_pane->notebook); } static void action_show_hide_search_callback (GtkAction *action, gpointer user_data) { NemoWindowPane *pane = user_data; NemoWindow *window = pane->window; NemoWindowSlot *slot; slot = pane->active_slot; if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { remember_focus_widget (pane); nemo_window_slot_set_query_editor_visible (slot, TRUE); } else { /* Do nothing if the query editor is not visible to begin with, i.e. if toggle action was due to switching from a search tab */ if (nemo_query_editor_get_active (NEMO_QUERY_EDITOR (slot->query_editor))) { GFile *location = NULL; restore_focus_widget (pane); if (slot->query_editor != NULL) { /* If closing the search bar, restore the original location */ location = g_file_new_for_uri (nemo_query_editor_get_base_uri (slot->query_editor)); /* Last try: use the home directory as the return location */ if (location == NULL) { location = g_file_new_for_path (g_get_home_dir ()); } nemo_window_go_to (window, location); g_object_unref (location); } nemo_window_slot_set_query_editor_visible (slot, FALSE); } } } static void setup_search_action (NemoWindowPane *pane) { GtkActionGroup *group = pane->action_group; GtkAction *action; action = gtk_action_group_get_action (group, NEMO_ACTION_SEARCH); g_signal_connect (action, "activate", G_CALLBACK (action_show_hide_search_callback), pane); } static void toolbar_action_group_activated_callback (GtkActionGroup *action_group, GtkAction *action, gpointer user_data) { NemoWindowPane *pane = user_data; nemo_window_set_active_pane (pane->window, pane); } static void nemo_window_pane_set_property (GObject *object, guint arg_id, const GValue *value, GParamSpec *pspec) { NemoWindowPane *self = NEMO_WINDOW_PANE (object); switch (arg_id) { case PROP_WINDOW: self->window = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec); break; } } static void nemo_window_pane_get_property (GObject *object, guint arg_id, GValue *value, GParamSpec *pspec) { NemoWindowPane *self = NEMO_WINDOW_PANE (object); switch (arg_id) { case PROP_WINDOW: g_value_set_object (value, self->window); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec); break; } } static void nemo_window_pane_dispose (GObject *object) { NemoWindowPane *pane = NEMO_WINDOW_PANE (object); unset_focus_widget (pane); pane->window = NULL; g_clear_object (&pane->action_group); g_assert (pane->slots == NULL); G_OBJECT_CLASS (nemo_window_pane_parent_class)->dispose (object); } static void nemo_window_pane_constructed (GObject *obj) { NemoWindowPane *pane = NEMO_WINDOW_PANE (obj); GtkSizeGroup *header_size_group; NemoWindow *window; GtkActionGroup *action_group; G_OBJECT_CLASS (nemo_window_pane_parent_class)->constructed (obj); window = pane->window; header_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); gtk_size_group_set_ignore_hidden (header_size_group, FALSE); /* build the toolbar */ action_group = nemo_window_create_toolbar_action_group (window); pane->toolbar_action_group = action_group; pane->tool_bar = GTK_WIDGET (nemo_toolbar_new (action_group)); g_signal_connect_object (pane->tool_bar, "notify::show-location-entry", G_CALLBACK (location_entry_changed_cb), pane, 0); pane->action_group = action_group; if (!NEMO_IS_DESKTOP_WINDOW (window)) setup_search_action (pane); g_signal_connect (pane->action_group, "pre-activate", G_CALLBACK (toolbar_action_group_activated_callback), pane); /* Pack to windows hbox (under the menu */ gtk_box_pack_start (GTK_BOX (window->details->toolbar_holder), pane->tool_bar, TRUE, TRUE, 0); /* start as non-active */ nemo_window_pane_set_active (pane, FALSE); g_settings_bind_with_mapping (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR, pane->tool_bar, "visible", G_SETTINGS_BIND_GET, nemo_window_disable_chrome_mapping, NULL, window, NULL); /* connect to the pathbar signals */ pane->path_bar = nemo_toolbar_get_path_bar (NEMO_TOOLBAR (pane->tool_bar)); gtk_size_group_add_widget (header_size_group, pane->path_bar); g_signal_connect_object (pane->path_bar, "path-clicked", G_CALLBACK (path_bar_location_changed_callback), pane, 0); g_signal_connect_object (pane->path_bar, "path-set", G_CALLBACK (path_bar_path_set_callback), pane, 0); /* connect to the location bar signals */ pane->location_bar = nemo_toolbar_get_location_bar (NEMO_TOOLBAR (pane->tool_bar)); gtk_size_group_add_widget (header_size_group, pane->location_bar); nemo_clipboard_set_up_editable (GTK_EDITABLE (nemo_location_bar_get_entry (NEMO_LOCATION_BAR (pane->location_bar))), nemo_window_get_ui_manager (NEMO_WINDOW (window)), TRUE); g_signal_connect_object (pane->location_bar, "location-changed", G_CALLBACK (navigation_bar_location_changed_callback), pane, 0); g_signal_connect_object (pane->location_bar, "cancel", G_CALLBACK (navigation_bar_cancel_callback), pane, 0); g_signal_connect_object (nemo_location_bar_get_entry (NEMO_LOCATION_BAR (pane->location_bar)), "focus-in-event", G_CALLBACK (toolbar_focus_in_callback), pane, 0); /* initialize the notebook */ pane->notebook = g_object_new (NEMO_TYPE_NOTEBOOK, NULL); gtk_box_pack_start (GTK_BOX (pane), pane->notebook, TRUE, TRUE, 0); g_signal_connect (pane->notebook, "tab-close-request", G_CALLBACK (notebook_tab_close_requested), pane); g_signal_connect_after (pane->notebook, "button_press_event", G_CALLBACK (notebook_button_press_cb), pane); g_signal_connect (pane->notebook, "popup-menu", G_CALLBACK (notebook_popup_menu_cb), pane); g_signal_connect (pane->notebook, "switch-page", G_CALLBACK (notebook_switch_page_cb), pane); g_signal_connect (pane->notebook, "create-window", G_CALLBACK (notebook_create_window_cb), pane); g_signal_connect (pane->notebook, "page-added", G_CALLBACK (notebook_page_added_cb), pane); g_signal_connect (pane->notebook, "page-removed", G_CALLBACK (notebook_page_removed_cb), pane); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (pane->notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (pane->notebook), FALSE); gtk_notebook_set_group_name (GTK_NOTEBOOK (pane->notebook), "nemo-slots"); gtk_widget_show (pane->notebook); gtk_container_set_border_width (GTK_CONTAINER (pane->notebook), 0); /* Ensure that the view has some minimal size and that other parts * of the UI (like location bar and tabs) don't request more and * thus affect the default position of the split view paned. */ gtk_widget_set_size_request (GTK_WIDGET (pane), 60, 60); /* * If we're on the desktop we need to make sure the toolbar can never show */ if (NEMO_IS_DESKTOP_WINDOW(window)) { gtk_widget_hide (GTK_WIDGET (window->details->toolbar_holder)); } /* we can unref the size group now */ g_object_unref (header_size_group); } static void nemo_window_pane_class_init (NemoWindowPaneClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); oclass->constructed = nemo_window_pane_constructed; oclass->dispose = nemo_window_pane_dispose; oclass->set_property = nemo_window_pane_set_property; oclass->get_property = nemo_window_pane_get_property; properties[PROP_WINDOW] = g_param_spec_object ("window", "The NemoWindow", "The parent NemoWindow", NEMO_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); } static void nemo_window_pane_init (NemoWindowPane *pane) { pane->slots = NULL; pane->active_slot = NULL; gtk_orientable_set_orientation (GTK_ORIENTABLE (pane), GTK_ORIENTATION_VERTICAL); GtkStyleContext *context; context = gtk_widget_get_style_context (GTK_WIDGET (pane)); gtk_style_context_add_class (context, "nemo-window-pane"); } NemoWindowPane * nemo_window_pane_new (NemoWindow *window) { return g_object_new (NEMO_TYPE_WINDOW_PANE, "window", window, NULL); } static void nemo_window_pane_set_active_style (NemoWindowPane *pane, gboolean is_active) { GtkStyleContext *style; gboolean has_inactive; style = gtk_widget_get_style_context (GTK_WIDGET (pane)); has_inactive = gtk_style_context_has_class (style, "nemo-inactive-pane"); if (has_inactive == !is_active) { return; } if (is_active) { gtk_style_context_remove_class (style, "nemo-inactive-pane"); } else { gtk_style_context_add_class (style, "nemo-inactive-pane"); } gtk_widget_reset_style (GTK_WIDGET (pane)); } void nemo_window_pane_set_active (NemoWindowPane *pane, gboolean is_active) { NemoNavigationState *nav_state; if (is_active) { nav_state = nemo_window_get_navigation_state (pane->window); nemo_navigation_state_set_master (nav_state, pane->action_group); } /* pane inactive style */ nemo_window_pane_set_active_style (pane, is_active); } GtkActionGroup * nemo_window_pane_get_toolbar_action_group (NemoWindowPane *pane) { g_return_val_if_fail (NEMO_IS_WINDOW_PANE (pane), NULL); return pane->toolbar_action_group; } void nemo_window_pane_sync_location_widgets (NemoWindowPane *pane) { NemoWindowSlot *slot, *active_slot; NemoNavigationState *nav_state; slot = pane->active_slot; nemo_window_pane_hide_temporary_bars (pane); /* Change the location bar and path bar to match the current location. */ if (slot->location != NULL) { char *uri; /* this may be NULL if we just created the slot */ uri = nemo_window_slot_get_location_uri (slot); nemo_location_bar_set_location (NEMO_LOCATION_BAR (pane->location_bar), uri); g_free (uri); nemo_path_bar_set_path (NEMO_PATH_BAR (pane->path_bar), slot->location); restore_focus_widget (pane); } /* Update window global UI if this is the active pane */ if (pane == nemo_window_get_active_pane (pane->window)) { nemo_window_sync_up_button (pane->window); /* Check if the back and forward buttons need enabling or disabling. */ active_slot = nemo_window_get_active_slot (pane->window); nav_state = nemo_window_get_navigation_state (pane->window); nemo_navigation_state_set_boolean (nav_state, NEMO_ACTION_BACK, active_slot->back_list != NULL); nemo_navigation_state_set_boolean (nav_state, NEMO_ACTION_FORWARD, active_slot->forward_list != NULL); } } static void toggle_toolbar_search_button (NemoWindowPane *pane, gboolean active) { GtkActionGroup *group; GtkAction *action; group = pane->action_group; action = gtk_action_group_get_action (group, NEMO_ACTION_SEARCH); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); } void nemo_window_pane_sync_search_widgets (NemoWindowPane *pane) { NemoWindowSlot *slot; NemoDirectory *directory; NemoSearchDirectory *search_directory; slot = pane->active_slot; search_directory = NULL; directory = nemo_directory_get (slot->location); if (NEMO_IS_SEARCH_DIRECTORY (directory)) { search_directory = NEMO_SEARCH_DIRECTORY (directory); } if (search_directory != NULL) { toggle_toolbar_search_button (pane, TRUE); } else { /* If we're not in a search directory, make sure the query editor visibility matches the search button due to a quirk when switching tabs. TODO: Another approach would be to leave the editor visible and toggle the search button true. Which is better? */ if (nemo_query_editor_get_active (NEMO_QUERY_EDITOR (slot->query_editor))) { nemo_window_slot_set_query_editor_visible (slot, FALSE); } toggle_toolbar_search_button (pane, FALSE); } nemo_directory_unref (directory); } void nemo_window_pane_close_slot (NemoWindowPane *pane, NemoWindowSlot *slot) { NemoWindow *window; DEBUG ("Requesting to remove slot %p from pane %p", slot, pane); window = pane->window; if (!window) return; if (pane->active_slot == slot) { NemoWindowSlot *next_slot; next_slot = get_next_or_previous_slot (NEMO_WINDOW_PANE (pane)); nemo_window_set_active_slot (window, next_slot); } nemo_window_pane_remove_slot_unsafe (pane, slot); /* If that was the last slot in the pane, close the pane or even the * whole window. */ if (pane->slots == NULL) { if (nemo_window_split_view_showing (window)) { NemoWindowPane *new_pane; DEBUG ("Last slot removed from the pane %p, closing it", pane); nemo_window_close_pane (window, pane); new_pane = g_list_nth_data (window->details->panes, 0); if (new_pane->active_slot == NULL) { new_pane->active_slot = get_next_or_previous_slot (new_pane); } DEBUG ("Calling set_active_pane, new slot %p", new_pane->active_slot); nemo_window_set_active_pane (window, new_pane); nemo_window_update_show_hide_menu_items (window); } else { DEBUG ("Last slot removed from the last pane, close the window"); nemo_window_close (window); } } } void nemo_window_pane_grab_focus (NemoWindowPane *pane) { if (NEMO_IS_WINDOW_PANE (pane) && pane->active_slot) { nemo_view_grab_focus (pane->active_slot->content_view); } } void nemo_window_pane_ensure_location_bar (NemoWindowPane *pane) { gboolean show_location, use_temp_toolbars; use_temp_toolbars = !g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR); show_location = nemo_toolbar_get_show_location_entry (NEMO_TOOLBAR (pane->tool_bar)); if (use_temp_toolbars) { if (!pane->temporary_navigation_bar) { gtk_widget_show (pane->tool_bar); pane->temporary_navigation_bar = TRUE; } } if (show_location) { remember_focus_widget (pane); nemo_location_bar_activate (NEMO_LOCATION_BAR (pane->location_bar)); } else { restore_focus_widget (pane); } } void nemo_window_pane_remove_slot_unsafe (NemoWindowPane *pane, NemoWindowSlot *slot) { int page_num; GtkNotebook *notebook; g_assert (NEMO_IS_WINDOW_SLOT (slot)); g_assert (NEMO_IS_WINDOW_PANE (slot->pane)); DEBUG ("Removing slot %p", slot); /* save pane because slot is not valid anymore after this call */ pane = slot->pane; notebook = GTK_NOTEBOOK (pane->notebook); nemo_window_manage_views_close_slot (slot); page_num = gtk_notebook_page_num (notebook, GTK_WIDGET (slot)); g_assert (page_num >= 0); g_signal_handlers_block_by_func (notebook, G_CALLBACK (notebook_switch_page_cb), pane); /* this will call gtk_widget_destroy on the slot */ gtk_notebook_remove_page (notebook, page_num); g_signal_handlers_unblock_by_func (notebook, G_CALLBACK (notebook_switch_page_cb), pane); gtk_notebook_set_show_tabs (notebook, gtk_notebook_get_n_pages (notebook) > 1); pane->slots = g_list_remove (pane->slots, slot); } NemoWindowSlot * nemo_window_pane_open_slot (NemoWindowPane *pane, NemoWindowOpenSlotFlags flags) { NemoWindowSlot *slot; g_assert (NEMO_IS_WINDOW_PANE (pane)); g_assert (NEMO_IS_WINDOW (pane->window)); slot = nemo_window_slot_new (pane); g_signal_handlers_block_by_func (pane->notebook, G_CALLBACK (notebook_switch_page_cb), pane); nemo_notebook_add_tab (NEMO_NOTEBOOK (pane->notebook), slot, (flags & NEMO_WINDOW_OPEN_SLOT_APPEND) != 0 ? -1 : gtk_notebook_get_current_page (GTK_NOTEBOOK (pane->notebook)) + 1, FALSE); g_signal_handlers_unblock_by_func (pane->notebook, G_CALLBACK (notebook_switch_page_cb), pane); pane->slots = g_list_append (pane->slots, slot); return slot; } nemo-4.4.2/src/nemo-window-pane.h000066400000000000000000000073321357442400300166120ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-window-pane.h: Nemo window pane Copyright (C) 2008 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Holger Berndt */ #ifndef NEMO_WINDOW_PANE_H #define NEMO_WINDOW_PANE_H #include #include "nemo-window.h" #include #define NEMO_TYPE_WINDOW_PANE (nemo_window_pane_get_type()) #define NEMO_WINDOW_PANE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_WINDOW_PANE, NemoWindowPaneClass)) #define NEMO_WINDOW_PANE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_WINDOW_PANE, NemoWindowPane)) #define NEMO_IS_WINDOW_PANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_WINDOW_PANE)) #define NEMO_IS_WINDOW_PANE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_WINDOW_PANE)) #define NEMO_WINDOW_PANE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_WINDOW_PANE, NemoWindowPaneClass)) struct _NemoWindowPaneClass { GtkBoxClass parent_class; }; /* A NemoWindowPane is a layer between a slot and a window. * Each slot is contained in one pane, and each pane can contain * one or more slots. It also supports the notion of an "active slot". * On the other hand, each pane is contained in a window, while each * window can contain one or multiple panes. Likewise, the window has * the notion of an "active pane". * * A navigation window may have one or more panes. */ struct _NemoWindowPane { GtkBox parent; /* hosting window */ NemoWindow *window; /* available slots, and active slot. * Both of them may never be NULL. */ GList *slots; NemoWindowSlot *active_slot; /* location bar */ GtkWidget *location_bar; GtkWidget *path_bar; GtkWidget *search_bar; GtkWidget *tool_bar; gboolean temporary_navigation_bar; gboolean temporary_search_bar; gboolean show_location_entry; /* notebook */ GtkWidget *notebook; GtkActionGroup *action_group; GtkActionGroup *toolbar_action_group; GtkWidget *last_focus_widget; }; GType nemo_window_pane_get_type (void); NemoWindowPane *nemo_window_pane_new (NemoWindow *window); NemoWindowSlot *nemo_window_pane_open_slot (NemoWindowPane *pane, NemoWindowOpenSlotFlags flags); /* This removes the slot from the given pane but does not close the pane and/or * window as well if there are no more slots left afterwards. This * functionality is provided by `nemo_window_pane_close_slot' below. */ void nemo_window_pane_remove_slot_unsafe (NemoWindowPane *pane, NemoWindowSlot *slot); void nemo_window_pane_sync_location_widgets (NemoWindowPane *pane); void nemo_window_pane_sync_search_widgets (NemoWindowPane *pane); void nemo_window_pane_set_active (NemoWindowPane *pane, gboolean is_active); void nemo_window_pane_close_slot (NemoWindowPane *pane, NemoWindowSlot *slot); GtkActionGroup * nemo_window_pane_get_toolbar_action_group (NemoWindowPane *pane); void nemo_window_pane_grab_focus (NemoWindowPane *pane); /* bars */ void nemo_window_pane_ensure_location_bar (NemoWindowPane *pane); #endif /* NEMO_WINDOW_PANE_H */ nemo-4.4.2/src/nemo-window-private.h000066400000000000000000000154241357442400300173420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee * Darin Adler * */ #ifndef NEMO_WINDOW_PRIVATE_H #define NEMO_WINDOW_PRIVATE_H #include "nemo-window.h" #include "nemo-window-slot.h" #include "nemo-window-pane.h" #include "nemo-navigation-state.h" #include "nemo-bookmark-list.h" #include /* FIXME bugzilla.gnome.org 42575: Migrate more fields into here. */ struct NemoWindowDetails { GtkWidget *statusbar; GtkWidget *menubar; GtkWidget *nemo_status_bar; GtkUIManager *ui_manager; GtkActionGroup *main_action_group; /* owned by ui_manager */ guint help_message_cid; /* Menus. */ guint extensions_menu_merge_id; GtkActionGroup *extensions_menu_action_group; GtkActionGroup *bookmarks_action_group; GtkActionGroup *toolbar_action_group; guint bookmarks_merge_id; NemoBookmarkList *bookmark_list; NemoWindowShowHiddenFilesMode show_hidden_files_mode; /* Ensures that we do not react on signals of a * view that is re-used as new view when its loading * is cancelled */ gboolean temporarily_ignore_view_signals; /* available panes, and active pane. * Both of them may never be NULL. */ GList *panes; NemoWindowPane *active_pane; GtkWidget *content_paned; NemoNavigationState *nav_state; /* Side Pane */ int side_pane_width; GtkWidget *sidebar; gchar *sidebar_id; gboolean show_sidebar; /* Toolbar */ GtkWidget *toolbar; /* Toolbar holder */ GtkWidget *toolbar_holder; guint extensions_toolbar_merge_id; GtkActionGroup *extensions_toolbar_action_group; guint menu_hide_delay_id; /* split view */ GtkWidget *split_view_hpane; gboolean disable_chrome; guint sidebar_width_handler_id; guint menu_state_changed_id; gboolean menu_skip_release; gboolean menu_show_queued; gchar *ignore_meta_view_id; gint ignore_meta_zoom_level; GList *ignore_meta_visible_columns; GList *ignore_meta_column_order; gchar *ignore_meta_sort_column; gint ignore_meta_sort_direction; }; /* window geometry */ /* Min values are very small, and a Nemo window at this tiny size is *almost* * completely unusable. However, if all the extra bits (sidebar, location bar, etc) * are turned off, you can see an icon or two at this size. See bug 5946. */ #define NEMO_WINDOW_MIN_WIDTH 200 #define NEMO_WINDOW_MIN_HEIGHT 200 #define NEMO_WINDOW_DEFAULT_WIDTH 800 #define NEMO_WINDOW_DEFAULT_HEIGHT 550 typedef void (*NemoBookmarkFailedCallback) (NemoWindow *window, NemoBookmark *bookmark); void nemo_window_sync_view_type (NemoWindow *window); void nemo_window_load_extension_menus (NemoWindow *window); NemoWindowPane *nemo_window_get_next_pane (NemoWindow *window); void nemo_menus_append_bookmark_to_menu (NemoWindow *window, NemoBookmark *bookmark, const char *parent_path, const char *parent_id, guint index_in_parent, GtkActionGroup *action_group, guint merge_id, GCallback refresh_callback, NemoBookmarkFailedCallback failed_callback); NemoWindowSlot *nemo_window_get_slot_for_view (NemoWindow *window, NemoView *view); void nemo_window_set_active_slot (NemoWindow *window, NemoWindowSlot *slot); void nemo_window_set_active_pane (NemoWindow *window, NemoWindowPane *new_pane); NemoWindowPane * nemo_window_get_active_pane (NemoWindow *window); /* sync window GUI with current slot. Used when changing slots, * and when updating the slot state. */ void nemo_window_sync_allow_stop (NemoWindow *window, NemoWindowSlot *slot); void nemo_window_sync_title (NemoWindow *window, NemoWindowSlot *slot); void nemo_window_sync_zoom_widgets (NemoWindow *window); void nemo_window_sync_up_button (NemoWindow *window); void nemo_window_sync_menu_bar (NemoWindow *window); void nemo_window_sync_bookmark_action (NemoWindow *window); void nemo_window_sync_thumbnail_action (NemoWindow *window); /* window menus */ GtkActionGroup *nemo_window_create_toolbar_action_group (NemoWindow *window); void nemo_window_initialize_actions (NemoWindow *window); void nemo_window_initialize_menus (NemoWindow *window); void nemo_window_finalize_menus (NemoWindow *window); void nemo_window_update_show_hide_menu_items (NemoWindow *window); /* window toolbar */ void nemo_window_close_pane (NemoWindow *window, NemoWindowPane *pane); void nemo_window_show_location_entry (NemoWindow *window); #endif /* NEMO_WINDOW_PRIVATE_H */ nemo-4.4.2/src/nemo-window-slot-dnd.c000066400000000000000000000261331357442400300174060ustar00rootroot00000000000000/* * nemo-window-slot-dnd.c - Handle DnD for widgets acting as * NemoWindowSlot proxies * * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2010, Red Hat, Inc. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Pavel Cisler , * Ettore Perazzoli */ #include #include "nemo-view-dnd.h" #include "nemo-window-slot-dnd.h" typedef struct { gboolean have_data; gboolean have_valid_data; gboolean drop_occured; unsigned int info; union { GList *selection_list; GList *uri_list; char *netscape_url; } data; gchar *desktop_dnd_source_fs; gboolean desktop_dnd_can_delete_source; NemoFile *target_file; NemoWindowSlot *target_slot; } NemoDragSlotProxyInfo; static gboolean slot_proxy_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, unsigned int time, gpointer user_data) { NemoDragSlotProxyInfo *drag_info; NemoWindowSlot *target_slot; GtkWidget *window; GdkAtom target; int action = 0; char *target_uri; if (gtk_drag_get_source_widget (context) == widget) { goto out; } drag_info = user_data; window = gtk_widget_get_toplevel (widget); g_assert (NEMO_IS_WINDOW (window)); if (!drag_info->have_data) { target = gtk_drag_dest_find_target (widget, context, NULL); if (target == GDK_NONE) { goto out; } gtk_drag_get_data (widget, context, target, time); } target_uri = NULL; if (drag_info->target_file != NULL) { target_uri = nemo_file_get_uri (drag_info->target_file); } else { if (drag_info->target_slot != NULL) { target_slot = drag_info->target_slot; } else { target_slot = nemo_window_get_active_slot (NEMO_WINDOW (window)); } if (target_slot != NULL) { target_uri = nemo_window_slot_get_current_uri (target_slot); } } if (drag_info->have_data && drag_info->have_valid_data) { if (drag_info->info == NEMO_ICON_DND_GNOME_ICON_LIST) { nemo_drag_default_drop_action_for_icons (context, target_uri, drag_info->data.selection_list, &action, &drag_info->desktop_dnd_source_fs, &drag_info->desktop_dnd_can_delete_source); } else if (drag_info->info == NEMO_ICON_DND_URI_LIST) { action = nemo_drag_default_drop_action_for_uri_list (context, target_uri); } else if (drag_info->info == NEMO_ICON_DND_NETSCAPE_URL) { action = nemo_drag_default_drop_action_for_netscape_url (context); } } g_free (target_uri); out: if (action != 0) { gtk_drag_highlight (widget); } else { gtk_drag_unhighlight (widget); } gdk_drag_status (context, action, time); return TRUE; } static void drag_info_free (gpointer user_data) { NemoDragSlotProxyInfo *drag_info = user_data; g_clear_object (&drag_info->target_file); g_clear_object (&drag_info->target_slot); g_clear_pointer (&drag_info->desktop_dnd_source_fs, g_free); g_slice_free (NemoDragSlotProxyInfo, drag_info); } static void drag_info_clear (NemoDragSlotProxyInfo *drag_info) { if (!drag_info->have_data) { goto out; } if (drag_info->info == NEMO_ICON_DND_GNOME_ICON_LIST) { nemo_drag_destroy_selection_list (drag_info->data.selection_list); g_clear_pointer (&drag_info->desktop_dnd_source_fs, g_free); } else if (drag_info->info == NEMO_ICON_DND_URI_LIST) { g_list_free (drag_info->data.uri_list); } else if (drag_info->info == NEMO_ICON_DND_NETSCAPE_URL) { g_free (drag_info->data.netscape_url); } out: drag_info->have_data = FALSE; drag_info->have_valid_data = FALSE; drag_info->desktop_dnd_can_delete_source = FALSE; drag_info->drop_occured = FALSE; } static void slot_proxy_drag_leave (GtkWidget *widget, GdkDragContext *context, unsigned int time, gpointer user_data) { gtk_drag_unhighlight (widget); drag_info_clear ((NemoDragSlotProxyInfo *)user_data); } static gboolean slot_proxy_drag_drop (GtkWidget *widget, GdkDragContext *context, int x, int y, unsigned int time, gpointer user_data) { GdkAtom target; NemoDragSlotProxyInfo *drag_info; drag_info = user_data; g_assert (!drag_info->have_data); drag_info->drop_occured = TRUE; target = gtk_drag_dest_find_target (widget, context, NULL); gtk_drag_get_data (widget, context, target, time); return TRUE; } static void slot_proxy_handle_drop (GtkWidget *widget, GdkDragContext *context, unsigned int time, NemoDragSlotProxyInfo *drag_info) { GtkWidget *window; NemoWindowSlot *target_slot; NemoView *target_view; char *target_uri; GList *uri_list; if (!drag_info->have_data || !drag_info->have_valid_data) { gtk_drag_finish (context, FALSE, FALSE, time); drag_info_clear (drag_info); return; } window = gtk_widget_get_toplevel (widget); g_assert (NEMO_IS_WINDOW (window)); if (drag_info->target_slot != NULL) { target_slot = drag_info->target_slot; } else { target_slot = nemo_window_get_active_slot (NEMO_WINDOW (window)); } target_uri = NULL; if (drag_info->target_file != NULL) { target_uri = nemo_file_get_uri (drag_info->target_file); } else if (target_slot != NULL) { target_uri = nemo_window_slot_get_current_uri (target_slot); } target_view = NULL; if (target_slot != NULL) { target_view = nemo_window_slot_get_current_view (target_slot); } if (target_slot != NULL && target_view != NULL) { if (drag_info->info == NEMO_ICON_DND_GNOME_ICON_LIST) { uri_list = nemo_drag_uri_list_from_selection_list (drag_info->data.selection_list); g_assert (uri_list != NULL); nemo_view_drop_proxy_received_uris (target_view, uri_list, target_uri, gdk_drag_context_get_selected_action (context)); g_list_free_full (uri_list, g_free); } else if (drag_info->info == NEMO_ICON_DND_URI_LIST) { nemo_view_drop_proxy_received_uris (target_view, drag_info->data.uri_list, target_uri, gdk_drag_context_get_selected_action (context)); } if (drag_info->info == NEMO_ICON_DND_NETSCAPE_URL) { nemo_view_handle_netscape_url_drop (target_view, drag_info->data.netscape_url, target_uri, gdk_drag_context_get_selected_action (context), 0, 0); } gtk_drag_finish (context, TRUE, FALSE, time); } else { gtk_drag_finish (context, FALSE, FALSE, time); } g_free (target_uri); drag_info_clear (drag_info); } static void slot_proxy_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *data, unsigned int info, unsigned int time, gpointer user_data) { NemoDragSlotProxyInfo *drag_info; char **uris; drag_info = user_data; g_assert (!drag_info->have_data); drag_info->have_data = TRUE; drag_info->info = info; if (gtk_selection_data_get_length (data) < 0) { drag_info->have_valid_data = FALSE; return; } if (info == NEMO_ICON_DND_GNOME_ICON_LIST) { drag_info->data.selection_list = nemo_drag_build_selection_list (data); drag_info->have_valid_data = drag_info->data.selection_list != NULL; } else if (info == NEMO_ICON_DND_URI_LIST) { uris = gtk_selection_data_get_uris (data); drag_info->data.uri_list = nemo_drag_uri_list_from_array ((const char **) uris); g_strfreev (uris); drag_info->have_valid_data = drag_info->data.uri_list != NULL; } else if (info == NEMO_ICON_DND_NETSCAPE_URL) { drag_info->data.netscape_url = g_strdup ((char *) gtk_selection_data_get_data (data)); drag_info->have_valid_data = drag_info->data.netscape_url != NULL; } if (drag_info->drop_occured) { slot_proxy_handle_drop (widget, context, time, drag_info); } } void nemo_drag_slot_proxy_init (GtkWidget *widget, NemoFile *target_file, NemoWindowSlot *target_slot) { NemoDragSlotProxyInfo *drag_info; const GtkTargetEntry targets[] = { { (char *)NEMO_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NEMO_ICON_DND_GNOME_ICON_LIST }, { (char *)NEMO_ICON_DND_NETSCAPE_URL_TYPE, 0, NEMO_ICON_DND_NETSCAPE_URL } }; GtkTargetList *target_list; g_assert (GTK_IS_WIDGET (widget)); drag_info = g_slice_new0 (NemoDragSlotProxyInfo); g_object_set_data_full (G_OBJECT (widget), "drag-slot-proxy-data", drag_info, drag_info_free); drag_info->desktop_dnd_source_fs = NULL; drag_info->desktop_dnd_can_delete_source = FALSE; if (target_file != NULL) drag_info->target_file = g_object_ref (target_file); if (target_slot != NULL) drag_info->target_slot = g_object_ref (target_slot); gtk_drag_dest_set (widget, 0, NULL, 0, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK); target_list = gtk_target_list_new (targets, G_N_ELEMENTS (targets)); gtk_target_list_add_uri_targets (target_list, NEMO_ICON_DND_URI_LIST); gtk_drag_dest_set_target_list (widget, target_list); gtk_target_list_unref (target_list); g_signal_connect (widget, "drag-motion", G_CALLBACK (slot_proxy_drag_motion), drag_info); g_signal_connect (widget, "drag-drop", G_CALLBACK (slot_proxy_drag_drop), drag_info); g_signal_connect (widget, "drag-data-received", G_CALLBACK (slot_proxy_drag_data_received), drag_info); g_signal_connect (widget, "drag-leave", G_CALLBACK (slot_proxy_drag_leave), drag_info); } nemo-4.4.2/src/nemo-window-slot-dnd.h000066400000000000000000000026571357442400300174200ustar00rootroot00000000000000/* * nemo-window-slot-dnd.c - Handle DnD for widgets acting as * NemoWindowSlot proxies * * Copyright (C) 2000, 2001 Eazel, Inc. * Copyright (C) 2010, Red Hat, Inc. * * The Gnome 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. * * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. * * Authors: Pavel Cisler , * Ettore Perazzoli */ #ifndef __NEMO_WINDOW_SLOT_DND_H__ #define __NEMO_WINDOW_SLOT_DND_H__ #include #include #include #include "nemo-window-slot.h" void nemo_drag_slot_proxy_init (GtkWidget *widget, NemoFile *target_file, NemoWindowSlot *target_slot); #endif /* __NEMO_WINDOW_SLOT_DND_H__ */ nemo-4.4.2/src/nemo-window-slot.c000066400000000000000000000547541357442400300166550ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-window-slot.c: Nemo window slot Copyright (C) 2008 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Christian Neumair */ #include "config.h" #include "nemo-window-slot.h" #include "nemo-actions.h" #include "nemo-desktop-window.h" #include "nemo-floating-bar.h" #include "nemo-window-private.h" #include "nemo-window-manage-views.h" #include "nemo-window-types.h" #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_WINDOW #include #include G_DEFINE_TYPE (NemoWindowSlot, nemo_window_slot, GTK_TYPE_BOX); enum { ACTIVE, INACTIVE, CHANGED_PANE, LOCATION_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void sync_search_directory (NemoWindowSlot *slot) { NemoDirectory *directory; NemoQuery *query; g_assert (NEMO_IS_FILE (slot->viewed_file)); directory = nemo_directory_get_for_file (slot->viewed_file); g_assert (NEMO_IS_SEARCH_DIRECTORY (directory)); query = nemo_query_editor_get_query (slot->query_editor); if (query) { nemo_query_set_show_hidden (query, g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES)); } nemo_search_directory_set_query (NEMO_SEARCH_DIRECTORY (directory), query); g_clear_object (&query); nemo_window_slot_force_reload (slot); nemo_directory_unref (directory); } static void sync_search_location_cb (NemoWindow *window, GError *error, gpointer user_data) { NemoWindowSlot *slot = user_data; sync_search_directory (slot); } static void create_new_search (NemoWindowSlot *slot) { char *uri; NemoDirectory *directory; GFile *location; uri = nemo_search_directory_generate_new_uri (); location = g_file_new_for_uri (uri); directory = nemo_directory_get (location); g_assert (NEMO_IS_SEARCH_DIRECTORY (directory)); nemo_window_slot_open_location_full (slot, location, NEMO_WINDOW_OPEN_FLAG_SEARCH, NULL, sync_search_location_cb, slot); nemo_directory_unref (directory); g_object_unref (location); g_free (uri); } static void query_editor_cancel_callback (NemoQueryEditor *editor, NemoWindowSlot *slot) { GtkAction *search; search = gtk_action_group_get_action (slot->pane->toolbar_action_group, NEMO_ACTION_SEARCH); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (search), FALSE); } static void query_editor_changed_callback (NemoQueryEditor *editor, NemoQuery *query, gboolean reload, NemoWindowSlot *slot) { NemoDirectory *directory; g_assert (NEMO_IS_FILE (slot->viewed_file)); directory = nemo_directory_get_for_file (slot->viewed_file); if (!NEMO_IS_SEARCH_DIRECTORY (directory)) { /* this is the first change from the query editor. we ask for a location change to the search directory, indicate the directory needs to be sync'd with the current query. */ create_new_search (slot); /* Focus is now on the new slot, move it back to query_editor */ gtk_widget_grab_focus (GTK_WIDGET (slot->query_editor)); } else { sync_search_directory (slot); } nemo_directory_unref (directory); } static void update_query_editor (NemoWindowSlot *slot) { NemoDirectory *directory; NemoSearchDirectory *search_directory; directory = nemo_directory_get (slot->location); if (NEMO_IS_SEARCH_DIRECTORY (directory)) { NemoQuery *query; search_directory = NEMO_SEARCH_DIRECTORY (directory); query = nemo_search_directory_get_query (search_directory); if (query != NULL) { nemo_query_editor_set_query (slot->query_editor, query); g_object_unref (query); } } else { nemo_query_editor_set_location (slot->query_editor, slot->location); } nemo_directory_unref (directory); } static void ensure_query_editor (NemoWindowSlot *slot) { g_assert (slot->query_editor != NULL); update_query_editor (slot); nemo_query_editor_set_active (NEMO_QUERY_EDITOR (slot->query_editor), nemo_window_slot_get_location_uri (slot), TRUE); gtk_widget_grab_focus (GTK_WIDGET (slot->query_editor)); } void nemo_window_slot_set_query_editor_visible (NemoWindowSlot *slot, gboolean visible) { if (visible) { ensure_query_editor (slot); if (slot->qe_changed_id == 0) slot->qe_changed_id = g_signal_connect (slot->query_editor, "changed", G_CALLBACK (query_editor_changed_callback), slot); if (slot->qe_cancel_id == 0) slot->qe_cancel_id = g_signal_connect (slot->query_editor, "cancel", G_CALLBACK (query_editor_cancel_callback), slot); } else { nemo_query_editor_set_active (NEMO_QUERY_EDITOR (slot->query_editor), NULL, FALSE); if (slot->qe_changed_id > 0) { g_signal_handler_disconnect (slot->query_editor, slot->qe_changed_id); slot->qe_changed_id = 0; } if (slot->qe_cancel_id > 0) { g_signal_handler_disconnect (slot->query_editor, slot->qe_cancel_id); slot->qe_cancel_id = 0; } nemo_query_editor_set_query (slot->query_editor, NULL); } } static void real_active (NemoWindowSlot *slot) { NemoWindow *window; NemoWindowPane *pane; int page_num; window = nemo_window_slot_get_window (slot); pane = slot->pane; page_num = gtk_notebook_page_num (GTK_NOTEBOOK (pane->notebook), GTK_WIDGET (slot)); g_assert (page_num >= 0); gtk_notebook_set_current_page (GTK_NOTEBOOK (pane->notebook), page_num); /* sync window to new slot */ nemo_window_push_status (window, slot->status_text); nemo_window_sync_allow_stop (window, slot); nemo_window_sync_title (window, slot); nemo_window_sync_zoom_widgets (window); nemo_window_sync_bookmark_action (window); nemo_window_pane_sync_location_widgets (slot->pane); nemo_window_pane_sync_search_widgets (slot->pane); nemo_window_sync_thumbnail_action(window); if (slot->viewed_file != NULL) { nemo_window_sync_view_type (window); nemo_window_load_extension_menus (window); } } static void real_inactive (NemoWindowSlot *slot) { NemoWindow *window; window = nemo_window_slot_get_window (slot); g_assert (slot == nemo_window_get_active_slot (window)); } static void floating_bar_action_cb (NemoFloatingBar *floating_bar, gint action, NemoWindowSlot *slot) { if (action == NEMO_FLOATING_BAR_ACTION_ID_STOP) { nemo_window_slot_stop_loading (slot); } } static void nemo_window_slot_init (NemoWindowSlot *slot) { GtkWidget *extras_vbox; gtk_orientable_set_orientation (GTK_ORIENTABLE (slot), GTK_ORIENTATION_VERTICAL); gtk_widget_show (GTK_WIDGET (slot)); extras_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); slot->extra_location_widgets = extras_vbox; gtk_box_pack_start (GTK_BOX (slot), extras_vbox, FALSE, FALSE, 0); gtk_widget_show (extras_vbox); slot->query_editor = NEMO_QUERY_EDITOR (nemo_query_editor_new ()); nemo_window_slot_add_extra_location_widget (slot, GTK_WIDGET (slot->query_editor)); slot->view_overlay = gtk_overlay_new (); gtk_widget_add_events (slot->view_overlay, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_box_pack_start (GTK_BOX (slot), slot->view_overlay, TRUE, TRUE, 0); gtk_widget_show (slot->view_overlay); slot->floating_bar = nemo_floating_bar_new ("", FALSE); gtk_widget_set_halign (slot->floating_bar, GTK_ALIGN_END); gtk_widget_set_valign (slot->floating_bar, GTK_ALIGN_END); gtk_overlay_add_overlay (GTK_OVERLAY (slot->view_overlay), slot->floating_bar); g_signal_connect (slot->floating_bar, "action", G_CALLBACK (floating_bar_action_cb), slot); slot->cache_bar = NULL; slot->title = g_strdup (_("Loading...")); } static void view_end_loading_cb (NemoView *view, gboolean all_files_seen, NemoWindowSlot *slot) { if (slot->needs_reload) { nemo_window_slot_queue_reload (slot, FALSE); slot->needs_reload = FALSE; } } static void nemo_window_slot_dispose (GObject *object) { NemoWindowSlot *slot; GtkWidget *widget; slot = NEMO_WINDOW_SLOT (object); nemo_window_slot_clear_forward_list (slot); nemo_window_slot_clear_back_list (slot); nemo_window_slot_remove_extra_location_widgets (slot); if (slot->content_view) { widget = GTK_WIDGET (slot->content_view); gtk_widget_destroy (widget); g_object_unref (slot->content_view); slot->content_view = NULL; } if (slot->new_content_view) { widget = GTK_WIDGET (slot->new_content_view); gtk_widget_destroy (widget); g_object_unref (slot->new_content_view); slot->new_content_view = NULL; } if (slot->set_status_timeout_id != 0) { g_source_remove (slot->set_status_timeout_id); slot->set_status_timeout_id = 0; } if (slot->loading_timeout_id != 0) { g_source_remove (slot->loading_timeout_id); slot->loading_timeout_id = 0; } nemo_window_slot_set_viewed_file (slot, NULL); /* TODO? why do we unref here? the file is NULL. * It was already here before the slot move, though */ nemo_file_unref (slot->viewed_file); if (slot->location) { /* TODO? why do we ref here, instead of unreffing? * It was already here before the slot migration, though */ g_object_ref (slot->location); } g_list_free_full (slot->pending_selection, g_object_unref); slot->pending_selection = NULL; g_clear_object (&slot->current_location_bookmark); g_clear_object (&slot->last_location_bookmark); if (slot->find_mount_cancellable != NULL) { g_cancellable_cancel (slot->find_mount_cancellable); slot->find_mount_cancellable = NULL; } slot->pane = NULL; g_free (slot->title); slot->title = NULL; g_free (slot->status_text); slot->status_text = NULL; G_OBJECT_CLASS (nemo_window_slot_parent_class)->dispose (object); } static void nemo_window_slot_class_init (NemoWindowSlotClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); klass->active = real_active; klass->inactive = real_inactive; oclass->dispose = nemo_window_slot_dispose; signals[ACTIVE] = g_signal_new ("active", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoWindowSlotClass, active), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[INACTIVE] = g_signal_new ("inactive", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoWindowSlotClass, inactive), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[CHANGED_PANE] = g_signal_new ("changed-pane", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NemoWindowSlotClass, changed_pane), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[LOCATION_CHANGED] = g_signal_new ("location-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); } GFile * nemo_window_slot_get_location (NemoWindowSlot *slot) { g_assert (slot != NULL); if (slot->location != NULL) { return g_object_ref (slot->location); } return NULL; } char * nemo_window_slot_get_location_uri (NemoWindowSlot *slot) { g_assert (NEMO_IS_WINDOW_SLOT (slot)); if (slot->location) { return g_file_get_uri (slot->location); } return NULL; } void nemo_window_slot_make_hosting_pane_active (NemoWindowSlot *slot) { g_assert (NEMO_IS_WINDOW_PANE (slot->pane)); nemo_window_set_active_slot (nemo_window_slot_get_window (slot), slot); } NemoWindow * nemo_window_slot_get_window (NemoWindowSlot *slot) { g_assert (NEMO_IS_WINDOW_SLOT (slot)); return slot->pane->window; } /* nemo_window_slot_update_title: * * Re-calculate the slot title. * Called when the location or view has changed. * @slot: The NemoWindowSlot in question. * */ void nemo_window_slot_update_title (NemoWindowSlot *slot) { NemoWindow *window; char *title; gboolean do_sync = FALSE; title = nemo_compute_title_for_location (slot->location); window = nemo_window_slot_get_window (slot); if (g_strcmp0 (title, slot->title) != 0) { do_sync = TRUE; g_free (slot->title); slot->title = title; title = NULL; } if (strlen (slot->title) > 0 && slot->current_location_bookmark != NULL) { do_sync = TRUE; } if (do_sync) { nemo_window_sync_title (window, slot); } if (title != NULL) { g_free (title); } } /* nemo_window_slot_update_icon: * * Re-calculate the slot icon * Called when the location or view or icon set has changed. * @slot: The NemoWindowSlot in question. */ void nemo_window_slot_update_icon (NemoWindowSlot *slot) { NemoWindow *window; NemoIconInfo *info; const char *icon_name; GdkPixbuf *pixbuf; window = nemo_window_slot_get_window (slot); info = NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->get_icon (window, slot); icon_name = NULL; if (info) { icon_name = nemo_icon_info_get_used_name (info); if (icon_name != NULL) { /* Gtk+ doesn't short circuit this (yet), so avoid lots of work * if we're setting to the same icon. This happens a lot e.g. when * the trash directory changes due to the file count changing. */ if (g_strcmp0 (icon_name, gtk_window_get_icon_name (GTK_WINDOW (window))) != 0) { gtk_window_set_icon_name (GTK_WINDOW (window), icon_name); } } else { pixbuf = nemo_icon_info_get_pixbuf_nodefault (info); if (pixbuf) { gtk_window_set_icon (GTK_WINDOW (window), pixbuf); g_object_unref (pixbuf); } } nemo_icon_info_unref (info); } } void nemo_window_slot_set_show_thumbnails (NemoWindowSlot *slot, gboolean show_thumbnails) { NemoDirectory *directory; directory = nemo_directory_get (slot->location); nemo_directory_set_show_thumbnails(directory, show_thumbnails); } void nemo_window_slot_set_content_view_widget (NemoWindowSlot *slot, NemoView *new_view) { NemoWindow *window; GtkWidget *widget; window = nemo_window_slot_get_window (slot); if (slot->content_view != NULL) { /* disconnect old view */ g_signal_handlers_disconnect_by_func (slot->content_view, G_CALLBACK (view_end_loading_cb), slot); nemo_window_disconnect_content_view (window, slot->content_view); widget = GTK_WIDGET (slot->content_view); gtk_widget_destroy (widget); g_object_unref (slot->content_view); slot->content_view = NULL; } if (new_view != NULL) { widget = GTK_WIDGET (new_view); gtk_container_add (GTK_CONTAINER (slot->view_overlay), widget); gtk_widget_show (widget); slot->content_view = new_view; g_object_ref (slot->content_view); g_signal_connect (new_view, "end_loading", G_CALLBACK (view_end_loading_cb), slot); /* connect new view */ nemo_window_connect_content_view (window, new_view); } } void nemo_window_slot_set_allow_stop (NemoWindowSlot *slot, gboolean allow) { NemoWindow *window; g_assert (NEMO_IS_WINDOW_SLOT (slot)); slot->allow_stop = allow; window = nemo_window_slot_get_window (slot); nemo_window_sync_allow_stop (window, slot); } static void real_slot_set_short_status (NemoWindowSlot *slot, const gchar *status) { gboolean show_statusbar; gboolean disable_chrome; nemo_floating_bar_cleanup_actions (NEMO_FLOATING_BAR (slot->floating_bar)); nemo_floating_bar_set_show_spinner (NEMO_FLOATING_BAR (slot->floating_bar), FALSE); show_statusbar = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_STATUS_BAR); g_object_get (nemo_window_slot_get_window (slot), "disable-chrome", &disable_chrome, NULL); if (status == NULL || show_statusbar || disable_chrome) { gtk_widget_hide (slot->floating_bar); return; } nemo_floating_bar_set_label (NEMO_FLOATING_BAR (slot->floating_bar), status); gtk_widget_show (slot->floating_bar); } typedef struct { gchar *status; NemoWindowSlot *slot; } SetStatusData; static void set_status_data_free (gpointer data) { SetStatusData *status_data = data; g_free (status_data->status); g_slice_free (SetStatusData, data); } static gboolean set_status_timeout_cb (gpointer data) { SetStatusData *status_data = data; status_data->slot->set_status_timeout_id = 0; real_slot_set_short_status (status_data->slot, status_data->status); return FALSE; } static void set_floating_bar_status (NemoWindowSlot *slot, const gchar *status) { GtkSettings *settings; gint double_click_time; SetStatusData *status_data; if (slot->set_status_timeout_id != 0) { g_source_remove (slot->set_status_timeout_id); slot->set_status_timeout_id = 0; } settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (slot->content_view))); g_object_get (settings, "gtk-double-click-time", &double_click_time, NULL); status_data = g_slice_new0 (SetStatusData); status_data->status = g_strdup (status); status_data->slot = slot; /* waiting for half of the double-click-time before setting * the status seems to be a good approximation of not setting it * too often and not delaying the statusbar too much. */ slot->set_status_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, (guint) (double_click_time / 2), set_status_timeout_cb, status_data, set_status_data_free); } void nemo_window_slot_set_status (NemoWindowSlot *slot, const char *status, const char *short_status) { NemoWindow *window; g_assert (NEMO_IS_WINDOW_SLOT (slot)); g_free (slot->status_text); slot->status_text = g_strdup (status); if (slot->content_view != NULL) { set_floating_bar_status (slot, short_status); } window = nemo_window_slot_get_window (slot); if (slot == nemo_window_get_active_slot (window)) { nemo_window_push_status (window, slot->status_text); } } static void remove_all_extra_location_widgets (GtkWidget *widget, gpointer data) { NemoWindowSlot *slot = data; NemoDirectory *directory; directory = nemo_directory_get (slot->location); if (widget != GTK_WIDGET (slot->query_editor)) { gtk_container_remove (GTK_CONTAINER (slot->extra_location_widgets), widget); } nemo_directory_unref (directory); } void nemo_window_slot_remove_extra_location_widgets (NemoWindowSlot *slot) { gtk_container_foreach (GTK_CONTAINER (slot->extra_location_widgets), remove_all_extra_location_widgets, slot); } void nemo_window_slot_add_extra_location_widget (NemoWindowSlot *slot, GtkWidget *widget) { gtk_box_pack_start (GTK_BOX (slot->extra_location_widgets), widget, TRUE, TRUE, 0); gtk_widget_show (slot->extra_location_widgets); } /* returns either the pending or the actual current uri */ char * nemo_window_slot_get_current_uri (NemoWindowSlot *slot) { if (slot->pending_location != NULL) { return g_file_get_uri (slot->pending_location); } if (slot->location != NULL) { return g_file_get_uri (slot->location); } g_assert_not_reached (); return NULL; } NemoView * nemo_window_slot_get_current_view (NemoWindowSlot *slot) { if (slot->content_view != NULL) { return slot->content_view; } else if (slot->new_content_view) { return slot->new_content_view; } return NULL; } void nemo_window_slot_go_home (NemoWindowSlot *slot, NemoWindowOpenFlags flags) { GFile *home; g_return_if_fail (NEMO_IS_WINDOW_SLOT (slot)); home = g_file_new_for_path (g_get_home_dir ()); nemo_window_slot_open_location (slot, home, flags); g_object_unref (home); } void nemo_window_slot_go_up (NemoWindowSlot *slot, NemoWindowOpenFlags flags) { GFile *parent; char * uri; if (slot->location == NULL) { return; } parent = g_file_get_parent (slot->location); if (parent == NULL) { if (g_file_has_uri_scheme (slot->location, "smb")) { uri = g_file_get_uri (slot->location); DEBUG ("Starting samba URI for navigation: %s", uri); if (g_strcmp0 ("smb:///", uri) == 0) { parent = g_file_new_for_uri ("network:///"); } else { GString *gstr; char * temp; gstr = g_string_new (uri); // Remove last / if (g_str_has_suffix (gstr->str, "/")) { gstr = g_string_set_size (gstr, gstr->len - 1); } // Remove last part of string after last remaining / temp = g_strrstr (gstr->str, "/") + 1; if (temp != NULL) { gstr = g_string_set_size (gstr, temp - gstr->str); } // if we're going to end up with smb://, redirect it to network instead. if (g_strcmp0 ("smb://", gstr->str) == 0) { gstr = g_string_assign (gstr, "network:///"); } uri = g_string_free (gstr, FALSE); parent = g_file_new_for_uri (uri); DEBUG ("Ending samba URI for navigation: %s", uri); } g_free (uri); } else { return; } } nemo_window_slot_open_location (slot, parent, flags); g_object_unref (parent); } void nemo_window_slot_clear_forward_list (NemoWindowSlot *slot) { g_assert (NEMO_IS_WINDOW_SLOT (slot)); g_list_free_full (slot->forward_list, g_object_unref); slot->forward_list = NULL; } void nemo_window_slot_clear_back_list (NemoWindowSlot *slot) { g_assert (NEMO_IS_WINDOW_SLOT (slot)); g_list_free_full (slot->back_list, g_object_unref); slot->back_list = NULL; } gboolean nemo_window_slot_should_close_with_mount (NemoWindowSlot *slot, GMount *mount) { GFile *mount_location; gboolean close_with_mount; mount_location = g_mount_get_root (mount); close_with_mount = g_file_has_prefix (NEMO_WINDOW_SLOT (slot)->location, mount_location) || g_file_equal (NEMO_WINDOW_SLOT (slot)->location, mount_location); g_object_unref (mount_location); return close_with_mount; } NemoWindowSlot * nemo_window_slot_new (NemoWindowPane *pane) { NemoWindowSlot *slot; slot = g_object_new (NEMO_TYPE_WINDOW_SLOT, NULL); slot->pane = pane; return slot; } nemo-4.4.2/src/nemo-window-slot.h000066400000000000000000000152001357442400300166410ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- nemo-window-slot.h: Nemo window slot Copyright (C) 2008 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 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 - Suite 500, Boston, MA 02110-1335, USA. Author: Christian Neumair */ #ifndef NEMO_WINDOW_SLOT_H #define NEMO_WINDOW_SLOT_H #include "nemo-view.h" #include "nemo-window-types.h" #include "nemo-query-editor.h" #define NEMO_TYPE_WINDOW_SLOT (nemo_window_slot_get_type()) #define NEMO_WINDOW_SLOT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_WINDOW_SLOT, NemoWindowSlotClass)) #define NEMO_WINDOW_SLOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_WINDOW_SLOT, NemoWindowSlot)) #define NEMO_IS_WINDOW_SLOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_WINDOW_SLOT)) #define NEMO_IS_WINDOW_SLOT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_WINDOW_SLOT)) #define NEMO_WINDOW_SLOT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_WINDOW_SLOT, NemoWindowSlotClass)) typedef enum { NEMO_LOCATION_CHANGE_STANDARD, NEMO_LOCATION_CHANGE_BACK, NEMO_LOCATION_CHANGE_FORWARD, NEMO_LOCATION_CHANGE_RELOAD } NemoLocationChangeType; struct NemoWindowSlotClass { GtkBoxClass parent_class; /* wrapped NemoWindowInfo signals, for overloading */ void (* active) (NemoWindowSlot *slot); void (* inactive) (NemoWindowSlot *slot); void (* changed_pane) (NemoWindowSlot *slot); }; /* Each NemoWindowSlot corresponds to a location in the window * for displaying a NemoView, i.e. a tab. */ struct NemoWindowSlot { GtkBox parent; NemoWindowPane *pane; /* slot contains * 1) an event box containing extra_location_widgets * 2) the view box for the content view */ GtkWidget *extra_location_widgets; GtkWidget *view_overlay; GtkWidget *floating_bar; GtkWidget *cache_bar; guint set_status_timeout_id; guint loading_timeout_id; NemoView *content_view; NemoView *new_content_view; /* Information about bookmarks */ NemoBookmark *current_location_bookmark; NemoBookmark *last_location_bookmark; /* Current location. */ GFile *location; char *title; char *status_text; NemoFile *viewed_file; gboolean viewed_file_seen; gboolean viewed_file_in_trash; gboolean allow_stop; NemoQueryEditor *query_editor; GtkWidget *query_editor_revealer; gulong qe_changed_id; gulong qe_cancel_id; /* New location. */ NemoLocationChangeType location_change_type; guint location_change_distance; GFile *pending_location; char *pending_scroll_to; GList *pending_selection; NemoFile *determine_view_file; GCancellable *mount_cancellable; GError *mount_error; gboolean tried_mount; NemoWindowGoToCallback open_callback; gpointer open_callback_user_data; gboolean needs_reload; GCancellable *find_mount_cancellable; gboolean visible; /* Back/Forward chain, and history list. * The data in these lists are NemoBookmark pointers. */ GList *back_list, *forward_list; }; GType nemo_window_slot_get_type (void); NemoWindowSlot * nemo_window_slot_new (NemoWindowPane *pane); void nemo_window_slot_update_title (NemoWindowSlot *slot); void nemo_window_slot_update_icon (NemoWindowSlot *slot); void nemo_window_slot_set_query_editor_visible (NemoWindowSlot *slot, gboolean visible); GFile * nemo_window_slot_get_location (NemoWindowSlot *slot); char * nemo_window_slot_get_location_uri (NemoWindowSlot *slot); void nemo_window_slot_queue_reload (NemoWindowSlot *slot, gboolean clear_thumbs); void nemo_window_slot_force_reload (NemoWindowSlot *slot); /* convenience wrapper without selection and callback/user_data */ #define nemo_window_slot_open_location(slot, location, flags)\ nemo_window_slot_open_location_full(slot, location, flags, NULL, NULL, NULL) void nemo_window_slot_open_location_full (NemoWindowSlot *slot, GFile *location, NemoWindowOpenFlags flags, GList *new_selection, /* NemoFile list */ NemoWindowGoToCallback callback, gpointer user_data); void nemo_window_slot_stop_loading (NemoWindowSlot *slot); void nemo_window_slot_set_content_view (NemoWindowSlot *slot, const char *id); const char *nemo_window_slot_get_content_view_id (NemoWindowSlot *slot); gboolean nemo_window_slot_content_view_matches_iid (NemoWindowSlot *slot, const char *iid); void nemo_window_slot_go_home (NemoWindowSlot *slot, NemoWindowOpenFlags flags); void nemo_window_slot_go_up (NemoWindowSlot *slot, NemoWindowOpenFlags flags); void nemo_window_slot_set_content_view_widget (NemoWindowSlot *slot, NemoView *content_view); void nemo_window_slot_set_viewed_file (NemoWindowSlot *slot, NemoFile *file); void nemo_window_slot_set_allow_stop (NemoWindowSlot *slot, gboolean allow_stop); void nemo_window_slot_set_status (NemoWindowSlot *slot, const char *status, const char *short_status); void nemo_window_slot_add_extra_location_widget (NemoWindowSlot *slot, GtkWidget *widget); void nemo_window_slot_remove_extra_location_widgets (NemoWindowSlot *slot); NemoView * nemo_window_slot_get_current_view (NemoWindowSlot *slot); char * nemo_window_slot_get_current_uri (NemoWindowSlot *slot); NemoWindow * nemo_window_slot_get_window (NemoWindowSlot *slot); void nemo_window_slot_make_hosting_pane_active (NemoWindowSlot *slot); gboolean nemo_window_slot_should_close_with_mount (NemoWindowSlot *slot, GMount *mount); void nemo_window_slot_clear_forward_list (NemoWindowSlot *slot); void nemo_window_slot_clear_back_list (NemoWindowSlot *slot); void nemo_window_slot_check_bad_cache_bar (NemoWindowSlot *slot); void nemo_window_slot_set_show_thumbnails (NemoWindowSlot *slot, gboolean show_thumbnails); #endif /* NEMO_WINDOW_SLOT_H */ nemo-4.4.2/src/nemo-window-types.h000066400000000000000000000035021357442400300170260ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * nemo-window-types: typedefs for window-related types. * * Copyright (C) 1999, 2000, 2010 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee * Darin Adler * */ #ifndef __NEMO_WINDOW_TYPES_H__ #define __NEMO_WINDOW_TYPES_H__ typedef struct _NemoWindowPane NemoWindowPane; typedef struct _NemoWindowPaneClass NemoWindowPaneClass; typedef struct NemoWindow NemoWindow; typedef struct NemoWindowSlot NemoWindowSlot; typedef struct NemoWindowSlotClass NemoWindowSlotClass; typedef void (* NemoWindowGoToCallback) (NemoWindow *window, GError *error, gpointer user_data); typedef enum { NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND = 1<<0, NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW = 1<<1, NEMO_WINDOW_OPEN_FLAG_NEW_TAB = 1<<2, NEMO_WINDOW_OPEN_FLAG_SEARCH = 1<<3, NEMO_WINDOW_OPEN_FLAG_MOUNT = 1<<4 } NemoWindowOpenFlags; #endif /* __NEMO_WINDOW_TYPES_H__ */ nemo-4.4.2/src/nemo-window.c000066400000000000000000002037611357442400300156700ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000, 2004 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee * John Sullivan * Alexander Larsson */ /* nemo-window.c: Implementation of the main window object */ #include #include "nemo-window-private.h" #include "nemo-actions.h" #include "nemo-application.h" #include "nemo-bookmarks-window.h" #include "nemo-location-bar.h" #include "nemo-mime-actions.h" #include "nemo-notebook.h" #include "nemo-places-sidebar.h" #include "nemo-tree-sidebar.h" #include "nemo-view-factory.h" #include "nemo-window-manage-views.h" #include "nemo-window-bookmarks.h" #include "nemo-window-slot.h" #include "nemo-window-menus.h" #include "nemo-icon-view.h" #include "nemo-list-view.h" #include "nemo-statusbar.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XF86KEYSYM_H #include #endif #include #include #include #include #include #include #include #include #define DEBUG_FLAG NEMO_DEBUG_WINDOW #include #include #include #define MAX_TITLE_LENGTH 180 /* Forward and back buttons on the mouse */ static gboolean mouse_extra_buttons = TRUE; static guint mouse_forward_button = 9; static guint mouse_back_button = 8; static void mouse_back_button_changed (gpointer callback_data); static void mouse_forward_button_changed (gpointer callback_data); static void use_extra_mouse_buttons_changed (gpointer callback_data); static void side_pane_id_changed (NemoWindow *window); static void toggle_menubar (NemoWindow *window, gint action); /* Sanity check: highest mouse button value I could find was 14. 5 is our * lower threshold (well-documented to be the one of the button events for the * scrollwheel), so it's hardcoded in the functions below. However, if you have * a button that registers higher and want to map it, file a bug and * we'll move the bar. Makes you wonder why the X guys don't have * defined values for these like the XKB stuff, huh? */ #define UPPER_MOUSE_LIMIT 14 enum { PROP_DISABLE_CHROME = 1, PROP_SIDEBAR_VIEW_TYPE, PROP_SHOW_SIDEBAR, NUM_PROPERTIES, }; enum { GO_UP, RELOAD, PROMPT_FOR_LOCATION, LOADING_URI, HIDDEN_FILES_MODE_CHANGED, SLOT_ADDED, SLOT_REMOVED, LAST_SIGNAL }; enum { MENU_HIDE, MENU_SHOW, MENU_TOGGLE }; static guint signals[LAST_SIGNAL] = { 0 }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (NemoWindow, nemo_window, GTK_TYPE_APPLICATION_WINDOW); static const struct { unsigned int keyval; const char *action; } extra_window_keybindings [] = { #ifdef HAVE_X11_XF86KEYSYM_H { XF86XK_AddFavorite, NEMO_ACTION_ADD_BOOKMARK }, { XF86XK_Favorites, NEMO_ACTION_EDIT_BOOKMARKS }, { XF86XK_Go, NEMO_ACTION_EDIT_LOCATION }, { XF86XK_HomePage, NEMO_ACTION_GO_HOME }, { XF86XK_OpenURL, NEMO_ACTION_EDIT_LOCATION }, { XF86XK_Refresh, NEMO_ACTION_RELOAD }, { XF86XK_Reload, NEMO_ACTION_RELOAD }, { XF86XK_Search, NEMO_ACTION_SEARCH }, { XF86XK_Start, NEMO_ACTION_GO_HOME }, { XF86XK_Stop, NEMO_ACTION_STOP }, { XF86XK_ZoomIn, NEMO_ACTION_ZOOM_IN }, { XF86XK_ZoomOut, NEMO_ACTION_ZOOM_OUT }, { XF86XK_Back, NEMO_ACTION_BACK }, { XF86XK_Forward, NEMO_ACTION_FORWARD } #endif }; void nemo_window_push_status (NemoWindow *window, const char *text) { g_return_if_fail (NEMO_IS_WINDOW (window)); /* clear any previous message, underflow is allowed */ gtk_statusbar_pop (GTK_STATUSBAR (window->details->statusbar), 0); if (text != NULL && text[0] != '\0') { gtk_statusbar_push (GTK_STATUSBAR (window->details->statusbar), 0, text); } } void nemo_window_go_to (NemoWindow *window, GFile *location) { g_return_if_fail (NEMO_IS_WINDOW (window)); nemo_window_slot_open_location (nemo_window_get_active_slot (window), location, 0); } void nemo_window_go_to_tab (NemoWindow *window, GFile *location) { g_return_if_fail (NEMO_IS_WINDOW (window)); nemo_window_slot_open_location (nemo_window_get_active_slot (window), location, NEMO_WINDOW_OPEN_FLAG_NEW_TAB); } void nemo_window_go_to_full (NemoWindow *window, GFile *location, NemoWindowGoToCallback callback, gpointer user_data) { g_return_if_fail (NEMO_IS_WINDOW (window)); nemo_window_slot_open_location_full (nemo_window_get_active_slot (window), location, 0, NULL, callback, user_data); } static void nemo_window_go_up_signal (NemoWindow *window) { nemo_window_slot_go_up (nemo_window_get_active_slot (window), 0); } void nemo_window_slot_removed (NemoWindow *window, NemoWindowSlot *slot) { g_signal_emit (window, signals[SLOT_REMOVED], 0, slot); } void nemo_window_slot_added (NemoWindow *window, NemoWindowSlot *slot) { g_signal_emit (window, signals[SLOT_ADDED], 0, slot); } void nemo_window_new_tab (NemoWindow *window) { NemoWindowSlot *current_slot; NemoWindowSlot *new_slot; NemoWindowOpenFlags flags; GFile *location; int new_slot_position; char *scheme; current_slot = nemo_window_get_active_slot (window); location = nemo_window_slot_get_location (current_slot); if (location != NULL) { flags = 0; new_slot_position = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_NEW_TAB_POSITION); if (new_slot_position == NEMO_NEW_TAB_POSITION_END) { flags = NEMO_WINDOW_OPEN_SLOT_APPEND; } scheme = g_file_get_uri_scheme (location); if (!strcmp (scheme, "x-nemo-search")) { g_object_unref (location); location = g_file_new_for_path (g_get_home_dir ()); } g_free (scheme); new_slot = nemo_window_pane_open_slot (current_slot->pane, flags); nemo_window_set_active_slot (window, new_slot); nemo_window_slot_open_location (new_slot, location, 0); g_object_unref (location); } } static void update_cursor (NemoWindow *window) { NemoWindowSlot *slot; GdkCursor *cursor; slot = nemo_window_get_active_slot (window); if (slot && slot->allow_stop) { cursor = gdk_cursor_new (GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor); g_object_unref (cursor); } else { gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL); } } void nemo_window_sync_allow_stop (NemoWindow *window, NemoWindowSlot *slot) { GtkAction *stop_action; GtkAction *reload_action; gboolean allow_stop, slot_is_active; NemoNotebook *notebook; stop_action = gtk_action_group_get_action (nemo_window_get_main_action_group (window), NEMO_ACTION_STOP); reload_action = gtk_action_group_get_action (nemo_window_get_main_action_group (window), NEMO_ACTION_RELOAD); allow_stop = gtk_action_get_sensitive (stop_action); slot_is_active = (slot == nemo_window_get_active_slot (window)); if (!slot_is_active || allow_stop != slot->allow_stop) { if (slot_is_active) { gtk_action_set_visible (stop_action, slot->allow_stop); gtk_action_set_visible (reload_action, !slot->allow_stop); } if (gtk_widget_get_realized (GTK_WIDGET (window))) { update_cursor (window); } notebook = NEMO_NOTEBOOK (slot->pane->notebook); nemo_notebook_sync_loading (notebook, slot); } } static void nemo_window_prompt_for_location (NemoWindow *window, const char *initial) { NemoWindowPane *pane; g_return_if_fail (NEMO_IS_WINDOW (window)); if (initial) { nemo_window_show_location_entry(window); pane = window->details->active_pane; nemo_location_bar_set_location (NEMO_LOCATION_BAR (pane->location_bar), initial); } } /* Code should never force the window taller than this size. * (The user can still stretch the window taller if desired). */ static guint get_max_forced_height (GdkScreen *screen) { return (gdk_screen_get_height (screen) * 90) / 100; } /* Code should never force the window wider than this size. * (The user can still stretch the window wider if desired). */ static guint get_max_forced_width (GdkScreen *screen) { return (gdk_screen_get_width (screen) * 90) / 100; } /* This must be called when construction of NemoWindow is finished, * since it depends on the type of the argument, which isn't decided at * construction time. */ static void nemo_window_set_initial_window_geometry (NemoWindow *window) { GdkScreen *screen; guint max_width_for_screen, max_height_for_screen; guint default_width, default_height; screen = gtk_window_get_screen (GTK_WINDOW (window)); max_width_for_screen = get_max_forced_width (screen); max_height_for_screen = get_max_forced_height (screen); default_width = NEMO_WINDOW_DEFAULT_WIDTH; default_height = NEMO_WINDOW_DEFAULT_HEIGHT; gtk_window_set_default_size (GTK_WINDOW (window), MIN (default_width, max_width_for_screen), MIN (default_height, max_height_for_screen)); } static gboolean save_sidebar_width_cb (gpointer user_data) { NemoWindow *window = user_data; window->details->sidebar_width_handler_id = 0; DEBUG ("Saving sidebar width: %d", window->details->side_pane_width); g_settings_set_int (nemo_window_state, NEMO_WINDOW_STATE_SIDEBAR_WIDTH, window->details->side_pane_width); return FALSE; } /* side pane helpers */ static void side_pane_size_allocate_callback (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data) { NemoWindow *window; window = user_data; if (window->details->sidebar_width_handler_id != 0) { g_source_remove (window->details->sidebar_width_handler_id); window->details->sidebar_width_handler_id = 0; } if (allocation->width != window->details->side_pane_width && allocation->width > 1) { window->details->side_pane_width = allocation->width; window->details->sidebar_width_handler_id = g_timeout_add (100, save_sidebar_width_cb, window); } } static void setup_side_pane_width (NemoWindow *window) { g_return_if_fail (window->details->sidebar != NULL); window->details->side_pane_width = g_settings_get_int (nemo_window_state, NEMO_WINDOW_STATE_SIDEBAR_WIDTH); gtk_paned_set_position (GTK_PANED (window->details->content_paned), window->details->side_pane_width); } static void nemo_window_set_up_sidebar (NemoWindow *window) { GtkWidget *sidebar; DEBUG ("Setting up sidebar id %s", window->details->sidebar_id); window->details->sidebar = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_style_context_add_class (gtk_widget_get_style_context (window->details->sidebar), GTK_STYLE_CLASS_SIDEBAR); gtk_paned_pack1 (GTK_PANED (window->details->content_paned), GTK_WIDGET (window->details->sidebar), FALSE, FALSE); setup_side_pane_width (window); g_signal_connect (window->details->sidebar, "size_allocate", G_CALLBACK (side_pane_size_allocate_callback), window); g_signal_connect_object (NEMO_WINDOW (window), "notify::sidebar-view-id", G_CALLBACK (side_pane_id_changed), window, 0); if (g_strcmp0 (window->details->sidebar_id, NEMO_WINDOW_SIDEBAR_PLACES) == 0) { sidebar = nemo_places_sidebar_new (window); } else if (g_strcmp0 (window->details->sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0) { sidebar = nemo_tree_sidebar_new (window); } else { g_assert_not_reached (); } gtk_box_pack_start (GTK_BOX (window->details->sidebar), sidebar, TRUE, TRUE, 0); gtk_widget_show (sidebar); gtk_widget_show (GTK_WIDGET (window->details->sidebar)); } static void nemo_window_tear_down_sidebar (NemoWindow *window) { DEBUG ("Destroying sidebar"); g_signal_handlers_disconnect_by_func (NEMO_WINDOW (window), side_pane_id_changed, window); if (window->details->sidebar != NULL) { gtk_widget_destroy (GTK_WIDGET (window->details->sidebar)); window->details->sidebar = NULL; } } void nemo_window_hide_sidebar (NemoWindow *window) { DEBUG ("Called hide_sidebar()"); if (window->details->sidebar == NULL) { return; } nemo_window_tear_down_sidebar (window); nemo_window_update_show_hide_menu_items (window); nemo_window_set_show_sidebar (window, FALSE); } void nemo_window_show_sidebar (NemoWindow *window) { DEBUG ("Called show_sidebar()"); if (window->details->sidebar != NULL) { return; } if (window->details->disable_chrome) { return; } nemo_window_set_up_sidebar (window); nemo_window_update_show_hide_menu_items (window); nemo_window_set_show_sidebar (window, TRUE); } static gboolean sidebar_id_is_valid (const gchar *sidebar_id) { return (g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_PLACES) == 0 || g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0); } static void side_pane_id_changed (NemoWindow *window) { if (!sidebar_id_is_valid (window->details->sidebar_id)) { return; } /* refresh the sidebar setting */ nemo_window_tear_down_sidebar (window); nemo_window_set_up_sidebar (window); } gboolean nemo_window_disable_chrome_mapping (GValue *value, GVariant *variant, gpointer user_data) { NemoWindow *window = user_data; g_value_set_boolean (value, g_variant_get_boolean (variant) && !window->details->disable_chrome); return TRUE; } static gboolean on_button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { NemoWindow *window = NEMO_WINDOW (user_data); if (event->button == 3) { toggle_menubar (window, MENU_TOGGLE); } return GDK_EVENT_STOP; } static void clear_menu_hide_delay (NemoWindow *window) { if (window->details->menu_hide_delay_id > 0) { g_source_remove (window->details->menu_hide_delay_id); } window->details->menu_hide_delay_id = 0; } static gboolean hide_menu_on_delay (NemoWindow *window) { toggle_menubar (window, MENU_HIDE); window->details->menu_hide_delay_id = 0; return FALSE; } static gboolean on_menu_focus_out (GtkWidget *widget, GdkEvent *event, gpointer user_data) { NemoWindow *window = NEMO_WINDOW (user_data); /* The menu, when visible on demand, gets the keyboard grab. * If the user clicks on some element in the window,, we want the menu * to disappear, but if it's done immediately, everything shifts up the * height of the menu, and the user will more than likely end up clicking * in the wrong spot. Delay the hide momentarily, to allow the user to * complete their click action. */ clear_menu_hide_delay (window); window->details->menu_hide_delay_id = g_timeout_add (200, (GSourceFunc) hide_menu_on_delay, window); return GDK_EVENT_PROPAGATE; } static void nemo_window_constructed (GObject *self) { NemoWindow *window; GtkWidget *grid; GtkWidget *menu; GtkWidget *hpaned; GtkWidget *vbox; GtkWidget *toolbar_holder; GtkWidget *nemo_statusbar; NemoWindowPane *pane; NemoWindowSlot *slot; NemoApplication *application; window = NEMO_WINDOW (self); application = nemo_application_get_singleton (); G_OBJECT_CLASS (nemo_window_parent_class)->constructed (self); gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (application)); /* disable automatic menubar handling, since we show our regular * menubar together with the app menu. */ gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (self), FALSE); grid = gtk_grid_new (); gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); gtk_widget_show (grid); gtk_container_add (GTK_CONTAINER (window), grid); /* Statusbar is packed in the subclasses */ nemo_window_initialize_menus (window); nemo_window_initialize_actions (window); menu = gtk_ui_manager_get_widget (window->details->ui_manager, "/MenuBar"); window->details->menubar = menu; gtk_widget_set_can_focus (menu, TRUE); gtk_widget_set_hexpand (menu, TRUE); g_signal_connect_object (menu, "focus-out-event", G_CALLBACK (on_menu_focus_out), window, 0); if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR)){ gtk_widget_show (menu); } else { gtk_widget_hide (menu); } g_settings_bind_with_mapping (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR, window->details->menubar, "visible", G_SETTINGS_BIND_GET, nemo_window_disable_chrome_mapping, NULL, window, NULL); gtk_container_add (GTK_CONTAINER (grid), menu); /* Set up the toolbar place holder */ toolbar_holder = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add (GTK_CONTAINER (grid), toolbar_holder); gtk_widget_show (toolbar_holder); g_signal_connect_object (toolbar_holder, "button-press-event", G_CALLBACK (on_button_press_callback), window, 0); window->details->toolbar_holder = toolbar_holder; /* Register to menu provider extension signal managing menu updates */ g_signal_connect_object (nemo_signaller_get_current (), "popup_menu_changed", G_CALLBACK (nemo_window_load_extension_menus), window, G_CONNECT_SWAPPED); window->details->content_paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); gtk_widget_set_hexpand (window->details->content_paned, TRUE); gtk_widget_set_vexpand (window->details->content_paned, TRUE); gtk_container_add (GTK_CONTAINER (grid), window->details->content_paned); gtk_widget_show (window->details->content_paned); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_paned_pack2 (GTK_PANED (window->details->content_paned), vbox, TRUE, FALSE); gtk_widget_show (vbox); hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0); gtk_widget_show (hpaned); window->details->split_view_hpane = hpaned; pane = nemo_window_pane_new (window); window->details->panes = g_list_prepend (window->details->panes, pane); gtk_paned_pack1 (GTK_PANED (hpaned), GTK_WIDGET (pane), TRUE, FALSE); nemo_statusbar = nemo_status_bar_new (window); window->details->nemo_status_bar = nemo_statusbar; GtkWidget *sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_container_add (GTK_CONTAINER (grid), sep); gtk_widget_show (sep); GtkWidget *eb; eb = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (eb), nemo_statusbar); gtk_container_add (GTK_CONTAINER (grid), eb); gtk_widget_show (eb); window->details->statusbar = nemo_status_bar_get_real_statusbar (NEMO_STATUS_BAR (nemo_statusbar)); window->details->help_message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->details->statusbar), "help_message"); gtk_widget_add_events (GTK_WIDGET (eb), GDK_BUTTON_PRESS_MASK); g_signal_connect_object (GTK_WIDGET (eb), "button-press-event", G_CALLBACK (on_button_press_callback), window, 0); g_settings_bind_with_mapping (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_STATUS_BAR, window->details->nemo_status_bar, "visible", G_SETTINGS_BIND_DEFAULT, nemo_window_disable_chrome_mapping, NULL, window, NULL); g_object_bind_property (window->details->nemo_status_bar, "visible", sep, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); /* this has to be done after the location bar has been set up, * but before menu stuff is being called */ nemo_window_set_active_pane (window, pane); side_pane_id_changed (window); nemo_window_initialize_bookmarks_menu (window); nemo_window_set_initial_window_geometry (window); slot = nemo_window_pane_open_slot (window->details->active_pane, 0); nemo_window_set_active_slot (window, slot); if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_START_WITH_DUAL_PANE) && !window->details->disable_chrome) nemo_window_split_view_on (window); } static void nemo_window_set_property (GObject *object, guint arg_id, const GValue *value, GParamSpec *pspec) { NemoWindow *window; window = NEMO_WINDOW (object); switch (arg_id) { case PROP_DISABLE_CHROME: window->details->disable_chrome = g_value_get_boolean (value); break; case PROP_SIDEBAR_VIEW_TYPE: window->details->sidebar_id = g_strdup (g_value_get_string (value)); break; case PROP_SHOW_SIDEBAR: nemo_window_set_show_sidebar (window, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec); break; } } static void nemo_window_get_property (GObject *object, guint arg_id, GValue *value, GParamSpec *pspec) { NemoWindow *window; window = NEMO_WINDOW (object); switch (arg_id) { case PROP_DISABLE_CHROME: g_value_set_boolean (value, window->details->disable_chrome); break; case PROP_SIDEBAR_VIEW_TYPE: g_value_set_string (value, window->details->sidebar_id); break; case PROP_SHOW_SIDEBAR: g_value_set_boolean (value, window->details->show_sidebar); break; default: g_assert_not_reached (); break; } } static void destroy_panes_foreach (gpointer data, gpointer user_data) { NemoWindowPane *pane = data; NemoWindow *window = user_data; nemo_window_close_pane (window, pane); } static void nemo_window_destroy (GtkWidget *object) { NemoWindow *window; GList *panes_copy; window = NEMO_WINDOW (object); DEBUG ("Destroying window"); /* close the sidebar first */ nemo_window_tear_down_sidebar (window); /* close all panes safely */ panes_copy = g_list_copy (window->details->panes); g_list_foreach (panes_copy, (GFunc) destroy_panes_foreach, window); g_list_free (panes_copy); /* the panes list should now be empty */ g_assert (window->details->panes == NULL); g_assert (window->details->active_pane == NULL); GTK_WIDGET_CLASS (nemo_window_parent_class)->destroy (object); } static void nemo_window_finalize (GObject *object) { NemoWindow *window; window = NEMO_WINDOW (object); if (window->details->sidebar_width_handler_id != 0) { g_source_remove (window->details->sidebar_width_handler_id); window->details->sidebar_width_handler_id = 0; } g_signal_handlers_disconnect_by_func (nemo_preferences, nemo_window_sync_thumbnail_action, window); clear_menu_hide_delay (window); nemo_window_finalize_menus (window); g_clear_object (&window->details->nav_state); g_clear_object (&window->details->ui_manager); g_free (window->details->sidebar_id); /* nemo_window_close() should have run */ g_assert (window->details->panes == NULL); G_OBJECT_CLASS (nemo_window_parent_class)->finalize (object); } void nemo_window_view_visible (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; NemoWindowPane *pane; GList *l, *walk; g_return_if_fail (NEMO_IS_WINDOW (window)); slot = nemo_window_get_slot_for_view (window, view); if (slot->visible) { return; } slot->visible = TRUE; pane = slot->pane; if (gtk_widget_get_visible (GTK_WIDGET (pane))) { return; } /* Look for other non-visible slots */ for (l = pane->slots; l != NULL; l = l->next) { slot = l->data; if (!slot->visible) { return; } } /* None, this pane is visible */ gtk_widget_show (GTK_WIDGET (pane)); /* Look for other non-visible panes */ for (walk = window->details->panes; walk; walk = walk->next) { pane = walk->data; if (!gtk_widget_get_visible (GTK_WIDGET (pane))) { return; } for (l = pane->slots; l != NULL; l = l->next) { slot = l->data; nemo_window_slot_update_title (slot); nemo_window_slot_update_icon (slot); } } nemo_window_pane_grab_focus (window->details->active_pane); /* All slots and panes visible, show window */ gtk_widget_show (GTK_WIDGET (window)); } static gboolean nemo_window_is_desktop (NemoWindow *window) { return window->details->disable_chrome; } static void nemo_window_save_geometry (NemoWindow *window) { char *geometry_string; gboolean is_maximized; g_assert (NEMO_IS_WINDOW (window)); if (gtk_widget_get_window (GTK_WIDGET (window)) && !nemo_window_is_desktop (window)) { geometry_string = eel_gtk_window_get_geometry_string (GTK_WINDOW (window)); is_maximized = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window))) & GDK_WINDOW_STATE_MAXIMIZED; if (!is_maximized) { g_settings_set_string (nemo_window_state, NEMO_WINDOW_STATE_GEOMETRY, geometry_string); } g_free (geometry_string); g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_MAXIMIZED, is_maximized); } } void nemo_window_close (NemoWindow *window) { NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->close (window); } void nemo_window_close_pane (NemoWindow *window, NemoWindowPane *pane) { g_assert (NEMO_IS_WINDOW_PANE (pane)); while (pane->slots != NULL) { NemoWindowSlot *slot = pane->slots->data; nemo_window_pane_remove_slot_unsafe (pane, slot); } /* If the pane was active, set it to NULL. The caller is responsible * for setting a new active pane with nemo_window_set_active_pane() * if it wants to continue using the window. */ if (window->details->active_pane == pane) { window->details->active_pane = NULL; } /* Required really. Destroying the NemoWindowPane still leaves behind the toolbar. * This kills it off. Do it before we call gtk_widget_destroy for safety. */ gtk_container_remove (GTK_CONTAINER (window->details->toolbar_holder), GTK_WIDGET (pane->tool_bar)); window->details->panes = g_list_remove (window->details->panes, pane); gtk_widget_destroy (GTK_WIDGET (pane)); } NemoWindowPane* nemo_window_get_active_pane (NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); return window->details->active_pane; } static void real_set_active_pane (NemoWindow *window, NemoWindowPane *new_pane) { /* make old pane inactive, and new one active. * Currently active pane may be NULL (after init). */ if (window->details->active_pane && window->details->active_pane != new_pane) { nemo_window_pane_set_active (window->details->active_pane, FALSE); } nemo_window_pane_set_active (new_pane, TRUE); window->details->active_pane = new_pane; } /* Make the given pane the active pane of its associated window. This * always implies making the containing active slot the active slot of * the window. */ void nemo_window_set_active_pane (NemoWindow *window, NemoWindowPane *new_pane) { g_assert (NEMO_IS_WINDOW_PANE (new_pane)); DEBUG ("Setting new pane %p as active", new_pane); if (new_pane->active_slot) { nemo_window_set_active_slot (window, new_pane->active_slot); } else if (new_pane != window->details->active_pane) { real_set_active_pane (window, new_pane); } } /* Make both, the given slot the active slot and its corresponding * pane the active pane of the associated window. * new_slot may be NULL. */ void nemo_window_set_active_slot (NemoWindow *window, NemoWindowSlot *new_slot) { NemoWindowSlot *old_slot; g_assert (NEMO_IS_WINDOW (window)); DEBUG ("Setting new slot %p as active", new_slot); if (new_slot) { g_assert ((window == nemo_window_slot_get_window (new_slot))); g_assert (NEMO_IS_WINDOW_PANE (new_slot->pane)); g_assert (g_list_find (new_slot->pane->slots, new_slot) != NULL); } old_slot = nemo_window_get_active_slot (window); if (old_slot == new_slot) { return; } /* make old slot inactive if it exists (may be NULL after init, for example) */ if (old_slot != NULL) { /* inform window */ if (old_slot->content_view != NULL) { nemo_window_disconnect_content_view (window, old_slot->content_view); } gtk_widget_hide (GTK_WIDGET (old_slot->pane->tool_bar)); /* inform slot & view */ g_signal_emit_by_name (old_slot, "inactive"); } /* deal with panes */ if (new_slot && new_slot->pane != window->details->active_pane) { real_set_active_pane (window, new_slot->pane); } window->details->active_pane->active_slot = new_slot; /* make new slot active, if it exists */ if (new_slot) { /* inform sidebar panels */ nemo_window_report_location_change (window); /* TODO decide whether "selection-changed" should be emitted */ if (new_slot->content_view != NULL) { /* inform window */ nemo_window_connect_content_view (window, new_slot->content_view); } // Show active toolbar gboolean show_toolbar; show_toolbar = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR); if ( show_toolbar) { gtk_widget_show (GTK_WIDGET (new_slot->pane->tool_bar)); } /* inform slot & view */ g_signal_emit_by_name (new_slot, "active"); } } static void nemo_window_realize (GtkWidget *widget) { GTK_WIDGET_CLASS (nemo_window_parent_class)->realize (widget); update_cursor (NEMO_WINDOW (widget)); } static void toggle_menubar (NemoWindow *window, gint action) { GtkWidget *menu; gboolean default_visible; default_visible = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR); if (default_visible || window->details->disable_chrome) { return; } menu = window->details->menubar; if (action == MENU_TOGGLE) { action = gtk_widget_get_visible (menu) ? MENU_HIDE : MENU_SHOW; } if (action == MENU_HIDE) { gtk_widget_hide (menu); } else { gtk_widget_show (menu); /* When the menu is normally hidden, have an activation of it trigger a key grab. * For keyboard users, this is a natural progression, that they will type a mnemonic * next to open a menu. Any loss of focus or click elsewhere will re-hide the menu * and cancel focus. */ gtk_widget_grab_focus (menu); gtk_window_set_mnemonics_visible (GTK_WINDOW (window), TRUE); } return; } static gboolean is_alt_key_event (GdkEventKey *event) { GdkModifierType nominal_state; gboolean state_ok; nominal_state = event->state & gtk_accelerator_get_default_mod_mask(); /* A key press of alt will show just the alt keyval (GDK_KEY_Alt_L/R). A key release * of a single modifier is always modified by itself. So a valid press state is 0 and * a valid release state is GDK_MOD1_MASK (alt modifier). */ state_ok = (event->type == GDK_KEY_PRESS && nominal_state == 0) || (event->type == GDK_KEY_RELEASE && nominal_state == GDK_MOD1_MASK); if (state_ok && (event->keyval == GDK_KEY_Alt_L || event->keyval == GDK_KEY_Alt_R)) { return TRUE; } return FALSE; } static gboolean nemo_window_key_press_event (GtkWidget *widget, GdkEventKey *event) { NemoWindow *window; NemoWindowSlot *active_slot; NemoView *view; GtkWidget *focus_widget; size_t i; window = NEMO_WINDOW (widget); active_slot = nemo_window_get_active_slot (window); view = active_slot->content_view; if (view != NULL && nemo_view_get_is_renaming (view)) { /* if we're renaming, just forward the event to the * focused widget and return. We don't want to process the window * accelerator bindings, as they might conflict with the * editable widget bindings. */ if (gtk_window_propagate_key_event (GTK_WINDOW (window), event)) { return TRUE; } } focus_widget = gtk_window_get_focus (GTK_WINDOW (window)); if (view != NULL && focus_widget != NULL && GTK_IS_EDITABLE (focus_widget)) { /* if we have input focus on a GtkEditable (e.g. a GtkEntry), forward * the event to it before activating accelerator bindings too. */ if (gtk_window_propagate_key_event (GTK_WINDOW (window), event)) { return TRUE; } } for (i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++) { if (extra_window_keybindings[i].keyval == event->keyval) { const GList *action_groups; GtkAction *action; action = NULL; action_groups = gtk_ui_manager_get_action_groups (window->details->ui_manager); while (action_groups != NULL && action == NULL) { action = gtk_action_group_get_action (action_groups->data, extra_window_keybindings[i].action); action_groups = action_groups->next; } g_assert (action != NULL); if (gtk_action_is_sensitive (action)) { gtk_action_activate (action); return TRUE; } break; } } /* An alt key press by itself will always hide the menu if it's visible. We set a flag * to skip the subsequent release, otherwise we'll show the menu again. * * When alt is pressed and the menu is NOT visible, we flag that on release we'll show the * menu. If any other keys are pressed between alt being pressed and released, we clear that * flag, because it was more than likely part of some other shortcut, and otherwise, depending * on the order the keys are released, if the alt key is last to be released, we don't want to * show the menu, as that was not the original intent. */ if (is_alt_key_event (event)) { if (gtk_widget_get_visible (window->details->menubar)) { toggle_menubar (window, MENU_HIDE); window->details->menu_skip_release = TRUE; } else { window->details->menu_show_queued = TRUE; } } else { window->details->menu_show_queued = FALSE; } return GTK_WIDGET_CLASS (nemo_window_parent_class)->key_press_event (widget, event); } static gboolean nemo_window_key_release_event (GtkWidget *widget, GdkEventKey *event) { NemoWindow *window = NEMO_WINDOW (widget); /* Conditions to show the menu via the alt key is that it must have been pressed and * released without any other key events in between, and we must not have hidden the * menu on the alt key press event. Show we check both flags here, for opposing states. */ if (is_alt_key_event (event)) { if (!window->details->menu_skip_release && window->details->menu_show_queued) { toggle_menubar (window, MENU_SHOW); } } window->details->menu_skip_release = FALSE; window->details->menu_show_queued = FALSE; return GTK_WIDGET_CLASS (nemo_window_parent_class)->key_release_event (widget, event); } /* * Main API */ static void sync_view_type_callback (NemoFile *file, gpointer callback_data) { NemoWindow *window; NemoWindowSlot *slot; slot = callback_data; window = nemo_window_slot_get_window (slot); if (slot == nemo_window_get_active_slot (window)) { NemoWindowPane *pane; const gchar *view_id; if (slot->content_view == NULL) { return; } pane = nemo_window_get_active_pane(window); view_id = nemo_window_slot_get_content_view_id (slot); toolbar_set_view_button (action_for_view_id (view_id), pane); menu_set_view_selection (action_for_view_id (view_id), window); } } static void cancel_sync_view_type_callback (NemoWindowSlot *slot) { nemo_file_cancel_call_when_ready (slot->viewed_file, sync_view_type_callback, slot); } void nemo_window_sync_view_type (NemoWindow *window) { NemoWindowSlot *slot; NemoFileAttributes attributes; g_return_if_fail (NEMO_IS_WINDOW (window)); attributes = nemo_mime_actions_get_required_file_attributes (); slot = nemo_window_get_active_slot (window); cancel_sync_view_type_callback (slot); nemo_file_call_when_ready (slot->viewed_file, attributes, sync_view_type_callback, slot); } void nemo_window_sync_menu_bar (NemoWindow *window) { GtkWidget *menu = window->details->menubar; if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR) && !window->details->disable_chrome) { gtk_widget_show (menu); } else { gtk_widget_hide (menu); } } void nemo_window_sync_up_button (NemoWindow *window) { GtkAction *action; GtkActionGroup *action_group; NemoWindowSlot *slot; gboolean allowed; GFile *parent; slot = nemo_window_get_active_slot (window); allowed = FALSE; if (slot->location != NULL) { parent = g_file_get_parent (slot->location); allowed = parent != NULL; g_clear_object (&parent); } action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, NEMO_ACTION_UP); gtk_action_set_sensitive (action, allowed); action = gtk_action_group_get_action (action_group, NEMO_ACTION_UP_ACCEL); gtk_action_set_sensitive (action, allowed); } void nemo_window_sync_title (NemoWindow *window, NemoWindowSlot *slot) { NemoWindowPane *pane; NemoNotebook *notebook; char *full_title; char *window_title; if (NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->sync_title != NULL) { NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->sync_title (window, slot); return; } if (slot == nemo_window_get_active_slot (window)) { /* if spatial mode is default, we keep "File Browser" in the window title * to recognize browser windows. Otherwise, we default to the directory name. */ if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) { full_title = g_strdup_printf (_("%s - File Browser"), slot->title); window_title = eel_str_middle_truncate (full_title, MAX_TITLE_LENGTH); g_free (full_title); } else { window_title = eel_str_middle_truncate (slot->title, MAX_TITLE_LENGTH); } gtk_window_set_title (GTK_WINDOW (window), window_title); g_free (window_title); } pane = slot->pane; notebook = NEMO_NOTEBOOK (pane->notebook); nemo_notebook_sync_tab_label (notebook, slot); } void nemo_window_sync_zoom_widgets (NemoWindow *window) { NemoWindowSlot *slot; NemoView *view; GtkActionGroup *action_group; GtkAction *action; gboolean supports_zooming; gboolean can_zoom, can_zoom_in, can_zoom_out; NemoZoomLevel zoom_level; slot = nemo_window_get_active_slot (window); view = slot->content_view; if (view != NULL) { supports_zooming = nemo_view_supports_zooming (view); zoom_level = nemo_view_get_zoom_level (view); can_zoom = supports_zooming && zoom_level >= NEMO_ZOOM_LEVEL_SMALLEST && zoom_level <= NEMO_ZOOM_LEVEL_LARGEST; can_zoom_in = can_zoom && nemo_view_can_zoom_in (view); can_zoom_out = can_zoom && nemo_view_can_zoom_out (view); } else { supports_zooming = FALSE; can_zoom = FALSE; can_zoom_in = FALSE; can_zoom_out = FALSE; } action_group = nemo_window_get_main_action_group (window); action = gtk_action_group_get_action (action_group, NEMO_ACTION_ZOOM_IN); gtk_action_set_visible (action, supports_zooming); gtk_action_set_sensitive (action, can_zoom_in); action = gtk_action_group_get_action (action_group, NEMO_ACTION_ZOOM_OUT); gtk_action_set_visible (action, supports_zooming); gtk_action_set_sensitive (action, can_zoom_out); action = gtk_action_group_get_action (action_group, NEMO_ACTION_ZOOM_NORMAL); gtk_action_set_visible (action, supports_zooming); gtk_action_set_sensitive (action, can_zoom); nemo_status_bar_sync_zoom_widgets (NEMO_STATUS_BAR (window->details->nemo_status_bar)); } void nemo_window_sync_bookmark_action (NemoWindow *window) { NemoWindowSlot *slot; GFile *location; GtkAction *action; gchar *uri; slot = nemo_window_get_active_slot (window); location = nemo_window_slot_get_location (slot); if (!location) { return; } uri = g_file_get_uri (location); action = gtk_action_group_get_action (nemo_window_get_main_action_group (window), NEMO_ACTION_ADD_BOOKMARK); gtk_action_set_sensitive (action, !eel_uri_is_search (uri)); g_free (uri); g_object_unref (location); } void sync_thumbnail_action_callback (NemoFile *file, gpointer callback_data) { NemoWindow *window; NemoWindowSlot *slot; slot = callback_data; window = nemo_window_slot_get_window (slot); if (slot == nemo_window_get_active_slot (window)) { NemoWindowPane *pane; gboolean show_thumbnails; pane = nemo_window_get_active_pane(window); show_thumbnails = nemo_file_should_show_thumbnail (file); toolbar_set_show_thumbnails_button (show_thumbnails, pane); menu_set_show_thumbnails_action (show_thumbnails, window); } } static void cancel_sync_show_thumbnail_callback (NemoWindowSlot *slot) { nemo_file_cancel_call_when_ready (slot->viewed_file, sync_thumbnail_action_callback, slot); } void nemo_window_sync_thumbnail_action (NemoWindow *window) { NemoWindowSlot *slot; NemoFileAttributes attributes; g_return_if_fail (NEMO_IS_WINDOW (window)); attributes = nemo_mime_actions_get_required_file_attributes (); slot = nemo_window_get_active_slot (window); cancel_sync_show_thumbnail_callback (slot); nemo_file_call_when_ready (slot->viewed_file, attributes, sync_thumbnail_action_callback, slot); } static void zoom_level_changed_callback (NemoView *view, NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); /* This is called each time the component in * the active slot successfully completed * a zooming operation. */ nemo_window_sync_zoom_widgets (window); } /* These are called * A) when switching the view within the active slot * B) when switching the active slot * C) when closing the active slot (disconnect) */ void nemo_window_connect_content_view (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; g_assert (NEMO_IS_WINDOW (window)); g_assert (NEMO_IS_VIEW (view)); slot = nemo_window_get_slot_for_view (window, view); if (slot != nemo_window_get_active_slot (window)) { return; } g_signal_connect (view, "zoom-level-changed", G_CALLBACK (zoom_level_changed_callback), window); /* Update displayed the selected view type in the toolbar and menu. */ if (slot->pending_location == NULL) { nemo_window_sync_view_type (window); } nemo_view_grab_focus (view); } void nemo_window_disconnect_content_view (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; g_assert (NEMO_IS_WINDOW (window)); g_assert (NEMO_IS_VIEW (view)); slot = nemo_window_get_slot_for_view (window, view); if (slot != nemo_window_get_active_slot (window)) { return; } g_signal_handlers_disconnect_by_func (view, G_CALLBACK (zoom_level_changed_callback), window); } /** * nemo_window_show: * @widget: GtkWidget * * Call parent and then show/hide window items * base on user prefs. */ static void nemo_window_show (GtkWidget *widget) { NemoWindow *window; window = NEMO_WINDOW (widget); window->details->sidebar_id = g_settings_get_string (nemo_window_state, NEMO_WINDOW_STATE_SIDE_PANE_VIEW); if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_SIDEBAR)) { nemo_window_show_sidebar (window); } else { nemo_window_hide_sidebar (window); } GTK_WIDGET_CLASS (nemo_window_parent_class)->show (widget); gtk_ui_manager_ensure_update (window->details->ui_manager); } GtkUIManager * nemo_window_get_ui_manager (NemoWindow *window) { g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL); return window->details->ui_manager; } GtkActionGroup * nemo_window_get_main_action_group (NemoWindow *window) { g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL); return window->details->main_action_group; } NemoNavigationState * nemo_window_get_navigation_state (NemoWindow *window) { g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL); return window->details->nav_state; } NemoWindowPane * nemo_window_get_next_pane (NemoWindow *window) { NemoWindowPane *next_pane; GList *node; /* return NULL if there is only one pane */ if (!window->details->panes || !window->details->panes->next) { return NULL; } /* get next pane in the (wrapped around) list */ node = g_list_find (window->details->panes, window->details->active_pane); g_return_val_if_fail (node, NULL); if (node->next) { next_pane = node->next->data; } else { next_pane = window->details->panes->data; } return next_pane; } void nemo_window_slot_set_viewed_file (NemoWindowSlot *slot, NemoFile *file) { NemoFileAttributes attributes; if (slot->viewed_file == file) { return; } nemo_file_ref (file); cancel_sync_view_type_callback (slot); if (slot->viewed_file != NULL) { nemo_file_monitor_remove (slot->viewed_file, slot); } if (file != NULL) { attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO; nemo_file_monitor_add (file, slot, attributes); } nemo_file_unref (slot->viewed_file); slot->viewed_file = file; } NemoWindowSlot * nemo_window_get_slot_for_view (NemoWindow *window, NemoView *view) { NemoWindowSlot *slot; GList *l, *walk; for (walk = window->details->panes; walk; walk = walk->next) { NemoWindowPane *pane = walk->data; for (l = pane->slots; l != NULL; l = l->next) { slot = l->data; if (slot->content_view == view || slot->new_content_view == view) { return slot; } } } return NULL; } NemoWindowShowHiddenFilesMode nemo_window_get_hidden_files_mode (NemoWindow *window) { return window->details->show_hidden_files_mode; } void nemo_window_set_hidden_files_mode (NemoWindow *window, NemoWindowShowHiddenFilesMode mode) { window->details->show_hidden_files_mode = mode; g_settings_set_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES, mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE); g_signal_emit_by_name (window, "hidden_files_mode_changed"); } NemoWindowSlot * nemo_window_get_active_slot (NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); if (window->details->active_pane == NULL) { return NULL; } return window->details->active_pane->active_slot; } NemoWindowSlot * nemo_window_get_extra_slot (NemoWindow *window) { NemoWindowPane *extra_pane; GList *node; g_assert (NEMO_IS_WINDOW (window)); /* return NULL if there is only one pane */ if (window->details->panes == NULL || window->details->panes->next == NULL) { return NULL; } /* get next pane in the (wrapped around) list */ node = g_list_find (window->details->panes, window->details->active_pane); g_return_val_if_fail (node, FALSE); if (node->next) { extra_pane = node->next->data; } else { extra_pane = window->details->panes->data; } return extra_pane->active_slot; } GList * nemo_window_get_panes (NemoWindow *window) { g_assert (NEMO_IS_WINDOW (window)); return window->details->panes; } static void window_set_search_action_text (NemoWindow *window, gboolean setting) { GtkAction *action; NemoWindowPane *pane; GList *l; for (l = window->details->panes; l != NULL; l = l->next) { pane = l->data; action = gtk_action_group_get_action (pane->action_group, NEMO_ACTION_SEARCH); gtk_action_set_is_important (action, setting); } } static void center_pane_divider (GtkWidget *paned, GParamSpec *pspec, gpointer user_data) { /* Make the paned think it's been manually resized, otherwise * things like the trash bar will force unwanted resizes */ g_object_set (G_OBJECT (paned), "position", gtk_widget_get_allocated_width (paned) / 2, NULL); g_signal_handlers_disconnect_by_func (G_OBJECT (paned), center_pane_divider, NULL); } static NemoWindowSlot * create_extra_pane (NemoWindow *window) { NemoWindowPane *pane; NemoWindowSlot *slot; GtkPaned *paned; /* New pane */ pane = nemo_window_pane_new (window); window->details->panes = g_list_append (window->details->panes, pane); paned = GTK_PANED (window->details->split_view_hpane); g_signal_connect_after (paned, "notify::position", G_CALLBACK(center_pane_divider), NULL); if (gtk_paned_get_child1 (paned) == NULL) { gtk_paned_pack1 (paned, GTK_WIDGET (pane), TRUE, FALSE); } else { gtk_paned_pack2 (paned, GTK_WIDGET (pane), TRUE, FALSE); } /* Ensure the toolbar doesn't pop itself into existence (double toolbars suck.) */ gtk_widget_hide (pane->tool_bar); /* slot */ slot = nemo_window_pane_open_slot (NEMO_WINDOW_PANE (pane), NEMO_WINDOW_OPEN_SLOT_APPEND); pane->active_slot = slot; return slot; } static void nemo_window_reload (NemoWindow *window) { NemoWindowSlot *active_slot; active_slot = nemo_window_get_active_slot (window); nemo_window_slot_queue_reload (active_slot, TRUE); } static gboolean nemo_window_state_event (GtkWidget *widget, GdkEventWindowState *event) { if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && !nemo_window_is_desktop (NEMO_WINDOW (widget))) { g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_MAXIMIZED, event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED); } if (GTK_WIDGET_CLASS (nemo_window_parent_class)->window_state_event != NULL) { return GTK_WIDGET_CLASS (nemo_window_parent_class)->window_state_event (widget, event); } return FALSE; } static gboolean nemo_window_delete_event (GtkWidget *widget, GdkEventAny *event) { nemo_window_close (NEMO_WINDOW (widget)); return FALSE; } static gboolean nemo_window_button_press_event (GtkWidget *widget, GdkEventButton *event) { NemoWindow *window; gboolean handled; window = NEMO_WINDOW (widget); if (mouse_extra_buttons && (event->button == mouse_back_button)) { nemo_window_back_or_forward (window, TRUE, 0, 0); handled = TRUE; } else if (mouse_extra_buttons && (event->button == mouse_forward_button)) { nemo_window_back_or_forward (window, FALSE, 0, 0); handled = TRUE; } else if (GTK_WIDGET_CLASS (nemo_window_parent_class)->button_press_event) { handled = GTK_WIDGET_CLASS (nemo_window_parent_class)->button_press_event (widget, event); } else { handled = FALSE; } return handled; } static void mouse_back_button_changed (gpointer callback_data) { int new_back_button; new_back_button = g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_MOUSE_BACK_BUTTON); /* Bounds checking */ if (new_back_button < 6 || new_back_button > UPPER_MOUSE_LIMIT) return; mouse_back_button = new_back_button; } static void mouse_forward_button_changed (gpointer callback_data) { int new_forward_button; new_forward_button = g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_MOUSE_FORWARD_BUTTON); /* Bounds checking */ if (new_forward_button < 6 || new_forward_button > UPPER_MOUSE_LIMIT) return; mouse_forward_button = new_forward_button; } static void use_extra_mouse_buttons_changed (gpointer callback_data) { mouse_extra_buttons = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS); } /* * Main API */ static void nemo_window_init (NemoWindow *window) { GtkWindowGroup *window_group; window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_WINDOW, NemoWindowDetails); window->details->panes = NULL; window->details->active_pane = NULL; gboolean show_hidden = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES); window->details->show_hidden_files_mode = show_hidden ? NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE : NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE; window->details->show_sidebar = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_SIDEBAR); window->details->menu_skip_release = FALSE; window->details->menu_show_queued = FALSE; window->details->ignore_meta_view_id = NULL; window->details->ignore_meta_zoom_level = -1; window->details->ignore_meta_visible_columns = NULL; window->details->ignore_meta_column_order = NULL; window->details->ignore_meta_sort_column = NULL; window->details->ignore_meta_sort_direction = SORT_NULL; /* This makes it possible for GTK+ themes to apply styling that is specific to Nemo * without affecting other GTK+ applications. */ gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "nemo-window"); window_group = gtk_window_group_new (); gtk_window_group_add_window (window_group, GTK_WINDOW (window)); g_object_unref (window_group); /* Set initial window title */ gtk_window_set_title (GTK_WINDOW (window), _("Nemo")); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, G_CALLBACK(nemo_window_sync_thumbnail_action), window); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS, G_CALLBACK(nemo_window_sync_thumbnail_action), window); } static NemoIconInfo * real_get_icon (NemoWindow *window, NemoWindowSlot *slot) { return nemo_file_get_icon (slot->viewed_file, 48, 0, gtk_widget_get_scale_factor (GTK_WIDGET (window)), NEMO_FILE_ICON_FLAGS_IGNORE_VISITING | NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON); } static void real_window_close (NemoWindow *window) { g_return_if_fail (NEMO_IS_WINDOW (window)); nemo_window_save_geometry (window); gtk_widget_destroy (GTK_WIDGET (window)); } static void nemo_window_class_init (NemoWindowClass *class) { GtkBindingSet *binding_set; GObjectClass *oclass = G_OBJECT_CLASS (class); GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class); oclass->finalize = nemo_window_finalize; oclass->constructed = nemo_window_constructed; oclass->get_property = nemo_window_get_property; oclass->set_property = nemo_window_set_property; wclass->destroy = nemo_window_destroy; wclass->show = nemo_window_show; wclass->realize = nemo_window_realize; wclass->key_press_event = nemo_window_key_press_event; wclass->key_release_event = nemo_window_key_release_event; wclass->window_state_event = nemo_window_state_event; wclass->button_press_event = nemo_window_button_press_event; wclass->delete_event = nemo_window_delete_event; class->get_icon = real_get_icon; class->close = real_window_close; properties[PROP_DISABLE_CHROME] = g_param_spec_boolean ("disable-chrome", "Disable chrome", "Disable window chrome, for the desktop", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_SIDEBAR_VIEW_TYPE] = g_param_spec_string ("sidebar-view-id", "Sidebar view type", "Sidebar view type", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_SHOW_SIDEBAR] = g_param_spec_boolean ("show-sidebar", "Show the sidebar", "Show the sidebar", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); signals[GO_UP] = g_signal_new ("go-up", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoWindowClass, go_up), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 0); signals[RELOAD] = g_signal_new ("reload", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoWindowClass, reload), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PROMPT_FOR_LOCATION] = g_signal_new ("prompt-for-location", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NemoWindowClass, prompt_for_location), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals[HIDDEN_FILES_MODE_CHANGED] = g_signal_new ("hidden_files_mode_changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[LOADING_URI] = g_signal_new ("loading_uri", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals[SLOT_ADDED] = g_signal_new ("slot-added", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NEMO_TYPE_WINDOW_SLOT); signals[SLOT_REMOVED] = g_signal_new ("slot-removed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NEMO_TYPE_WINDOW_SLOT); binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "go-up", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_F5, 0, "reload", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0, "prompt-for-location", 1, G_TYPE_STRING, "/"); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0, "prompt-for-location", 1, G_TYPE_STRING, "/"); gtk_binding_entry_add_signal (binding_set, GDK_KEY_asciitilde, 0, "prompt-for-location", 1, G_TYPE_STRING, "~"); class->reload = nemo_window_reload; class->go_up = nemo_window_go_up_signal; class->prompt_for_location = nemo_window_prompt_for_location; g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_MOUSE_BACK_BUTTON, G_CALLBACK(mouse_back_button_changed), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_MOUSE_FORWARD_BUTTON, G_CALLBACK(mouse_forward_button_changed), NULL); g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS, G_CALLBACK(use_extra_mouse_buttons_changed), NULL); g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); g_type_class_add_private (oclass, sizeof (NemoWindowDetails)); } NemoWindow * nemo_window_new (GtkApplication *application, GdkScreen *screen) { return g_object_new (NEMO_TYPE_WINDOW, "application", application, "screen", screen, NULL); } void nemo_window_split_view_on (NemoWindow *window) { NemoWindowSlot *slot, *old_active_slot; GFile *location; old_active_slot = nemo_window_get_active_slot (window); slot = create_extra_pane (window); location = NULL; if (old_active_slot != NULL) { location = nemo_window_slot_get_location (old_active_slot); if (location != NULL) { if (g_file_has_uri_scheme (location, "x-nemo-search")) { g_object_unref (location); location = NULL; } } } if (location == NULL) { location = g_file_new_for_path (g_get_home_dir ()); } nemo_window_slot_open_location (slot, location, 0); g_object_unref (location); window_set_search_action_text (window, FALSE); } void nemo_window_split_view_off (NemoWindow *window) { NemoWindowPane *pane, *active_pane; GList *l, *next; active_pane = nemo_window_get_active_pane (window); /* delete all panes except the first (main) pane */ for (l = window->details->panes; l != NULL; l = next) { next = l->next; pane = l->data; if (pane != active_pane) { nemo_window_close_pane (window, pane); } } /* Reset split view pane's position so the position can be * caught again later */ g_object_set (G_OBJECT (window->details->split_view_hpane), "position", 0, "position-set", FALSE, NULL); nemo_window_set_active_pane (window, active_pane); nemo_navigation_state_set_master (window->details->nav_state, active_pane->action_group); nemo_window_update_show_hide_menu_items (window); } gboolean nemo_window_split_view_showing (NemoWindow *window) { return g_list_length (NEMO_WINDOW (window)->details->panes) > 1; } void nemo_window_set_sidebar_id (NemoWindow *window, const gchar *id) { if (g_strcmp0 (id, window->details->sidebar_id) != 0) { g_settings_set_string (nemo_window_state, NEMO_WINDOW_STATE_SIDE_PANE_VIEW, id); g_free (window->details->sidebar_id); window->details->sidebar_id = g_strdup (id); g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_SIDEBAR_VIEW_TYPE]); } } const gchar * nemo_window_get_sidebar_id (NemoWindow *window) { return window->details->sidebar_id; } void nemo_window_set_show_sidebar (NemoWindow *window, gboolean show) { window->details->show_sidebar = show; g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_SIDEBAR, show); g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_SHOW_SIDEBAR]); } gboolean nemo_window_get_show_sidebar (NemoWindow *window) { return window->details->show_sidebar; } const gchar * nemo_window_get_ignore_meta_view_id (NemoWindow *window) { return window->details->ignore_meta_view_id; } void nemo_window_set_ignore_meta_view_id (NemoWindow *window, const gchar *id) { if (id != NULL) { gchar *old_id = window->details->ignore_meta_view_id; if (g_strcmp0 (old_id, id) != 0) { nemo_window_set_ignore_meta_zoom_level (window, -1); } window->details->ignore_meta_view_id = g_strdup (id); g_free (old_id); } } gint nemo_window_get_ignore_meta_zoom_level (NemoWindow *window) { return window->details->ignore_meta_zoom_level; } void nemo_window_set_ignore_meta_zoom_level (NemoWindow *window, gint level) { window->details->ignore_meta_zoom_level = level; } /* FIXME: * * Remove this and just use g_list_copy_deep * when we no longer need to support GLib < 2.34 * */ static GList * list_copy_deep (GList *list, GCopyFunc func, gpointer user_data) { GList *new_list = NULL; if (list) { GList *last; new_list = g_slice_new (GList); if (func) new_list->data = func (list->data, user_data); else new_list->data = list->data; new_list->prev = NULL; last = new_list; list = list->next; while (list) { last->next = g_slice_new (GList); last->next->prev = last; last = last->next; if (func) last->data = func (list->data, user_data); else last->data = list->data; list = list->next; } last->next = NULL; } return new_list; } GList * nemo_window_get_ignore_meta_visible_columns (NemoWindow *window) { return list_copy_deep (window->details->ignore_meta_visible_columns, (GCopyFunc) g_strdup, NULL); } void nemo_window_set_ignore_meta_visible_columns (NemoWindow *window, GList *list) { GList *old = window->details->ignore_meta_visible_columns; window->details->ignore_meta_visible_columns = list != NULL ? list_copy_deep (list, (GCopyFunc) g_strdup, NULL) : NULL; if (old != NULL) g_list_free_full (old, g_free); } GList * nemo_window_get_ignore_meta_column_order (NemoWindow *window) { return list_copy_deep (window->details->ignore_meta_column_order, (GCopyFunc) g_strdup, NULL); } void nemo_window_set_ignore_meta_column_order (NemoWindow *window, GList *list) { GList *old = window->details->ignore_meta_column_order; window->details->ignore_meta_column_order = list != NULL ? list_copy_deep (list, (GCopyFunc) g_strdup, NULL) : NULL; if (old != NULL) g_list_free_full (old, g_free); } const gchar * nemo_window_get_ignore_meta_sort_column (NemoWindow *window) { return window->details->ignore_meta_sort_column; } void nemo_window_set_ignore_meta_sort_column (NemoWindow *window, const gchar *column) { if (column != NULL) { gchar *old_column = window->details->ignore_meta_sort_column; window->details->ignore_meta_sort_column = g_strdup (column); g_free (old_column); } } gint nemo_window_get_ignore_meta_sort_direction (NemoWindow *window) { return window->details->ignore_meta_sort_direction; } void nemo_window_set_ignore_meta_sort_direction (NemoWindow *window, gint direction) { window->details->ignore_meta_sort_direction = direction; } NemoWindowOpenFlags nemo_event_get_window_open_flags (void) { NemoWindowOpenFlags flags = 0; GdkEvent *event; event = gtk_get_current_event (); if (event == NULL) { return flags; } if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) && (event->button.button == 2)) { flags |= NEMO_WINDOW_OPEN_FLAG_NEW_TAB; } gdk_event_free (event); return flags; } nemo-4.4.2/src/nemo-window.h000066400000000000000000000205151357442400300156670ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * Nemo * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * Nemo 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. * * Nemo 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, Suite 500, MA 02110-1335, USA. * * Authors: Elliot Lee * Darin Adler * */ /* nemo-window.h: Interface of the main window object */ #ifndef NEMO_WINDOW_H #define NEMO_WINDOW_H #include #include #include #include #include "nemo-navigation-state.h" #include "nemo-view.h" #include "nemo-window-types.h" #define NEMO_TYPE_WINDOW nemo_window_get_type() #define NEMO_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NEMO_TYPE_WINDOW, NemoWindow)) #define NEMO_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), NEMO_TYPE_WINDOW, NemoWindowClass)) #define NEMO_IS_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NEMO_TYPE_WINDOW)) #define NEMO_IS_WINDOW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), NEMO_TYPE_WINDOW)) #define NEMO_WINDOW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), NEMO_TYPE_WINDOW, NemoWindowClass)) typedef enum { NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE, NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE } NemoWindowShowHiddenFilesMode; typedef enum { NEMO_WINDOW_NOT_SHOWN, NEMO_WINDOW_POSITION_SET, NEMO_WINDOW_SHOULD_SHOW } NemoWindowShowState; typedef enum { NEMO_WINDOW_OPEN_SLOT_NONE = 0, NEMO_WINDOW_OPEN_SLOT_APPEND = 1 } NemoWindowOpenSlotFlags; enum { SORT_NULL = -1, SORT_ASCENDING = 0, SORT_DESCENDING = 1 }; #define NEMO_WINDOW_SIDEBAR_PLACES "places" #define NEMO_WINDOW_SIDEBAR_TREE "tree" typedef struct NemoWindowDetails NemoWindowDetails; typedef struct { GtkApplicationWindowClass parent_spot; /* Function pointers for overriding, without corresponding signals */ void (* sync_title) (NemoWindow *window, NemoWindowSlot *slot); NemoIconInfo * (* get_icon) (NemoWindow *window, NemoWindowSlot *slot); void (* prompt_for_location) (NemoWindow *window, const char *initial); void (* close) (NemoWindow *window); /* Signals used only for keybindings */ void (* go_up) (NemoWindow *window); void (* reload) (NemoWindow *window); } NemoWindowClass; struct NemoWindow { GtkApplicationWindow parent_object; NemoWindowDetails *details; }; GType nemo_window_get_type (void); NemoWindow * nemo_window_new (GtkApplication *application, GdkScreen *screen); void nemo_window_close (NemoWindow *window); void nemo_window_connect_content_view (NemoWindow *window, NemoView *view); void nemo_window_disconnect_content_view (NemoWindow *window, NemoView *view); void nemo_window_go_to (NemoWindow *window, GFile *location); void nemo_window_go_to_tab (NemoWindow *window, GFile *location); void nemo_window_go_to_full (NemoWindow *window, GFile *location, NemoWindowGoToCallback callback, gpointer user_data); void nemo_window_new_tab (NemoWindow *window); GtkUIManager * nemo_window_get_ui_manager (NemoWindow *window); GtkActionGroup * nemo_window_get_main_action_group (NemoWindow *window); NemoNavigationState * nemo_window_get_navigation_state (NemoWindow *window); void nemo_window_report_load_complete (NemoWindow *window, NemoView *view); NemoWindowSlot * nemo_window_get_extra_slot (NemoWindow *window); NemoWindowShowHiddenFilesMode nemo_window_get_hidden_files_mode (NemoWindow *window); void nemo_window_set_hidden_files_mode (NemoWindow *window, NemoWindowShowHiddenFilesMode mode); void nemo_window_report_load_underway (NemoWindow *window, NemoView *view); void nemo_window_view_visible (NemoWindow *window, NemoView *view); GList * nemo_window_get_panes (NemoWindow *window); NemoWindowSlot * nemo_window_get_active_slot (NemoWindow *window); void nemo_window_push_status (NemoWindow *window, const char *text); GtkWidget * nemo_window_ensure_location_bar (NemoWindow *window); void nemo_window_sync_location_widgets (NemoWindow *window); void nemo_window_sync_search_widgets (NemoWindow *window); void nemo_window_grab_focus (NemoWindow *window); void nemo_window_hide_sidebar (NemoWindow *window); void nemo_window_show_sidebar (NemoWindow *window); void nemo_window_back_or_forward (NemoWindow *window, gboolean back, guint distance, NemoWindowOpenFlags flags); void nemo_window_split_view_on (NemoWindow *window); void nemo_window_split_view_off (NemoWindow *window); gboolean nemo_window_split_view_showing (NemoWindow *window); gboolean nemo_window_disable_chrome_mapping (GValue *value, GVariant *variant, gpointer user_data); void nemo_window_set_sidebar_id (NemoWindow *window, const gchar *id); const gchar * nemo_window_get_sidebar_id (NemoWindow *window); void nemo_window_set_show_sidebar (NemoWindow *window, gboolean show); gboolean nemo_window_get_show_sidebar (NemoWindow *window); const gchar *nemo_window_get_ignore_meta_view_id (NemoWindow *window); void nemo_window_set_ignore_meta_view_id (NemoWindow *window, const gchar *id); gint nemo_window_get_ignore_meta_zoom_level (NemoWindow *window); void nemo_window_set_ignore_meta_zoom_level (NemoWindow *window, gint level); GList *nemo_window_get_ignore_meta_visible_columns (NemoWindow *window); void nemo_window_set_ignore_meta_visible_columns (NemoWindow *window, GList *list); GList *nemo_window_get_ignore_meta_column_order (NemoWindow *window); void nemo_window_set_ignore_meta_column_order (NemoWindow *window, GList *list); const gchar *nemo_window_get_ignore_meta_sort_column (NemoWindow *window); void nemo_window_set_ignore_meta_sort_column (NemoWindow *window, const gchar *column); gint nemo_window_get_ignore_meta_sort_direction (NemoWindow *window); void nemo_window_set_ignore_meta_sort_direction (NemoWindow *window, gint direction); NemoWindowOpenFlags nemo_event_get_window_open_flags (void); void nemo_window_slot_added (NemoWindow *window, NemoWindowSlot *slot); void nemo_window_slot_removed (NemoWindow *window, NemoWindowSlot *slot); #endif nemo-4.4.2/src/nemo-x-content-bar.c000066400000000000000000000204641357442400300170370ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2008 Red Hat, Inc. * Copyright (C) 2006 Paolo Borelli * * 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 - Suite 500, Boston, MA 02110-1335, USA. * * Authors: David Zeuthen * Paolo Borelli * */ #include "config.h" #include #include #include #include "nemo-x-content-bar.h" #include #define NEMO_X_CONTENT_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NEMO_TYPE_X_CONTENT_BAR, NemoXContentBarPrivate)) struct NemoXContentBarPrivate { GtkWidget *label; GtkWidget *button; char *x_content_type; GMount *mount; }; enum { PROP_0, PROP_MOUNT, PROP_X_CONTENT_TYPE, }; enum { CONTENT_BAR_RESPONSE_APP = 1 }; G_DEFINE_TYPE (NemoXContentBar, nemo_x_content_bar, GTK_TYPE_INFO_BAR) static void content_bar_response_cb (GtkInfoBar *infobar, gint response_id, gpointer user_data) { GAppInfo *default_app; NemoXContentBar *bar; if (response_id != CONTENT_BAR_RESPONSE_APP) { return; } bar = user_data; if (bar->priv->x_content_type == NULL || bar->priv->mount == NULL) return; default_app = g_app_info_get_default_for_type (bar->priv->x_content_type, FALSE); if (default_app != NULL) { nemo_launch_application_for_mount (default_app, bar->priv->mount, GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (bar)))); g_object_unref (default_app); } } static void nemo_x_content_bar_set_x_content_type (NemoXContentBar *bar, const char *x_content_type) { char *message; char *description; GAppInfo *default_app; g_free (bar->priv->x_content_type); bar->priv->x_content_type = g_strdup (x_content_type); description = g_content_type_get_description (x_content_type); /* Customize greeting for well-known x-content types */ if (strcmp (x_content_type, "x-content/audio-cdda") == 0) { message = g_strdup (_("These files are on an Audio CD.")); } else if (strcmp (x_content_type, "x-content/audio-dvd") == 0) { message = g_strdup (_("These files are on an Audio DVD.")); } else if (strcmp (x_content_type, "x-content/video-dvd") == 0) { message = g_strdup (_("These files are on a Video DVD.")); } else if (strcmp (x_content_type, "x-content/video-vcd") == 0) { message = g_strdup (_("These files are on a Video CD.")); } else if (strcmp (x_content_type, "x-content/video-svcd") == 0) { message = g_strdup (_("These files are on a Super Video CD.")); } else if (strcmp (x_content_type, "x-content/image-photocd") == 0) { message = g_strdup (_("These files are on a Photo CD.")); } else if (strcmp (x_content_type, "x-content/image-picturecd") == 0) { message = g_strdup (_("These files are on a Picture CD.")); } else if (strcmp (x_content_type, "x-content/image-dcf") == 0) { message = g_strdup (_("The media contains digital photos.")); } else if (strcmp (x_content_type, "x-content/audio-player") == 0) { message = g_strdup (_("These files are on a digital audio player.")); } else if (strcmp (x_content_type, "x-content/software") == 0) { message = g_strdup (_("The media contains software.")); } else { /* fallback to generic greeting */ message = g_strdup_printf (_("The media has been detected as \"%s\"."), description); } gtk_label_set_text (GTK_LABEL (bar->priv->label), message); gtk_widget_show (bar->priv->label); /* TODO: We really need a GtkBrowserBackButton-ish widget here.. until then, we only * show the default application. */ default_app = g_app_info_get_default_for_type (x_content_type, FALSE); if (default_app != NULL) { char *button_text; const char *name; GIcon *icon; GtkWidget *image; icon = g_app_info_get_icon (default_app); if (icon != NULL) { image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON); } else { image = NULL; } name = g_app_info_get_display_name (default_app); button_text = g_strdup_printf (_("Open %s"), name); gtk_button_set_image (GTK_BUTTON (bar->priv->button), image); gtk_button_set_label (GTK_BUTTON (bar->priv->button), button_text); gtk_widget_show (bar->priv->button); g_free (button_text); g_object_unref (default_app); } else { gtk_widget_hide (bar->priv->button); } g_free (message); g_free (description); } static void nemo_x_content_bar_set_mount (NemoXContentBar *bar, GMount *mount) { if (bar->priv->mount != NULL) { g_object_unref (bar->priv->mount); } bar->priv->mount = mount != NULL ? g_object_ref (mount) : NULL; } static void nemo_x_content_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NemoXContentBar *bar; bar = NEMO_X_CONTENT_BAR (object); switch (prop_id) { case PROP_MOUNT: nemo_x_content_bar_set_mount (bar, G_MOUNT (g_value_get_object (value))); break; case PROP_X_CONTENT_TYPE: nemo_x_content_bar_set_x_content_type (bar, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_x_content_bar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NemoXContentBar *bar = NEMO_X_CONTENT_BAR (object); switch (prop_id) { case PROP_MOUNT: g_value_set_object (value, bar->priv->mount); break; case PROP_X_CONTENT_TYPE: g_value_set_string (value, bar->priv->x_content_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void nemo_x_content_bar_finalize (GObject *object) { NemoXContentBar *bar = NEMO_X_CONTENT_BAR (object); g_free (bar->priv->x_content_type); if (bar->priv->mount != NULL) g_object_unref (bar->priv->mount); G_OBJECT_CLASS (nemo_x_content_bar_parent_class)->finalize (object); } static void nemo_x_content_bar_class_init (NemoXContentBarClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->get_property = nemo_x_content_bar_get_property; object_class->set_property = nemo_x_content_bar_set_property; object_class->finalize = nemo_x_content_bar_finalize; g_type_class_add_private (klass, sizeof (NemoXContentBarPrivate)); g_object_class_install_property (object_class, PROP_MOUNT, g_param_spec_object ( "mount", "The GMount to run programs for", "The GMount to run programs for", G_TYPE_MOUNT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_X_CONTENT_TYPE, g_param_spec_string ( "x-content-type", "The x-content type for the cluebar", "The x-content type for the cluebar", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); } static void nemo_x_content_bar_init (NemoXContentBar *bar) { GtkWidget *content_area; bar->priv = NEMO_X_CONTENT_BAR_GET_PRIVATE (bar); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar)); bar->priv->label = gtk_label_new (NULL); gtk_style_context_add_class (gtk_widget_get_style_context (bar->priv->label), "nemo-cluebar-label"); gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END); gtk_container_add (GTK_CONTAINER (content_area), bar->priv->label); bar->priv->button = gtk_info_bar_add_button (GTK_INFO_BAR (bar), "", CONTENT_BAR_RESPONSE_APP); g_signal_connect (bar, "response", G_CALLBACK (content_bar_response_cb), bar); } GtkWidget * nemo_x_content_bar_new (GMount *mount, const char *x_content_type) { return g_object_new (NEMO_TYPE_X_CONTENT_BAR, "mount", mount, "x-content-type", x_content_type, NULL); } nemo-4.4.2/src/nemo-x-content-bar.h000066400000000000000000000042301357442400300170350ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2008 Red Hat, Inc. * Copyright (C) 2006 Paolo Borelli * * 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 - Suite 500, Boston, MA 02110-1335, USA. * * Authors: David Zeuthen * Paolo Borelli * */ #ifndef __NEMO_X_CONTENT_BAR_H #define __NEMO_X_CONTENT_BAR_H #include #include G_BEGIN_DECLS #define NEMO_TYPE_X_CONTENT_BAR (nemo_x_content_bar_get_type ()) #define NEMO_X_CONTENT_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NEMO_TYPE_X_CONTENT_BAR, NemoXContentBar)) #define NEMO_X_CONTENT_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NEMO_TYPE_X_CONTENT_BAR, NemoXContentBarClass)) #define NEMO_IS_X_CONTENT_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NEMO_TYPE_X_CONTENT_BAR)) #define NEMO_IS_X_CONTENT_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NEMO_TYPE_X_CONTENT_BAR)) #define NEMO_X_CONTENT_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NEMO_TYPE_X_CONTENT_BAR, NemoXContentBarClass)) typedef struct NemoXContentBarPrivate NemoXContentBarPrivate; typedef struct { GtkInfoBar parent; NemoXContentBarPrivate *priv; } NemoXContentBar; typedef struct { GtkInfoBarClass parent_class; } NemoXContentBarClass; GType nemo_x_content_bar_get_type (void) G_GNUC_CONST; GtkWidget *nemo_x_content_bar_new (GMount *mount, const char *x_content_type); G_END_DECLS #endif /* __NEMO_X_CONTENT_BAR_H */ nemo-4.4.2/test/000077500000000000000000000000001357442400300134405ustar00rootroot00000000000000nemo-4.4.2/test/meson.build000066400000000000000000000011731357442400300156040ustar00rootroot00000000000000 test('Search Engine test', executable('test-nemo-search-engine', [ 'test-nemo-search-engine.c' ], include_directories: [ rootInclude, ], dependencies: [ gtk, nemo_private ], ), args: [] ) test('Directory Async test', executable('test-nemo-directory-async', [ 'test-nemo-directory-async.c' ], include_directories: [ rootInclude, ], dependencies: [ gtk, nemo_private ], ), args: [] ) test('Copy test', executable('test-nemo-copy', [ 'test-copy.c', 'test.c' ], include_directories: [ rootInclude, ], dependencies: [ gtk, nemo_private ], c_args: nemo_definitions, ), args: [] ) nemo-4.4.2/test/test-copy.c000066400000000000000000000041441357442400300155360ustar00rootroot00000000000000#include "test.h" #include #include #include static void copy_done (GHashTable *debuting_uris, gboolean success, gpointer data) { g_print ("Copy done\n"); } static void changed_cb (NemoProgressInfo *info, gpointer data) { g_print ("Changed: %s -- %s\n", nemo_progress_info_get_status (info), nemo_progress_info_get_details (info)); } static void progress_changed_cb (NemoProgressInfo *info, gpointer data) { g_print ("Progress changed: %f\n", nemo_progress_info_get_progress (info)); } static void finished_cb (NemoProgressInfo *info, gpointer data) { g_print ("Finished\n"); gtk_main_quit (); } int main (int argc, char* argv[]) { GtkWidget *window; GList *sources; GFile *dest; GFile *source; int i; GList *infos; NemoProgressInfoManager *manager; NemoProgressInfo *progress_info; test_init (&argc, &argv); if (argc < 3) { g_print ("Usage test-copy \n"); return 1; } sources = NULL; for (i = 1; i < argc - 1; i++) { source = g_file_new_for_commandline_arg (argv[i]); sources = g_list_prepend (sources, source); } sources = g_list_reverse (sources); dest = g_file_new_for_commandline_arg (argv[i]); window = test_window_new ("copy test", 5); gtk_widget_show (window); manager = nemo_progress_info_manager_new (); nemo_file_operations_copy (sources, NULL /* GArray *relative_item_points */, dest, GTK_WINDOW (window), copy_done, NULL); infos = nemo_progress_info_manager_get_all_infos (manager); if (infos == NULL) { g_object_unref (manager); return 0; } progress_info = NEMO_PROGRESS_INFO (infos->data); g_signal_connect (progress_info, "changed", (GCallback)changed_cb, NULL); g_signal_connect (progress_info, "progress-changed", (GCallback)progress_changed_cb, NULL); g_signal_connect (progress_info, "finished", (GCallback)finished_cb, NULL); gtk_main (); g_object_unref (manager); return 0; } nemo-4.4.2/test/test-eel-editable-label.c000066400000000000000000000026071357442400300201570ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ #include #include #include static void quit (GtkWidget *widget, gpointer data) { gtk_main_quit (); } int main (int argc, char* argv[]) { GtkWidget *window; GtkWidget *label; GtkWidget *vbox; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (quit), NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = eel_editable_label_new ("Centered dsau dsfgsdfgoydsfiugy oiusdyfg iouysdf goiuys dfioguy siodufgy iusdyfgiu ydsf giusydf gouiysdfgoiuysdfg oiudyfsg Label"); gtk_widget_set_size_request (label, 200, -1); eel_editable_label_set_line_wrap (EEL_EDITABLE_LABEL (label), TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 4); label = eel_editable_label_new ("Left aligned label"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 4); label = eel_editable_label_new ("Right aligned label"); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 4); gtk_window_set_default_size (GTK_WINDOW (window), 300, 300); gtk_widget_show_all (window); gtk_main (); return 0; } nemo-4.4.2/test/test-nemo-directory-async.c000066400000000000000000000040651357442400300206410ustar00rootroot00000000000000#include #include #include #include #include void *client1, *client2; #if 0 static gboolean quit_cb (gpointer data) { gtk_main_quit (); return FALSE; } #endif static void files_added (NemoDirectory *directory, GList *added_files) { #if 0 GList *list; for (list = added_files; list != NULL; list = list->next) { NemoFile *file = list->data; g_print (" - %s\n", nemo_file_get_uri (file)); } #endif g_print ("files added: %d files\n", g_list_length (added_files)); } static void files_changed (NemoDirectory *directory, GList *changed_files) { #if 0 GList *list; for (list = changed_files; list != NULL; list = list->next) { NemoFile *file = list->data; g_print (" - %s\n", nemo_file_get_uri (file)); } #endif g_print ("files changed: %d\n", g_list_length (changed_files)); } static gboolean force_reload (NemoDirectory *directory) { g_print ("forcing reload!\n"); nemo_directory_force_reload (directory); return FALSE; } static void done_loading (NemoDirectory *directory) { static int i = 0; g_print ("done loading\n"); if (i == 0) { g_timeout_add (5000, (GSourceFunc)force_reload, directory); i++; } else { } } int main (int argc, char **argv) { NemoDirectory *directory; NemoQuery *query; client1 = g_new0 (int, 1); client2 = g_new0 (int, 1); gtk_init (&argc, &argv); query = nemo_query_new (); nemo_query_set_text (query, "richard hult"); directory = nemo_directory_get_by_uri ("x-nemo-search://0/"); nemo_search_directory_set_query (NEMO_SEARCH_DIRECTORY (directory), query); g_object_unref (query); g_signal_connect (directory, "files-added", G_CALLBACK (files_added), NULL); g_signal_connect (directory, "files-changed", G_CALLBACK (files_changed), NULL); g_signal_connect (directory, "done-loading", G_CALLBACK (done_loading), NULL); nemo_directory_file_monitor_add (directory, client1, TRUE, NEMO_FILE_ATTRIBUTE_INFO, NULL, NULL); gtk_main (); return 0; } nemo-4.4.2/test/test-nemo-search-engine.c000066400000000000000000000022251357442400300202260ustar00rootroot00000000000000#include #include static void hits_added_cb (NemoSearchEngine *engine, GSList *hits) { g_print ("hits added\n"); while (hits) { g_print (" - %s\n", (char *)hits->data); hits = hits->next; } } static void hits_subtracted_cb (NemoSearchEngine *engine, GSList *hits) { g_print ("hits subtracted\n"); while (hits) { g_print (" - %s\n", (char *)hits->data); hits = hits->next; } } static void finished_cb (NemoSearchEngine *engine) { g_print ("finished!\n"); // gtk_main_quit (); } int main (int argc, char* argv[]) { NemoSearchEngine *engine; NemoQuery *query; gtk_init (&argc, &argv); engine = nemo_search_engine_new (); g_signal_connect (engine, "hits-added", G_CALLBACK (hits_added_cb), NULL); g_signal_connect (engine, "hits-subtracted", G_CALLBACK (hits_subtracted_cb), NULL); g_signal_connect (engine, "finished", G_CALLBACK (finished_cb), NULL); query = nemo_query_new (); nemo_query_set_text (query, "richard hult"); nemo_search_engine_set_query (engine, query); g_object_unref (query); nemo_search_engine_start (engine); gtk_main (); return 0; } nemo-4.4.2/test/test.c000066400000000000000000000040641357442400300145670ustar00rootroot00000000000000#include "test.h" #include #include void test_init (int *argc, char ***argv) { gtk_init (argc, argv); eel_make_warnings_and_criticals_stop_in_debugger (); } int test_quit (int exit_code) { if (gtk_main_level () > 0) { gtk_main_quit (); } return exit_code; } void test_delete_event (GtkWidget *widget, GdkEvent *event, gpointer callback_data) { test_quit (0); } GtkWidget * test_window_new (const char *title, guint border_width) { GtkWidget *window; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); if (title != NULL) { gtk_window_set_title (GTK_WINDOW (window), title); } g_signal_connect (window, "delete_event", G_CALLBACK (test_delete_event), NULL); gtk_container_set_border_width (GTK_CONTAINER (window), border_width); return window; } GdkPixbuf * test_pixbuf_new_named (const char *name, float scale) { GdkPixbuf *pixbuf; char *path; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (scale >= 0.0, NULL); if (name[0] == '/') { path = g_strdup (name); } else { path = g_strdup_printf ("%s/%s", NEMO_DATADIR, name); } pixbuf = gdk_pixbuf_new_from_file (path, NULL); g_free (path); g_return_val_if_fail (pixbuf != NULL, NULL); if (scale != 1.0) { GdkPixbuf *scaled; float width = gdk_pixbuf_get_width (pixbuf) * scale; float height = gdk_pixbuf_get_width (pixbuf) * scale; scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR); g_object_unref (pixbuf); g_return_val_if_fail (scaled != NULL, NULL); pixbuf = scaled; } return pixbuf; } GtkWidget * test_label_new (const char *text, gboolean with_background, int num_sizes_larger) { GtkWidget *label; if (text == NULL) { text = "Foo"; } label = gtk_label_new (text); return label; } void test_window_set_title_with_pid (GtkWindow *window, const char *title) { char *tmp; g_return_if_fail (GTK_IS_WINDOW (window)); tmp = g_strdup_printf ("%lu: %s", (gulong) getpid (), title); gtk_window_set_title (GTK_WINDOW (window), tmp); g_free (tmp); } nemo-4.4.2/test/test.h000066400000000000000000000033711357442400300145740ustar00rootroot00000000000000#ifndef TEST_H #define TEST_H #include #include #include #include #include void test_init (int *argc, char ***argv); int test_quit (int exit_code); void test_delete_event (GtkWidget *widget, GdkEvent *event, gpointer callback_data); GtkWidget *test_window_new (const char *title, guint border_width); void test_gtk_widget_set_background_image (GtkWidget *widget, const char *image_name); void test_gtk_widget_set_background_color (GtkWidget *widget, const char *color_spec); GdkPixbuf *test_pixbuf_new_named (const char *name, float scale); GtkWidget *test_label_new (const char *text, gboolean with_background, int num_sizes_larger); void test_pixbuf_draw_rectangle_tiled (GdkPixbuf *pixbuf, const char *tile_name, int x0, int y0, int x1, int y1, int opacity); void test_window_set_title_with_pid (GtkWindow *window, const char *title); #endif /* TEST_H */ nemo-4.4.2/utils/000077500000000000000000000000001357442400300136215ustar00rootroot00000000000000nemo-4.4.2/utils/gvfs-info.nemo_action000066400000000000000000000002741357442400300177370ustar00rootroot00000000000000[Nemo Action] Active=true Name=Report GVFS info on %f Comment=Send the results of gvfs-info on %f to stdout Exec=gvfs-info %F Icon-Name=info Selection=s Extensions=any; EscapeSpaces=true