From 4ea699ba3bd9dcba8128995451f43fafc3e27484 Mon Sep 17 00:00:00 2001 From: "deepin-community-bot[bot]" <156989552+deepin-community-bot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:11:02 +0000 Subject: [PATCH] feat: update nautilus-python to 4.1.0-1 --- .gitignore | 5 + .gitlab-ci.yml | 42 ++ AUTHORS | 6 + COPYING | 339 +++++++++++++ MAINTAINERS | 3 + NEWS.md | 165 ++++++ README.md | 32 +- debian/NEWS | 14 + debian/README.Debian | 12 + debian/changelog | 380 +++++++++++++- debian/compat | 1 - debian/control | 53 +- debian/copyright | 7 +- debian/gbp.conf | 17 + debian/patches/series | 0 debian/python3-nautilus.dirs | 1 + debian/python3-nautilus.docs | 3 + debian/python3-nautilus.lintian-overrides | 2 + debian/rules | 14 +- debian/upstream/metadata | 5 + debian/watch | 4 + default.nix | 107 ++++ docs/reference/entities.docbook.in | 1 + docs/reference/meson.build | 42 ++ .../nautilus-python-class-reference.xml | 15 + .../nautilus-python-column-provider.xml | 85 ++++ docs/reference/nautilus-python-column.xml | 162 ++++++ .../nautilus-python-enum-reference.xml | 10 + docs/reference/nautilus-python-file-info.xml | 423 ++++++++++++++++ .../nautilus-python-info-provider.xml | 239 +++++++++ docs/reference/nautilus-python-menu-item.xml | 248 +++++++++ .../nautilus-python-menu-provider.xml | 280 +++++++++++ docs/reference/nautilus-python-menu.xml | 126 +++++ .../nautilus-python-migrating-to-4.xml | 54 ++ .../nautilus-python-operation-result.xml | 59 +++ .../nautilus-python-overview-example.xml | 30 ++ .../nautilus-python-overview-methods.xml | 20 + docs/reference/nautilus-python-overview.xml | 41 ++ .../nautilus-python-properties-item.xml | 163 ++++++ ...tilus-python-properties-model-provider.xml | 84 ++++ .../nautilus-python-properties-model.xml | 187 +++++++ .../nautilus-python-provider-reference.xml | 13 + docs/reference/nautilus-python-ref.xml | 33 ++ examples/README | 15 + examples/TestExtension.py | 42 ++ examples/background-image.py | 58 +++ examples/block-size-column.py | 26 + examples/md5sum-properties-model.py | 39 ++ examples/meson.build | 15 + examples/open-terminal.py | 62 +++ examples/submenu.py | 48 ++ examples/update-file-info-async.py | 30 ++ meson.build | 72 +++ meson_options.txt | 5 + nautilus-python.doap | 27 + npins/default.nix | 146 ++++++ npins/sources.json | 11 + shell.nix | 8 + src/meson.build | 18 + src/nautilus-python-object.c | 476 ++++++++++++++++++ src/nautilus-python-object.h | 45 ++ src/nautilus-python.c | 295 +++++++++++ src/nautilus-python.h | 70 +++ 63 files changed, 5013 insertions(+), 22 deletions(-) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 MAINTAINERS create mode 100644 NEWS.md create mode 100644 debian/NEWS create mode 100644 debian/README.Debian delete mode 100644 debian/compat create mode 100644 debian/gbp.conf create mode 100644 debian/patches/series create mode 100644 debian/python3-nautilus.dirs create mode 100644 debian/python3-nautilus.docs create mode 100644 debian/python3-nautilus.lintian-overrides create mode 100644 debian/upstream/metadata create mode 100644 debian/watch create mode 100644 default.nix create mode 100644 docs/reference/entities.docbook.in create mode 100644 docs/reference/meson.build create mode 100644 docs/reference/nautilus-python-class-reference.xml create mode 100644 docs/reference/nautilus-python-column-provider.xml create mode 100644 docs/reference/nautilus-python-column.xml create mode 100644 docs/reference/nautilus-python-enum-reference.xml create mode 100644 docs/reference/nautilus-python-file-info.xml create mode 100644 docs/reference/nautilus-python-info-provider.xml create mode 100644 docs/reference/nautilus-python-menu-item.xml create mode 100644 docs/reference/nautilus-python-menu-provider.xml create mode 100644 docs/reference/nautilus-python-menu.xml create mode 100644 docs/reference/nautilus-python-migrating-to-4.xml create mode 100644 docs/reference/nautilus-python-operation-result.xml create mode 100644 docs/reference/nautilus-python-overview-example.xml create mode 100644 docs/reference/nautilus-python-overview-methods.xml create mode 100644 docs/reference/nautilus-python-overview.xml create mode 100644 docs/reference/nautilus-python-properties-item.xml create mode 100644 docs/reference/nautilus-python-properties-model-provider.xml create mode 100644 docs/reference/nautilus-python-properties-model.xml create mode 100644 docs/reference/nautilus-python-provider-reference.xml create mode 100644 docs/reference/nautilus-python-ref.xml create mode 100644 examples/README create mode 100644 examples/TestExtension.py create mode 100644 examples/background-image.py create mode 100644 examples/block-size-column.py create mode 100644 examples/md5sum-properties-model.py create mode 100644 examples/meson.build create mode 100644 examples/open-terminal.py create mode 100644 examples/submenu.py create mode 100644 examples/update-file-info-async.py create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 nautilus-python.doap create mode 100644 npins/default.nix create mode 100644 npins/sources.json create mode 100644 shell.nix create mode 100644 src/meson.build create mode 100644 src/nautilus-python-object.c create mode 100644 src/nautilus-python-object.h create mode 100644 src/nautilus-python.c create mode 100644 src/nautilus-python.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b96932d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Meson +_build/ + +# Nix +result* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..65325f0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,42 @@ +include: + - component: gitlab.gnome.org/GNOME/citemplates/release-service@master + inputs: + dist-job-name: "build-and-test" + +build-and-test: + image: nixpkgs/nix:latest + variables: + MESON_BUILD_DIR: _build + script: + - nix-shell --run "meson setup '${MESON_BUILD_DIR}'" + - nix-shell --run "meson compile -C '${MESON_BUILD_DIR}'" + - nix-shell --run "meson test -C '${MESON_BUILD_DIR}'" + - nix-shell --run "meson dist -C '${MESON_BUILD_DIR}' --include-subprojects" + - cp -r "${MESON_BUILD_DIR}/meson-dist/" "${CI_PROJECT_DIR}/public-dist/" + artifacts: + name: "${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: "always" + paths: + - "public-dist" + +build-nix-derivation: + image: nixpkgs/nix:latest + script: + # Build the project including docs. + - nix-build -A all + - cp -r result-devdoc/share/gtk-doc/html/nautilus-python/ public/ + artifacts: + paths: + - public/ + +pages: + stage: deploy + dependencies: + - build-nix-derivation + script: + - echo "Re-using public artifact from build job" + artifacts: + paths: + - public/ + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..60ca939 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +nautilus-python is written by +Johan Dahlin + +Somewhat on nautilus-mono by: +Dave Camp +Calvin Gaisford diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..ece9a51 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,3 @@ +Adam Plumb +E-mail: adamplumb@gmail.com +Userid: adamplumb diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..ab99a53 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,165 @@ +## 4.1.0 (2025-10-04) + +- Added support for Nautilus 49 (https://gitlab.gnome.org/GNOME/nautilus-python/-/merge_requests/13) +- Removed `MenuItem.icon`, `MenuItem.priority`, `MenuItem.tip` from docs. These were unsupported for a long time and now Nautilus officially deprecated them. + +## 4.0.1 (2024-04-19) + +- Fixed build failure due to underlinking. (https://gitlab.gnome.org/GNOME/nautilus-python/-/merge_requests/13) +- Fixed build failure with Python 3.13 (Patrick Monnerat) + +## 4.0 (2022-09-17) + +- Updated migration docs and rewrote overview. + +## 4.0.alpha (2022-08-12) + +- The extension was ported to Nautilus 43 (https://gitlab.gnome.org/GNOME/nautilus-python/-/merge_requests/11) + - Notably, this removes any direct access to GTK widgets from the API. **Most scripts will need to be modified.** Please check the migration guide in the docs on how to update your scripts. +- Switched to Meson build system (https://gitlab.gnome.org/GNOME/nautilus-python/-/merge_requests/10) +- Removed support for Python 2 +- Fixed build with `-fno-common` (Andreas Henriksson) +- Added missing parent constructor calls to examples +- Decorated the examples with typehints +- Fixed several memory leaks (Michael Webster) + +## 1.2.3 (2019-07-17) + +- First release from gitlab +- Fixed open-terminal example extension (Maximillian Schambach) +- Fixed invalid DOAP file category (Andre Klapper) +- Fixed bug https://gitlab.gnome.org/GNOME/nautilus-python/-/issues/3, setting `argv[0]` to thunar +- Fixed bug https://gitlab.gnome.org/GNOME/nautilus-python/-/issues/4, allow overriding the build date to enable reproducible builds +- Removed build warnings (Christian Stadelman) +- Fix to work with python 3.8 (stratakis) + +## 1.2.2 (2018-01-14) + +- Fixed [bug #792427](https://bugzilla.gnome.org/show_bug.cgi?id=792427), Fix folder string comparison to prevent duplicate extension loading + +## 1.2.1 (2018-01-08) + +- Fixed [bug #792348](https://bugzilla.gnome.org/show_bug.cgi?id=792348), Fix syntax error when building docs using python3 + +## 1.2.0 (2018-01-02) + +- Added capability to compile with python 3 support using PYTHON environment variable +- Fix [#781232](https://bugzilla.gnome.org/show_bug.cgi?id=781232), Improve extension path loading semantics to follow XDG recommendations +- Fix [#791208](https://bugzilla.gnome.org/show_bug.cgi?id=791208), require Nautilus 3.0 before importing extensions to prevent warnings +- Switch to using gtkdoc mkhtml for generating devhelp2 documentation + +## 1.1.0 (2011-10-17) + +- Added pygobject3 compatibility. Retained pygobject 2.28.x compatibility. + - Updated extension examples to support pygobject3. +- Fixed [bug #660290](https://bugzilla.gnome.org/show_bug.cgi?id=660290). Updated the FSF address +- Fixed [bug #660288](https://bugzilla.gnome.org/show_bug.cgi?id=660288). Fix autogen warnings with additional macro ACLOCAL_AMFLAGS +- Fixed [bug #660287](https://bugzilla.gnome.org/show_bug.cgi?id=660287). Make the docdir not hard-coded +- Fixed [bug #660286](https://bugzilla.gnome.org/show_bug.cgi?id=660286). Fixes m4 underquoting warning +- Fixed [bug #660283](https://bugzilla.gnome.org/show_bug.cgi?id=660283). Fixes html docs installation issue +- Fixed [bug #653169](https://bugzilla.gnome.org/show_bug.cgi?id=653169). Upated the COPYING file with the most recent GPLv2 license + +## 1.0.0 (2011-04-17) + +- Use the gobject instrospection dynamic bindings, breaks compatibility for existing extensions. +- For Nautilus3, the `get_toolbar_items` methods have been removed. (Only reporting that change, it isn't up to us). Should still work with Nautilus 2.x annotations. +- No longer look in the old `~/.nautilus/python-extensions` or `/usr/lib/nautilus/extensions2.0/python` folders for extensions. Now look in `~/.local/share/nautilus-python/extensions` or `$XDG_DATA_DIR/nautilus-python/extensions`. Extensions should be arch-independent now. +- General clean up of the repository, removed old .cvsignore files +- Updated the gtk-doc documentation and examples to work with new dynamic bindings. + +## 0.7.3 (2011-03-28) + +- Use `PyCapsule_Import` for pygobject as well as pygtk +- Fixed bug [#644399](https://bugzilla.gnome.org/show_bug.cgi?id=644399), in the property page example plugin, get the md5sum of the file contents, not the file name +- Removed extraneous `.cvsignore` files +- Fixed the update-file-info-async example plugin + +## 0.7.2 (2011-03-04) + +- Fix to get the PyCapsule patch to work even if there is no PyCapsule object set up for pygtk. + +## 0.7.1 (2011-03-02) + +- Fixed AM_CHECK_PYTHON_LIBS usage of test (GNOME [bug #619440](https://bugzilla.gnome.org/show_bug.cgi?id=619440)) +- Cleaned up the docs Makefile.am to make it more consistent +- Fix some python3 syntax issues in the python.m4 script +- Add python 2.7 support (GNOME [bug #633171](https://bugzilla.gnome.org/show_bug.cgi?id=633171)) + +## 0.7.0 (2010-05-21) + +- Added methods: + - `nautilus.InfoProvider.update_file_info_full` + - `nautilus.InfoProvider.update_complete_invoke` + - `nautilus.InfoProvider.cancel_update` + - `nautilus.MenuProvider.get_file_items_full` + - `nautilus.MenuProvider.get_background_items_full` + - `nautilus.MenuProvider.get_toolbar_items_full` + - `nautilus.MenuProvider.emit_items_updated_signal` +- Added complete gtk-doc documentation: tutorial and reference. Enable by adding the `--enable-gtk-doc` argument to `./configure` or `./autogen.sh` +- Updated the `autogen.sh` file so it is not a copied-over obsolete version of gnome-autogen.sh, but a shell that calls the user's installed gnome-autogen.sh. +- Removed obsolete .spec file +- Removed obsolete `examples/documentation.py` file +- Added an example plugin for the LocationWidgetProvider +- Look for python plugins in `$XDG_DATA_DIR/nautilus-python/extensions`. This includes `~/.local/share` and `/usr/share` (or whatever `$XDG_DATA_DIR` is set to) + +## 0.6.1 (2010-01-19) + +- Look for `libpython2.6.so.1.0` instead of `libpython2.6.so`, the latter is general available from -devel packages only. +- Re-added the missing spec and pc files +- Free pygobject data directly after using file objects. Stops segfaults from occurring when nautilus wants to free pygobject data after `Py_Finalize()` is called. + +## 0.6.0 (2010-01-15) + +- Remove eel dependency (Vincent Untz) +- Sanitize python search path (Mark Lee) +- Remove gnomevfs dependency and unused code (Daniel Holbach) +- Load python from lib64 in 64 bit multilib distributions (Ted Toth) +- Fix segfault when a plugin doesn't implement the `__init__` method +- Added the `can_write`, `get_mount`, `get_file_type`, `get_location`, and `get_parent_location` methods to the `NautilusFileInfo` object +- Added the `NautilusMenu.get_items` method +- Updated some example plugins +- Bug fix for some `PyThreadState_New` segmentation faults +- Use the nautilus prefix by default for distfiles, rather than /usr +- Require nautilus-2.22 and pygobject-2.16 now that we support GIO + +## 0.5.2 (2010-03-01) + +- Look for libpython2.6.so.1.0 instead of libpython2.6.so, the latter is general available from -devel packages only. +- Remove eel dependency (Vincent Untz) +- Sanitize python search path (Mark Lee) +- Load python from lib64 in 64 bit multilib distributions (Ted Toth) +- Updated some example plugins +- Added explicit gnome-vfs build dependency +- Removed obsolete .spec file + +## 0.5.1 (2008-09-16) + +- Add support for location widgets (Tim Cole) + +## 0.5.0 (2008-01-11) + +- Add support for submenus (Lukáš Lalinský, Sylvain Baubeau, Erik Wien) +- Make it work with nautilus 2.22 (Brian Pepple) +- Initialize gnomevfs explicitly (Scott Tsai) +- Compilable with Python 2.5 (Jonathan Rogers) +- Shutdown Python (Gustavo Carneiro) +- Initialize PyGObject/PyGTK/PyGNOMEVFS on demand (Gustavo Carneiro) + +## 0.4.3 (2006-02-15) + +- Make debugging messages a run-time option +- Fix bug in loading extensions from system extensions dir +- Fix crash when no extensions were loaded + +## 0.4.2 (2006-02-10) + +- Make it work again with nautilus ≥ 2.13.4 +- Minor bug fixes + +## 0.4.1 (2005-09-22) + +(missing) + +## 0.4.0 (2005-05-30) + +First public release diff --git a/README.md b/README.md index 9ebb840..6eed3a6 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# template-repository \ No newline at end of file +# nautilus-python + +This is an extension for Nautilus that allows further extending it with Python scripts with the help of Nautilus’s GObject API. + +Documentation, including an API reference, is available through the [Devhelp app](https://apps.gnome.org/app/org.gnome.Devhelp/), if you have `nautilus-python` package installed, or [on-line](https://gnome.pages.gitlab.gnome.org/nautilus-python/). For sample extensions, check the `examples/` subdirectory in the source distribution. Note that some distros move the documentation into a separate package. + +## Requirements + +- Nautilus ≥ 43.beta +- Python 3.x +- PyGObject 3 + +## Running Extensions + +Scripts are loaded in the following order: + + 1. `$XDG_DATA_HOME/nautilus-python/extensions` (i.e. `~/.local/share/…`) + 2. `nautilus_prefix/share/nautilus-python/extensions` (i.e. `~/Development/…`) + 3. `$XDG_DATA_DIRS/nautilus-python/extensions` (i.e. `/usr/share/…`) + +Simply copy your Python scripts into one of those directories and restart Nautilus. + +## Issues + +It is currently not possible to reload a Python script without restarting Nautilus. + +Run Nautilus with the `NAUTILUS_PYTHON_DEBUG=misc` environment variable to print out debug information. + +## License + +nautilus-python is released under the terms of the GNU General Public License, either version 2.0 or, at your option, any later version. diff --git a/debian/NEWS b/debian/NEWS new file mode 100644 index 0000000..b16ea81 --- /dev/null +++ b/debian/NEWS @@ -0,0 +1,14 @@ +nautilus-python (1.1-1) unstable; urgency=low + + The extensions should now be arch-independent, the system-wide extension + directory has changed to /usr/share/nautilus-python/extensions/. + + -- Laurent Bigonville Tue, 18 Oct 2011 11:51:17 +0200 + +nautilus-python (0.5.0-1) experimental; urgency=low + + This version of nautilus-python requires Nautilus 2.22. Because there + have been API/ABI changes, the extension directory has changed to + /usr/lib/nautilus/extension-2.0/python. + + -- Ross Burton Sun, 20 Apr 2008 16:43:55 +0100 diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..2cb40ea --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,12 @@ +nautilus-python for Debian +-------------------------- + +Plugins are loaded by default from two locations: + + /usr/share/nautilus-python/extensions - all-user plugin directory + ~/.local/share/nautilus-python/extensions - per-user plugin directory + +Sample plugins can be found in /usr/share/doc/python-nautilus/examples. To use +them, copy them to one of the locations above and restart nautilus--this can +be done gracefully by running 'nautilus --quit'. + diff --git a/debian/changelog b/debian/changelog index bad88e2..d78742b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,379 @@ -template-repository (1.0-1) unstable; urgency=medium +nautilus-python (4.1.0-1) unstable; urgency=medium - * Initial release + * New upstream release + * Move Maintainer from Debian GNOME to Debian GNOME Extras + * Remove remaining patch: no longer needed + * Bump Standards Version to 4.7.3 - -- Tsic404 Sat, 28 Jan 2023 13:46:49 +0800 + -- Jeremy Bícha Sat, 10 Jan 2026 15:03:33 -0500 + +nautilus-python (4.0.1-3) unstable; urgency=medium + + * Add patch to use nautilus 4.1 instead of 4.0 API + * Update Depends: gir1.2-nautilus-4.0 → gir1.2-nautilus-4.1 + * Bump Standards Version to 4.7.2 + * Remove obsolete Rules-Requires-Root: no field + + -- Jeremy Bícha Mon, 08 Sep 2025 10:35:20 -0400 + +nautilus-python (4.0.1-2) unstable; urgency=medium + + * Remove Josselin Mouette from uploaders, with thanks for + previous work on this package (Closes: #930191) + * Run wrap-and-sort + * Bump Standards Version to 4.7.0 + + -- Jeremy Bícha Sun, 19 Jan 2025 09:58:39 -0500 + +nautilus-python (4.0.1-1) unstable; urgency=medium + + * New upstream release + * Add debian/upstream/metadata + * Stop using debian/control.in and dh-sequence-gnome + * Update standards version to 4.6.2, no changes needed + + -- Jeremy Bícha Fri, 03 May 2024 14:27:37 -0400 + +nautilus-python (4.0-1) unstable; urgency=medium + + * New upstream release + * Drop all patches: applied in new release + * Release to unstable + + -- Jeremy Bicha Sun, 18 Sep 2022 07:09:20 -0400 + +nautilus-python (4.0~alpha-2) experimental; urgency=medium + + * Cherry-pick some docs improvements + + -- Jeremy Bicha Wed, 17 Aug 2022 10:25:32 -0400 + +nautilus-python (4.0~alpha-1) experimental; urgency=medium + + * New upstream release + - Build against nautilus 43 (Closes: #1016960) + - This is a major API break and it's expected that all + nautilus-python extensions will need code changes + * Add Breaks against several packaged nautilus-python extensions + * Build with meson + * Build and install docs (Closes: #960671) + * debian/docs: NEWS and README are now Markdown files + * Build-Depend on debhelper-compat 13 + * Build-Depend on dh-sequence-gnome & dh-sequence-python3 + * debian/control.in: Bump Standards-Version to 4.6.1 + * debian/control.in: Set Rules-Requires-Root: no + * debian/rules: Drop unneeded -Wl,--as-needed + * Drop patch: applied in new release + + -- Jeremy Bicha Mon, 15 Aug 2022 08:19:15 -0400 + +nautilus-python (1.2.3-3.1) unstable; urgency=medium + + * Non-maintainer upload. + * debian/control{,in}: Add missing build-dependency gtk-doc-tools. + (Closes: #978868) + + -- Boyuan Yang Wed, 29 Sep 2021 21:24:28 -0400 + +nautilus-python (1.2.3-3) unstable; urgency=high + + * Fix up debian/patches/gcc10.patch to work properly (Closes: #960079) + + -- Andreas Henriksson Tue, 12 May 2020 13:54:14 +0200 + +nautilus-python (1.2.3-2) unstable; urgency=medium + + * Team upload. + + [ Laurent Bigonville ] + * debian/control.in: Bump libnautilus-extension-dev build-dependency to + 3.27.90, this is the release that starts to ship nautilus-extension.h + + [ Moritz Mühlenhoff ] + * Drop python-nautilus binary package (Python2) (Closes: #937115) + + [ Andreas Henriksson ] + * Add debian/patches/gcc10.patch (Closes: #957578) + + -- Andreas Henriksson Fri, 24 Apr 2020 16:23:25 +0200 + +nautilus-python (1.2.3-1) unstable; urgency=medium + + * New upstream release + * Build-Depend on python-gi (and python3-gi) (Closes: #945037) + + -- Jeremy Bicha Mon, 18 Nov 2019 19:21:40 -0500 + +nautilus-python (1.2.2-3) unstable; urgency=medium + + [ Jonas Meurer ] + * Build nautilus bindings for python3 (Closes: #911082) + + [ Andreas Henriksson ] + * Describe python2 version as deprecated + - will be removed shortly, this intermediate upload still contains it + to give reverse dependencies chance to migrate smoothly. + See: #937115 + + -- Andreas Henriksson Mon, 21 Oct 2019 12:20:06 +0200 + +nautilus-python (1.2.2-2) unstable; urgency=medium + + * Add -Wl,-O1 to our LDFLAGS + * Bump Standards-Version to 4.3.0 + + -- Jeremy Bicha Thu, 27 Dec 2018 11:18:48 -0500 + +nautilus-python (1.2.2-1) unstable; urgency=medium + + * New upstream release (Closes: #725665, #907591) (LP: #1529460) + * Build-Depend on pkg-config + * Update Vcs fields for migration to https://salsa.debian.org/ + * debian/copyright: Switch to the machine-readable 1.0 format + * Bump Standards-Version to 4.2.1 + * Drop all patches: applied in new release + + -- Jeremy Bicha Mon, 08 Oct 2018 13:01:38 -0400 + +nautilus-python (1.1-6) unstable; urgency=medium + + * Update Vcs fields for conversion to git + * Add debian/gbp.conf + * Bump Standards-Version to 4.1.2 + * Bump debhelper compat to 11 + + -- Jeremy Bicha Sun, 17 Dec 2017 17:29:50 -0500 + +nautilus-python (1.1-5) unstable; urgency=medium + + * Switch from cdbs to dh + * Bump debhelper compat to 10 + * Bump Standards-Version to 4.1.1 + * debian/rules: + - Adapt to nautilus multi-archification + - Enable all hardening flags + + -- Jeremy Bicha Sat, 11 Nov 2017 15:05:06 -0500 + +nautilus-python (1.1-4) unstable; urgency=low + + * Team upload. + * Sync with ubuntu (Closes: #697565, #558613, #725665) + - debian/control(.in) changes excluded except added dh-autoreconf b-d + + -- Andreas Henriksson Wed, 09 Oct 2013 23:48:55 +0200 + +nautilus-python (1.1-3ubuntu3) saucy; urgency=low + + [ Doug McMahon ] + * d/p/02_python_multiarch_path.patch: Follow up fix for i386 multiarch. + (LP: #1170017) + + -- Barry Warsaw Wed, 29 May 2013 16:34:23 -0400 + +nautilus-python (1.1-3ubuntu2) saucy; urgency=low + + [ Dr.Amr Osman ] + * debian/patches/02_python_multiarch_path.patch: Add 64bit multiarch + search paths for libpython2.7.so. (LP: #1170017) + + -- Barry Warsaw Tue, 28 May 2013 16:26:27 -0400 + +nautilus-python (1.1-3ubuntu1) raring; urgency=low + + * Fix FTBFS with python multiarch headers; Add dh-autoreconf to control; + Add autoreconf to rules + - update debian/control + - update debian/rules + - add debian/patches/02_python_multiarch_path.patch + - update debian/patches/series + + -- Micah Gersten Sun, 06 Jan 2013 17:52:30 -0600 + +nautilus-python (1.1-3) unstable; urgency=low + + * Bump debhelper compatibility to 8. + * Set pkg-gnome-maintainers@lists.alioth.debian.org as Maintainer. + * Tighten dependency on python-gi to ensure it has dynamic bindings support. + Closes: #652109 + + -- Michael Biebl Thu, 15 Dec 2011 01:00:58 +0100 + +nautilus-python (1.1-2) unstable; urgency=low + + [ Josselin Mouette ] + * Replace python-gobject by python-gi. + + [ Martin Pitt ] + * Add 00git_open_terminal_example_GI.patch: Use GI GConf bindings in open + terminal example. Patch taken from upstream git. + * Add 01_port_examples_to_GI.patch: Port remaining examples to GI + bindings/GSettings. (Closes: #649910, LP: #898959) + + -- Martin Pitt Fri, 02 Dec 2011 07:40:34 +0100 + +nautilus-python (1.1-1) unstable; urgency=low + + * New upstream release. + - Transition to nautilus 3 (Closes: #637315) + * debian/control.in: + - Adjusts {build-}dependencies + - Bump Standards-Version to 3.9.2 (no further changes) + - Add Vcs-* fields + * Switch to dpkg-source 3.0 (quilt) format + * debian/dirs: Create system-wide extensions directory to new location + * debian/watch: Switch to .xz tarballs + * debian/README.Debian: Update to new locations + * debian/lintian-overrides: Add an override for the empty system-wide + extensions directory + * debian/copyright: Add missing copyright statements + + -- Laurent Bigonville Wed, 19 Oct 2011 22:04:10 +0200 + +nautilus-python (0.6.1-1) unstable; urgency=low + + [ Josselin Mouette ] + * Require python-gconf instead of python-gnome2. Closes: #541582. + * Add missing dependency on python-gtk2. + * Drop useless .la files. + + [ Emilio Pozuelo Monfort ] + * New upstream release. + * debian/patches/02_libeel.patch, + debian/patches/10_dlopen-nasty.patch, + debian/patches/50_CVE-2009-0317.patch, + debian/patches/70_missing_m4.patch, + debian/patches/90_relibtoolize.patch: + - Removed, no longer needed / applied upstream. + * debian/control.in: + - Remove libgnomevfs-dev from build depends, add python-gobject-dev. + - Standards-Version is 3.8.4, no changes needed. + * debian/watch: + - Don't uupdate. + * debian/control.in, + debian/rules: + - Remove quilt support, no longer needed. + + -- Emilio Pozuelo Monfort Sat, 30 Jan 2010 14:12:47 +0100 + +nautilus-python (0.5.1-2) unstable; urgency=low + + * Remove useless libeel build-dependency. + + -- Josselin Mouette Sat, 25 Apr 2009 12:51:34 +0200 + +nautilus-python (0.5.1-1) unstable; urgency=low + + * New upstream release. + * Switch to quilt; build-depend on quilt. + * Rename un-numbered patches. + * 01_fix-extension-directory.patch: removed, fixed upstream. + * 02_libeel.patch: drop eel requirement. + * update.patch: removed, merged upstream. + * 70_missing_m4.patch: add missing m4 macros to acinclude.m4. + * 90_relibtoolize.patch: as the name says. + * Use debhelper compatibility mode 7. + * Refer to versioned GPL in the copyright. + + -- Josselin Mouette Thu, 16 Apr 2009 18:30:58 +0200 + +nautilus-python (0.5.0-2) unstable; urgency=low + + [ Loic Minier ] + * Section is gnome says ftpmasters. + * Wrap build-deps and deps. + * Add ${misc:Depends}. + + [ Emilio Pozuelo Monfort ] + * Change section back to python, override has been fixed. + * Do not duplicate the section in the binary package stanza. + + [ Josselin Mouette ] + * 50_CVE-2009-0317.patch: fix CVE-2009-0317: untrusted search path + vulnerability. Closes: #513419 + * Standards version is 3.8.1. + * Upload to unstable. + * Pass --no-act to dh_makeshlibs. + + -- Josselin Mouette Tue, 07 Apr 2009 15:51:10 +0200 + +nautilus-python (0.5.0-1) experimental; urgency=low + + * New upstream release, depends on Nautilus 2.22 so target experimental + * Add watch file, and patches from Ubuntu + * Also add nasty patch to load libpython2.5.so.1. Ugly. + + -- Ross Burton Sun, 20 Apr 2008 16:33:37 +0100 + +nautilus-python (0.4.3-2) unstable; urgency=low + + [ Ross Burton ] + * Acknowledge NMU. + * Add to pkg-gnome team maintainership. + * Bump Standards. + * Fix FSF address. + + [ Loic Minier ] + * Add a get-orig-source target to retrieve the upstream tarball. + + -- Ross Burton Thu, 26 Apr 2007 11:12:37 +0100 + +nautilus-python (0.4.3-1.1) unstable; urgency=low + + * NMU. + * Upload to unstable. + * Drop dependency on python2.3, lowering severity of #373465. + + -- Matthias Klose Mon, 1 Jan 2007 11:36:59 +0100 + +nautilus-python (0.4.3-1) experimental; urgency=low + + * New upstream releases. + - Should not cause nautilus to crash anymore. (Closes: #304370) + * Add CDBS' utils. + [debian/rules] + * Add CDBS' simple patch system. + [debian/patches, debian/rules] + * Merge patch by Sam Morris to ease use of the package: + - Add a README.Debian file containing notes on usage. + [debian/README.Debian] + - Create an empty /usr/lib/nautilus/extensions-1.0/python directory for + plugins to be installed into. + [debian/dirs] + - Add missing libeel2-dev (>= 2.6.0) build-dep. + [debian/control] + + -- Loic Minier Wed, 1 Mar 2006 20:36:33 +0100 + +nautilus-python (0.4.1-1) experimental; urgency=low + + [ Ross Burton ] + * New upstream release (closes: #314297) + - Threading fixes (closes: #304019) + - Examples are not installed by default (closes: #309653) + * Change build-dep to nautilus-extension (closes: #323743) + * Tighten build-deps + + [Sebastien Bacher ] + * debian/control: + - build with the current gnome-python packages. + + -- Ross Burton Wed, 12 Oct 2005 21:03:53 +0100 + +nautilus-python (0.3.0-3) unstable; urgency=low + + * Add Depends on python-gnome2 + + -- Ross Burton Tue, 8 Mar 2005 13:44:23 +0000 + +nautilus-python (0.3.0-2) unstable; urgency=low + + * Build-Dep on python-gnome2-dev (closes: #283026) + + -- Ross Burton Mon, 29 Nov 2004 10:46:07 +0000 + +nautilus-python (0.3.0-1) unstable; urgency=low + + * Initial Release. + + -- Ross Burton Wed, 6 Oct 2004 18:02:08 +0100 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index b4de394..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/debian/control b/debian/control index cb7c4a0..c239e42 100644 --- a/debian/control +++ b/debian/control @@ -1,15 +1,42 @@ -Source: template-repository -Section: unknown -Priority: optional -Maintainer: Tsic404 -Build-Depends: debhelper (>= 11) -Standards-Version: 4.1.3 -Homepage: https://github.com/deepin-community/template-repository -#Vcs-Browser: https://salsa.debian.org/debian/deepin-community-template-repository -#Vcs-Git: https://salsa.debian.org/debian/deepin-community-template-repository.git +Source: nautilus-python +Section: python +Maintainer: Debian GNOME Extras Maintainers +Uploaders: Emilio Pozuelo Monfort , + Jeremy Bícha , + Laurent Bigonville +Build-Depends: debhelper-compat (= 13), + dh-sequence-python3, + gtk-doc-tools, + libnautilus-extension-dev (>= 43~beta), + meson (>= 0.59.0), + pkgconf, + python-gi-dev, + python3-dev, + python3-gi +Standards-Version: 4.7.3 +Vcs-Browser: https://salsa.debian.org/gnome-team/extras/nautilus-python +Vcs-Git: https://salsa.debian.org/gnome-team/extras/nautilus-python.git -Package: template-repository +Package: python3-nautilus Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: - +Depends: gir1.2-nautilus-4.1, + python3-gi (>= 3.0), + ${misc:Depends}, + ${python3:Depends}, + ${shlibs:Depends} +Conflicts: python-nautilus +Breaks: clamtk-gnome (<< 6.07-1.1~), + folder-color (<< 0.0.86-0ubuntu4.1~), + nautilus-admin (<< 1.1.9-3.2~), + nautilus-hide (<< 0.2.3-8.1~), + nautilus-kdeconnect (<< 21.12.3-1.1~), + nautilus-nextcloud (<< 3.5.1-2.1~), + nautilus-owncloud (<< 2.6.3.14058+dfsg-1.1~), + rabbitvcs-nautilus (<< 0.18-3.1~), + subliminal-nautilus (<< 2.1.0-1.1~), + tortoisehg-nautilus (<< 6.2-1.1~) +Description: Python binding for Nautilus components (Python 3 version) + Python binding for Nautilus, to allow Nautilus property page and menu item + extensions to be written in Python. + . + This package contains the Python 3 version of the library. diff --git a/debian/copyright b/debian/copyright index f5c805e..2101258 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,9 +1,10 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: template-repository -Source: https://github.com/deepin-community/template-repository +Upstream-Name: nautilus-python +Source: https://download.gnome.org/sources/nautilus-python/ Files: * -Copyright: 2023 Tsic404 +Copyright: 2004,2005 Johan Dahlin + 2003,2004 Novell, Inc. 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 diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 0000000..7ad7f9f --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,17 @@ +[DEFAULT] +pristine-tar = True +debian-branch = debian/latest +upstream-branch = upstream/latest + +[buildpackage] +sign-tags = True + +[dch] +multimaint-merge = True + +[import-orig] +postimport = dch -v%(version)s New upstream release; git add debian/changelog; debcommit +upstream-vcs-tag = %(version%~%.)s + +[pq] +patch-numbers = False diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..e69de29 diff --git a/debian/python3-nautilus.dirs b/debian/python3-nautilus.dirs new file mode 100644 index 0000000..2383610 --- /dev/null +++ b/debian/python3-nautilus.dirs @@ -0,0 +1 @@ +usr/share/nautilus-python/extensions diff --git a/debian/python3-nautilus.docs b/debian/python3-nautilus.docs new file mode 100644 index 0000000..2c2d3b6 --- /dev/null +++ b/debian/python3-nautilus.docs @@ -0,0 +1,3 @@ +AUTHORS +NEWS.md +README.md diff --git a/debian/python3-nautilus.lintian-overrides b/debian/python3-nautilus.lintian-overrides new file mode 100644 index 0000000..2894002 --- /dev/null +++ b/debian/python3-nautilus.lintian-overrides @@ -0,0 +1,2 @@ +# System-wide directory where extensions must be added +python3-nautilus: package-contains-empty-directory [usr/share/nautilus-python/extensions/] diff --git a/debian/rules b/debian/rules index 2d33f6a..3ab9de1 100755 --- a/debian/rules +++ b/debian/rules @@ -1,4 +1,16 @@ -#!/usr/bin/make -f +#! /usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1 -Wl,-z,defs %: dh $@ + +override_dh_auto_configure: + dh_auto_configure -- -Ddocs=enabled + +override_dh_installexamples: + dh_installexamples -A examples/*.py examples/README + +override_dh_makeshlibs: + dh_makeshlibs -ppython3-nautilus --no-act diff --git a/debian/upstream/metadata b/debian/upstream/metadata new file mode 100644 index 0000000..381f88e --- /dev/null +++ b/debian/upstream/metadata @@ -0,0 +1,5 @@ +--- +Bug-Database: https://gitlab.gnome.org/GNOME/nautilus-python/-/issues +Bug-Submit: https://gitlab.gnome.org/GNOME/nautilus-python/-/issues/new +Repository: https://gitlab.gnome.org/gnome/nautilus-python.git +Repository-Browse: https://gitlab.gnome.org/GNOME/nautilus-python/ diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..64675b4 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=4 +opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ +https://download.gnome.org/sources/@PACKAGE@/cache.json \ + [\d.]+/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@ diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..682b5bc --- /dev/null +++ b/default.nix @@ -0,0 +1,107 @@ +/* + +How to use? +*********** + +If you have Nix installed, you can get an environment with everything +needed to compile nautilus-python by running: + + $ nix-shell + +at the root of the nautilus-python repository. + +You can also compile nautilus-python and ‘install’ it by running: + + $ nix-build + +at the root of the nautilus-python repository. The command will install +nautilus-python to a location under Nix store and create a ‘result’ symlink +in the current directory pointing to the in-store location. + +The dependencies are pinned, you can update them to latest versions with: + + $ nix-shell --run 'npins update' + +How to tweak default arguments? +******************************* + +Nix supports the ‘--arg’ option (see nix-build(1)) that allows you +to override the top-level arguments. + +For instance, to use your local copy of Nixpkgs: + + $ nix-build --arg pkgs "import $HOME/Projects/nixpkgs {}" + +Or to speed up the build by not running the test suite: + + $ nix-build --arg doCheck false + +*/ + +{ + # Nixpkgs instance, will default to one from npins. + pkgs ? null, + # Whether to run tests when building File Roller using nix-build. + doCheck ? true, + # Whether to build File Roller, or shell for developing it. + # We do not use lib.inNixShell because that would also apply + # when in a nix-shell of some package depending on this one. + shell ? false, +} @ args: + +let + # Pinned Nix dependencies (e.g. Nixpkgs) managed by npins. + sources = import ./npins/default.nix; + + # Setting pkgs to the pinned version + # when not overridden in args. + pkgs = + if args.pkgs or null == null + then + import sources.nixpkgs { + overlays = []; + config = {}; + } + else args.pkgs; + + inherit (pkgs) lib; + + # Function for building File Roller or shell for developing it. + makeDerivation = + if shell + then pkgs.mkShell + else pkgs.stdenv.mkDerivation; +in +makeDerivation rec { + name = "nautilus-python"; + + outputs = [ "out" "devdoc" ]; + + src = + let + # Do not copy to the store paths listed in .gitignore files + cleanSource = path: pkgs.nix-gitignore.gitignoreFilterRecursiveSource (_: _: true) [ ] path; + in + if shell then null else cleanSource ./.; + + # Dependencies for build platform + nativeBuildInputs = with pkgs; ([ + pkg-config + meson + ninja + gtk-doc + docbook-xsl-nons + docbook_xml_dtd_412 + ] ++ lib.optionals shell [ + npins + ]); + + # Dependencies for host platform + buildInputs = with pkgs; [ + python3 + python3.pkgs.pygobject3 + nautilus + ]; + + inherit doCheck; +} diff --git a/docs/reference/entities.docbook.in b/docs/reference/entities.docbook.in new file mode 100644 index 0000000..7b2eb41 --- /dev/null +++ b/docs/reference/entities.docbook.in @@ -0,0 +1 @@ + diff --git a/docs/reference/meson.build b/docs/reference/meson.build new file mode 100644 index 0000000..4e90e00 --- /dev/null +++ b/docs/reference/meson.build @@ -0,0 +1,42 @@ +entities = configure_file( + input: 'entities.docbook.in', + output: 'entities.docbook', + configuration: { + 'VERSION': meson.project_version(), + }, +) + +gnome.gtkdoc( + 'nautilus-python', + main_xml: 'nautilus-python-ref.xml', + src_dir: 'src', + content_files: [ + entities, + 'nautilus-python-class-reference.xml', + 'nautilus-python-column-provider.xml', + 'nautilus-python-column.xml', + 'nautilus-python-enum-reference.xml', + 'nautilus-python-file-info.xml', + 'nautilus-python-info-provider.xml', + 'nautilus-python-menu-item.xml', + 'nautilus-python-menu-provider.xml', + 'nautilus-python-menu.xml', + 'nautilus-python-migrating-to-4.xml', + 'nautilus-python-operation-result.xml', + 'nautilus-python-overview-example.xml', + 'nautilus-python-overview-methods.xml', + 'nautilus-python-overview.xml', + 'nautilus-python-properties-item.xml', + 'nautilus-python-properties-model-provider.xml', + 'nautilus-python-properties-model.xml', + 'nautilus-python-provider-reference.xml', + '../../examples/TestExtension.py', + '../../examples/background-image.py', + '../../examples/block-size-column.py', + '../../examples/md5sum-properties-model.py', + '../../examples/open-terminal.py', + '../../examples/submenu.py', + '../../examples/update-file-info-async.py', + ], + install: true, +) diff --git a/docs/reference/nautilus-python-class-reference.xml b/docs/reference/nautilus-python-class-reference.xml new file mode 100644 index 0000000..62fcf8e --- /dev/null +++ b/docs/reference/nautilus-python-class-reference.xml @@ -0,0 +1,15 @@ + + + + + Available Classes + + + + + + + + diff --git a/docs/reference/nautilus-python-column-provider.xml b/docs/reference/nautilus-python-column-provider.xml new file mode 100644 index 0000000..7d52970 --- /dev/null +++ b/docs/reference/nautilus-python-column-provider.xml @@ -0,0 +1,85 @@ + + + + + + Nautilus.ColumnProvider + + + Nautilus.ColumnProvider + Nautilus.ColumnProvider Reference + + + + + + + + Synopsis + + + Nautilus.ColumnProvider + + + get_columns + + + + + + + + + + + Description + + + If subclassed, Nautilus will request a list of Nautilus.Column + objects, which are then displayed when the user is in List mode. + + An extension sub-classing Nautilus.ColumnProvider + will almost always want to sub-class Nautilus.InfoProvider + as well, since that is how an extension provides information for each item in a directory listing. + + + + + Nautilus.ColumnProvider Example + + + + + + + + + + + Passive Methods + + + Nautilus.ColumnProvider.get_columns + + + get_columns + + + + + + Returns : + a list of Nautilus.Column + + + + + The get_columns() method returns a list of + Nautilus.Column. + + + + + + diff --git a/docs/reference/nautilus-python-column.xml b/docs/reference/nautilus-python-column.xml new file mode 100644 index 0000000..5f30495 --- /dev/null +++ b/docs/reference/nautilus-python-column.xml @@ -0,0 +1,162 @@ + + + + + + Nautilus.Column + + + Nautilus.Column + Nautilus.Column Reference + + + + + + + + Synopsis + + + Nautilus.Column + gobject.GObject + + + Nautilus.Column + name + attribute + label + description + + + + + + + + + + Ancestry + ++-- gobject.GObject + +-- Nautilus.Column + + + + + + + + + + Description + + + A list of Nautilus.Column objects is returned by Nautilus.ColumnProvider extensions. + + + + + + + + + + + Properties + +
+ + + + + + + + + "attribute" + The attribute name to display. Default value: None + Read-Write + + + + "attribute-q" + The attribute name to display, in quark form. Default value: 0 + Read + + + + "description" + The user-visible description of the column. Default value: None + Read-Write + + + + "label" + The label to display in the column. Default value: None + Read-Write + + + + "name" + The name of the column. Default value: None + Read-Write-ConstructOnly + + + + "xalign" + The x-alignment of the column. Allowed values: [0,1]. Default value: 0 + Read-Write + + + + + +
+
+ + + + + + + + Constructor + + + Nautilus.Column + name + attribute + label + description + + + + + 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 Nautilus.Column object. + + + + + +
+ diff --git a/docs/reference/nautilus-python-enum-reference.xml b/docs/reference/nautilus-python-enum-reference.xml new file mode 100644 index 0000000..bcc95f7 --- /dev/null +++ b/docs/reference/nautilus-python-enum-reference.xml @@ -0,0 +1,10 @@ + + + + + Available Enums + + + diff --git a/docs/reference/nautilus-python-file-info.xml b/docs/reference/nautilus-python-file-info.xml new file mode 100644 index 0000000..3a7c380 --- /dev/null +++ b/docs/reference/nautilus-python-file-info.xml @@ -0,0 +1,423 @@ + + + + + + Nautilus.FileInfo + + + Nautilus.FileInfo + Nautilus.FileInfo Reference + + + + + + + + Synopsis + + + Nautilus.FileInfo + gobject.GInterface + + + is_gone + + + + + get_file_type + + + + + get_location + + + + + get_name + + + + + get_uri + + + + + get_activation_uri + + + + + get_parent_info + + + + + get_parent_location + + + + + get_parent_uri + + + + + get_mount + + + + + get_uri_scheme + + + + + get_mime_type + + + + + is_mime_type + mime_type + + + + is_directory + + + + + can_write + + + + + add_emblem + emblem_name + + + + get_string_attribute + attribute_name + + + + add_string_attribute + attribute_name + value + + + + invalidate_extension_info + + + + + + + + + + + + Ancestry + ++-- gobject.GInterface + +-- Nautilus.FileInfo + + + + + + + + + + Description + + + Nautilus.FileInfo objects are passed + to extensions by the Nautilus.InfoProvider. + + + + + + + + + + + Public Methods + + + Nautilus.FileInfo.is_gone + + is_gone + + + + Returns : + whether the file still exists + + + + + + Nautilus.FileInfo.get_file_type + + get_file_type + + + + Returns : + the gio.FileType associated with the file + + + + + + Nautilus.FileInfo.get_location + + get_location + + + + Returns : + the gio.File associated with the file + + + + + + Nautilus.FileInfo.get_name + + get_name + + + + Returns : + the basename of the file + + + + + + Nautilus.FileInfo.get_uri + + get_uri + + + + Returns : + the uri of the file + + + + + + Nautilus.FileInfo.get_activation_uri + + get_activation_uri + + + + Returns : + the activation uri of the file + + + + + + Nautilus.FileInfo.get_parent_info + + get_parent_info + + + + Returns : + the Nautilus.FileInfo object associated with the file's parent + + + + + + Nautilus.FileInfo.get_parent_location + + get_parent_location + + + + Returns : + the gio.File associated with the file's parent location + + + + + + Nautilus.FileInfo.get_parent_uri + + get_parent_uri + + + + Returns : + the uri of the file's parent + + + + + + Nautilus.FileInfo.get_mount + + get_mount + + + + Returns : + the gio.GMount associated with the file, if it exists + + + + + + Nautilus.FileInfo.get_uri_scheme + + get_uri_scheme + + + + Returns : + the uri scheme of the file + + + + + + Nautilus.FileInfo.get_mime_type + + get_mime_type + + + + Returns : + the mimetype of the file + + + + + + Nautilus.FileInfo.is_mime_type + + is_mime_type + mimetype + + + + mimetype : + a mimetype string (i.e. "text/plain") + + + Returns : + whether the file's mimetype string matches the provided mimetype string + + + + + + Nautilus.FileInfo.is_directory + + is_directory + + + + Returns : + whether the item is a directory + + + + + + Nautilus.FileInfo.can_write + + can_write + + + + Returns : + whether the file is writeable + + + + + + Nautilus.FileInfo.add_emblem + + add_emblem + emblem_name + + + + emblem_name : + the name of an emblem to add + + + + + + Nautilus.FileInfo.get_string_attribute + + get_string_attribute + attribute_name + + + + attribute_name : + a string attribute name + + + Returns : + the value associated with the file attribute + + + + + + Nautilus.FileInfo.add_string_attribute + + add_string_attribute + attribute_name + value + + + + attribute_name : + a string attribute name + + + value : + an attribute value + + + + + + Nautilus.FileInfo.invalidate_extension_info + + invalidate_extension_info + + Invalidates the information Nautilus has about this file, which causes it to request new information + from its Nautilus.InfoProvider providers. + + + + + + + diff --git a/docs/reference/nautilus-python-info-provider.xml b/docs/reference/nautilus-python-info-provider.xml new file mode 100644 index 0000000..c9b2c2b --- /dev/null +++ b/docs/reference/nautilus-python-info-provider.xml @@ -0,0 +1,239 @@ + + + + + + Nautilus.InfoProvider + + + Nautilus.InfoProvider + Nautilus.InfoProvider Reference + + + + + + + + Synopsis + + + Nautilus.InfoProvider + + + update_file_info + file + + + + update_file_info_full + provider + handle + closure + file + + + + cancel_update + provider + handle + + + + Nautilus.info_provider_update_complete_invoke + provider + handle + closure + resultNautilus.OperationResult.COMPLETE + + + + + + + + + + Description + + + If subclassed, Nautilus will call update_file_info(_full) to notify extensions of which + files are being viewed by the user. This gives extensions an opportunity to invoke actions on the files, + or to add emblems or attributes. + + + + Nautilus.InfoProvider Example + + + + + + + + + + + Passive Methods + + + Nautilus.InfoProvider.update_file_info + + + update_file_info + file + + + + + file : + a Nautilus.FileInfo object + + + + + This method is called by Nautilus for each file or folder that exists under the + current directory listing. There is no return value. + + + + + + Nautilus.InfoProvider.update_file_info_full + + + update_file_info_full + provider + handle + closure + file + + + + + provider : + the current Nautilus.InfoProvider instance + + + handle : + a gobject.gpointer generated solely to track this call + + + closure : + a C Closure that must be passed to Nautilus.info_provider_update_complete_invoke if that method is called + + + file : + a Nautilus.FileInfo object + + + Returns : + None or a Nautilus.OperationResult enum + + + + + This method is called by Nautilus for each file or folder that exists under the + current directory listing. Originally, Nautilus.InfoProvider + only provided the update_file_info + method, which blocked Nautilus when the method required a lot of computation time. This method was + created to allow an extension to tell Nautilus that it will be spending time on an operation and that + Nautilus should not block itself during that time. + + + In order to notify Nautilus of your extension's intentions, you must return a + Nautilus.OperationResult enum. + Then, when the operation has completed, call the Nautilus.info_provider_update_complete_invoke method, passing the provider, + handle and closure variables as parameters. + + + This method was created for backwards compatibility reasons. If your + extension used the update_file_info method and you want non-blocking + usage, you should switch to this method. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + Nautilus.InfoProvider.cancel_update + + + cancel_update + provider + handle + + + + + provider : + the current Nautilus.InfoProvider instance + + + handle : + a gobject.gpointer generated by a specific update_file_info_full call + + + + + This method is called by Nautilus when an update_file_info_full call is in progress + but is no longer required. This may happen because the user is moving directories or a file + has been deleted, etc. You may use the handle parameter here to match the + handle parameter passed in update_file_info_full. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + Active Methods + + + Nautilus.info_provider_update_complete_invoke + + + info_provider_update_complete_invoke + provider + handle + closure + resultNautilus.OperationResult.COMPLETE + + + + + provider : + the current Nautilus.InfoProvider instance + + + handle : + a gobject.gpointer generated by a specific update_file_info_full call + + + closure : + a C Closure that must be passed to Nautilus.info_provider_update_complete_invoke if that method is called + + + result : + an optional parameter. If left out, Nautilus.OperationResult.COMPLETE is assumed. + Otherwise, you may pass any any of the Nautilus.OperationResult enums. + + + + + An extension must call this method for each update_file_info_full method that + returns the Nautilus.OperationResult.IN_PROGRESS enum. + The method must be called with the provider, handle, and closure parameters which were passed to the earlier update_file_info_full method. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + diff --git a/docs/reference/nautilus-python-menu-item.xml b/docs/reference/nautilus-python-menu-item.xml new file mode 100644 index 0000000..c630dc7 --- /dev/null +++ b/docs/reference/nautilus-python-menu-item.xml @@ -0,0 +1,248 @@ + + + + + + Nautilus.MenuItem + + + Nautilus.MenuItem + Nautilus.MenuItem Reference + + + + + + + + Synopsis + + + Nautilus.MenuItem + gobject.GObject + + + Nautilus.MenuItem + name + label + + + + activate + + + + set_submenu + menu + + + + + + + + + + + Ancestry + ++-- gobject.GObject + +-- Nautilus.MenuItem + + + + + + + + + + Description + + + Nautilus.MenuItem objects are appended to lists to create menus and submenus. + + + + + + + + + + + Properties + +
+ + + + + + + + + "label" + The label to display to the user. Default value: None + Read-Write + + + + "menu" + The Nautilus.Menu menu object belonging to this item. May be None. + Read-Write + + + + "name" + The name of the item. Default value: None + Read-Write-ConstructOnly + + + + "sensitive" + Whether or not the menu item is sensitive. Default value: True + Read-Write + + + + + +
+
+ + + + + + + + Signals + + + "activate" + + callback + item + user_param1 + ... + + + + + + + + + + + + + + + Constructor + + + Nautilus.MenuItem + name + label + + + + + name : + identifier of the item + + + label : + the user-visible label for the item + + + + + Creates a new Nautilus.MenuItem object. + + + + + + + + + + Public Methods + + + Nautilus.MenuItem.activate + + activate + + + + Generates the "activate" signal for this Nautilus.MenuItem. + + + + + Nautilus.MenuItem.set_submenu + + set_submenu + menu + + + + menu : + a Nautilus.Menu + + + + Attaches a Nautilus.Menu as the submenu for this Nautilus.MenuItem. + + + + + + + + + + + Signal Details + + + The "activate" Nautilus.MenuItem Signal + + + callback + item + user_param1 + ... + + + + + item : + the Nautilus.MenuItem being activated + + + user_param1 : + User-defined parameter the user attaches to the signal connector + + + ... : + Additional parameter(s) the user attaches to the signal connector + + + + + Emits the "activate" signal. + + + + + + + +
+ diff --git a/docs/reference/nautilus-python-menu-provider.xml b/docs/reference/nautilus-python-menu-provider.xml new file mode 100644 index 0000000..5e0542e --- /dev/null +++ b/docs/reference/nautilus-python-menu-provider.xml @@ -0,0 +1,280 @@ + + + + + + Nautilus.MenuProvider + + + Nautilus.MenuProvider + Nautilus.MenuProvider Reference + + + + + + + + Synopsis + + + Nautilus.MenuProvider + + + get_file_items + files + + + + get_file_items_full + provider + files + + + + get_background_items + folder + + + + get_background_items_full + provider + folder + + + + Nautilus.menu_provider_emit_items_updated_signal + provider + + + + + + + + + + Description + + + If subclassed, Nautilus will request a list of Nautilus.MenuItem objects, + which are then attached to various menus. Nautilus expects at least one of + the following methods to be defined (or their *_full variants): get_file_items or + get_background_items. + + The get_toolbar_items methods were removed in nautilus-python 1.0 because they were removed from Nautilus 3. Technically, you should still be + able to call those methods with nautilus-python 1.0 if you are running Nautilus 2.x with annotations. + + + + Nautilus.MenuProvider Example + + + + + + + + + + Signals + + + "items-updated" + + callback + + + + + + + + + + + + + + + Passive Methods + + + Nautilus.MenuProvider.get_file_items + + + get_file_items + files + + + + + menu : + a list of Nautilus.FileInfo objects. + + + Returns : + a list of Nautilus.MenuItem objects + + + + + The get_file_items() method returns a list of + Nautilus.MenuItem objects. + + + + + Nautilus.MenuProvider.get_file_items_full + + + get_file_items_full + provider + files + + + + + provider : + the current Nautilus.MenuProvider instance + + + files : + a list of Nautilus.FileInfo objects. + + + Returns : + a list of Nautilus.MenuItem objects + + + + + The get_file_items_full() method returns a list of + Nautilus.MenuItem objects. + + + This method was created in order to allow extension writers to call the + Nautilus.menu_provider_emit_items_updated_signal, which must + be passed the current provider instance. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + Nautilus.MenuProvider.get_background_items + + + get_background_items + folder + + + + + folder : + the current folder, as a Nautilus.FileInfo object. + + + Returns : + a list of Nautilus.MenuItem objects + + + + + The get_background_items() method returns a list of + Nautilus.MenuItem objects. + + + + + Nautilus.MenuProvider.get_background_items_full + + + get_background_items_full + provider + folder + + + + + provider : + the current Nautilus.MenuProvider instance + + + folder : + the current folder, as a Nautilus.FileInfo object. + + + Returns : + a list of Nautilus.MenuItem objects + + + + + The get_background_items_full() method returns a list of + Nautilus.MenuItem objects. + + + This method was created in order to allow extension writers to call the + Nautilus.menu_provider_emit_items_updated_signal, which must + be passed the current provider instance. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + + Active Methods + + + Nautilus.menu_provider_emit_items_updated_signal + + + menu_provider_emit_items_updated_signal + provider + + + + + provider : + the current Nautilus.MenuProvider instance + + + + + Emits the "items-updated" signal. + + + This method was introduced in nautilus-python 0.7.0. + + + + + + + + + + + + Signal Details + + + The "items-updated" Nautilus.MenuProvider Signal + + + Emits the "items-updated" signal. + + + + + + + + diff --git a/docs/reference/nautilus-python-menu.xml b/docs/reference/nautilus-python-menu.xml new file mode 100644 index 0000000..e1ccbf8 --- /dev/null +++ b/docs/reference/nautilus-python-menu.xml @@ -0,0 +1,126 @@ + + + + + + Nautilus.Menu + + + Nautilus.Menu + Nautilus.Menu Reference + + + + + + + + Synopsis + + + Nautilus.Menu + gobject.GObject + + + Nautilus.Menu + + + + append_item + item + + + + get_items + + + + + + + + + + + Ancestry + ++-- gobject.GObject + +-- Nautilus.Menu + + + + + + + + + + Description + + + A Nautilus.Menu object allows an extension to create sub-menus. + + + + + + + + + + + + Constructor + + + Nautilus.Menu + + + + Creates a new Nautilus.Menu object. + + + + + + + + + + + Public Methods + + + Nautilus.Menu.append_item + + append_item + item + + + + item : + a Nautilus.MenuItem + + + + + Append a Nautilus.MenuItem to a Nautilus.Menu. + + + + + Nautilus.Menu.get_items + + get_items + + + Returns a list of Nautilus.MenuItem objects attached to the Nautilus.Menu. + + + + + + + + diff --git a/docs/reference/nautilus-python-migrating-to-4.xml b/docs/reference/nautilus-python-migrating-to-4.xml new file mode 100644 index 0000000..64bb353 --- /dev/null +++ b/docs/reference/nautilus-python-migrating-to-4.xml @@ -0,0 +1,54 @@ + + + + + Migrating to Nautilus API 4.0 + + Nautilus 43 no longer allows extensions to directly manipulate GTK widgets – all UI changes now need to happen through model objects. If your script implements any of the following provider interfaces, you will need to update it: + + + LocationWidgetProvider + The Nautilus.LocationWidgetProvider was removed without replacement. If your script requires it, you can request a new model-based API for your specific use case on the Nautilus issue tracker. + + + + MenuProvider + The get_file_items, get_file_items_full, get_background_items a get_background_items_full methods of Nautilus.MenuProvider no longer take the window argument. Remove it from your implementations. + If you need to keep supporting older versions of Nautilus, you can use variadic arguments: + + def get_file_items(self, *args): + # `args` will be `[files: List[Nautilus.FileInfo]]` in Nautilus 4.0 API, + # and `[window: Gtk.Widget, files: List[Nautilus.FileInfo]]` in Nautilus 3.0 API. + files = args[-1] + + + + + PropertyPageProvider + The Nautilus.PropertyPageProvider was replaced by Nautilus.PropertiesModelProvider class. Unlike the previous unrestricted property pages that could contain any GTK widget, the new model-based interface currently only supports a pre-defined layout. Scripts can add pages, each of which can display a list of text properties. + Subclass the Nautilus.PropertiesModelProvider abstract class and have the get_models method return the list of Nautilus.PropertiesModel, one for each properties page. + If you need to keep supporting older versions of Nautilus, you can keep the old definition conditionally: + + if hasattr(Nautilus, "PropertiesModelProvider"): + # For Nautilus 4.0 API + class MD5SumPropertiesModel(GObject.GObject, Nautilus.PropertiesModelProvider): + ... +else: + class MD5SumPropertyPage(GObject.GObject, Nautilus.PropertyPageProvider): + ... + + + + + Direct use of GTK and other libraries + If you use GTK directly, e.g. to create dialogue windows, you will need to upgrade the code to GTK 4 as well, since Nautilus switched to GTK 4 and it is not possible to use multiple versions of GTK in the same process. Do not forget to replace gi.require_version("Gtk", "3.0") with gi.require_version("Gtk", "4.0"), then. + The other option is moving the window and dialogues into a separate program and having the extension just launch it. But unless the code base is very large, migrating to GTK 4 will probably be easier. + + + + More information + See the relevant Nautilus change for more context and the corresponding nautilus-python update for more migration examples. + + + diff --git a/docs/reference/nautilus-python-operation-result.xml b/docs/reference/nautilus-python-operation-result.xml new file mode 100644 index 0000000..5e9b661 --- /dev/null +++ b/docs/reference/nautilus-python-operation-result.xml @@ -0,0 +1,59 @@ + + + + + + Nautilus.OperationResult + + + Nautilus.OperationResult + Nautilus.OperationResult Reference + + + + + + + + + + Description + + + The Nautilus.OperationResult constants are + used by the Nautilus.InfoProvider provider to + notify Nautilus what the extension intends to do when Nautilus calls the extension's update_file_info_full + method. The possible values are as follows: + + + + + + Nautilus.OperationResult.COMPLETE + + The operation is complete and Nautilus can move on to the next update_file_info_full call. + + + + Nautilus.OperationResult.IN_PROGRESS + + The operation is in progress and running asynchronously and Nautilus should wait until the Nautilus.info_provider_update_complete_invoke method + is called before moving on to the next update_file_info_full call. + + + + Nautilus.OperationResult.FAILED + + The operation has failed. + + + + + + + + + + + diff --git a/docs/reference/nautilus-python-overview-example.xml b/docs/reference/nautilus-python-overview-example.xml new file mode 100644 index 0000000..887e266 --- /dev/null +++ b/docs/reference/nautilus-python-overview-example.xml @@ -0,0 +1,30 @@ + + + + + A Simple Extension + + Create an empty file with the following code: + + + A Simple Extension + + + + Save this file as TestExtension.py in the ~/.local/share/nautilus-python/extensions folder. + You may need to create this folder. To run, simply restart Nautilus. + + Once Nautilus restarts, right-click on a file and you should see a new menu item, + "Showing #filename#". It is as simple as that! + + As mentioned above, in order to + get loaded by Nautilus, a python extension must import the Nautilus module from gi.repository, + create a class derived from a nautilus *Provider and a gobject.GObject, and create the methods that + will be called by Nautilus when it requests information from its providers. + In this case, when someone right-clicks on a file, Nautilus will ask all of its + MenuProviders for additional menu items to show the user. When folders or files are clicked, + the get_file_items method is called and a list of Nautilus.MenuItems is expected. + + diff --git a/docs/reference/nautilus-python-overview-methods.xml b/docs/reference/nautilus-python-overview-methods.xml new file mode 100644 index 0000000..c56aa82 --- /dev/null +++ b/docs/reference/nautilus-python-overview-methods.xml @@ -0,0 +1,20 @@ + + + + + + Explanation of Passive/Active Methods + + Because nautilus-python is an interface to a Nautilus' extension interface rather than a true library, it is + rather quirky in how it works. One example of this is that several providers have additional public methods + that an extension actively calls, rather than the extension defining and the method in their class that is called by + Nautilus. You can see this with the Nautilus.menu_provider_emit_items_updated_signal + and Nautilus.info_provider_update_complete_invoke methods, which + the extension actively calls, passing the provider instance as a parameter. + + + Due to this confusion, I have termed these actively-called methods Active Methods and the methods + called by Nautilus are termed Passive Methods. + diff --git a/docs/reference/nautilus-python-overview.xml b/docs/reference/nautilus-python-overview.xml new file mode 100644 index 0000000..b370940 --- /dev/null +++ b/docs/reference/nautilus-python-overview.xml @@ -0,0 +1,41 @@ + + + + + Overview + + Writing a Nautilus-Python extension is a fairly straight-forward process. One simply imports the Nautilus module from the GObject Introspection repository and creates a class which is derived from a GObject.GObject and one or more of the Nautilus module’s abstract classes. When an extension derives a class, it becomes a “provider”, telling Nautilus to ask it for information. + + There are several types of providers available for extensions to use, all of which will be explained in more detail in later chapters: + + + ColumnProvider + InfoProvider + MenuProvider + PropertiesModelProvider + + + Your class can be derived from multiple providers. + + Then the script needs to be installed to one of the paths nautilus-python looks for extensions to. That will be nautilus-python/extensions subdirectory of one of the following data directories: + + the path in XDG_DATA_HOME environment variable , falling back to $HOME/.local/share if not set + datadir configured when building nautilus-python (such as /usr/local/share) + Any path listed in the XDG_DATA_DIRS environment variable + + + After that, you will need to (re)start Nautilus, which will loads the nautilus-python C extension, which in turn will load all python extensions it can find. + + + Do not forget to have the extension class derive from a GObject.GObject in addition to the standard Nautilus classes. + + + + For now, some Nautilus class constructors require passing named arguments instead of a standard argument list. This requirement may go away at some point. + + + + + + diff --git a/docs/reference/nautilus-python-properties-item.xml b/docs/reference/nautilus-python-properties-item.xml new file mode 100644 index 0000000..e01c0cb --- /dev/null +++ b/docs/reference/nautilus-python-properties-item.xml @@ -0,0 +1,163 @@ + + + + + + Nautilus.PropertiesItem + + + Nautilus.PropertiesItem + Nautilus.PropertiesItem Reference + + + + + + + + Synopsis + + + Nautilus.PropertiesItem + gobject.GObject + + + Nautilus.PropertiesItem + name + value + + + + get_name + + + + get_value + + + + + + + + + + Ancestry + ++-- gobject.GObject + +-- Nautilus.PropertiesItem + + + + + + + + + + Description + + + Nautilus.PropertiesItem is an object that describes a name & value pair in file properties. Extensions can provide Nautilus.PropertiesItem objects grouped in Nautilus.PropertiesModel. + + + + + + + + + + + Properties + +
+ + + + + + + + + "name" + The user-visible name for the properties item + Read-Write-ConstructOnly + + + + "value" + The user-visible value for the properties item + Read-Write-ConstructOnly + + + + + +
+
+ + + + + + + + Constructor + + + Nautilus.PropertiesItem + name + value + + + + + name : + the user-visible name for the properties item + + + value : + the user-visible value for the properties item + + + + + Creates a new Nautilus.PropertiesItem object. + + + + + + + + + + + Public Methods + + + Nautilus.Menu.get_name + + get_name + + + Returns the name of this Nautilus.PropertiesItem. + + + + + Nautilus.Menu.get_value + + get_value + + + Returns the value of this Nautilus.PropertiesItem. + + + + + + +
+ diff --git a/docs/reference/nautilus-python-properties-model-provider.xml b/docs/reference/nautilus-python-properties-model-provider.xml new file mode 100644 index 0000000..2fa72e2 --- /dev/null +++ b/docs/reference/nautilus-python-properties-model-provider.xml @@ -0,0 +1,84 @@ + + + + + + Nautilus.PropertiesModelProvider + + + Nautilus.PropertiesModelProvider + Nautilus.PropertiesModelProvider Reference + + + + + + + + Synopsis + + + Nautilus.PropertiesModelProvider + + + get_models + files + + + + + + + + + + Description + + + If subclassed, Nautilus will request a list of custom properties models that should + appear when a user opens the Properties dialog for a file or folder. + + + + Nautilus.PropertiesModelProvider Example + + + + + + + + + + + Passive Methods + + + Nautilus.PropertiesModelProvider.get_models + + + get_models + files + + + + + files : + a list of Nautilus.FileInfo objects. + + + Returns : + a list of Nautilus.PropertiesModel objects + + + + + This function is called by Nautilus when it wants properties model items from the extension. + It is called in the main thread before a properties model is shown, so it should return quickly. + + + + + + diff --git a/docs/reference/nautilus-python-properties-model.xml b/docs/reference/nautilus-python-properties-model.xml new file mode 100644 index 0000000..c7aee70 --- /dev/null +++ b/docs/reference/nautilus-python-properties-model.xml @@ -0,0 +1,187 @@ + + + + + + Nautilus.PropertiesModel + + + Nautilus.PropertiesModel + Nautilus.PropertiesModel Reference + + + + + + + + Synopsis + + + Nautilus.PropertiesModel + gobject.GObject + + + Nautilus.PropertiesModel + title + model + + + + set_title + title + + + + get_title + + + + get_model + + + + + + + + + + Ancestry + ++-- gobject.GObject + +-- Nautilus.PropertiesModel + + + + + + + + + + Description + + + A Nautilus.PropertiesModel object an model that describes a set of file properties. Extensions can provide Nautilus.PropertiesModel objects by registering it in Nautilus.PropertiesModelProvider. + + + + + + + + + + + Properties + +
+ + + + + + + + + "title" + The user-visible name for the set of properties in this model. + Read-Write + + + + "model" + The GListModel containing Nautilus.PropertyItem objects. Default value: [] + Read-Write-ConstructOnly + + + + + +
+
+ + + + + + + + Constructor + + + Nautilus.PropertiesModel + title + model + + + + + title : + the user-visible name for the set of properties in this model + + + model : + The GListModel containing Nautilus.PropertyItem objects. + + + + + Creates a new Nautilus.PropertiesModel object. + + + + + + + + + + + Public Methods + + + Nautilus.Menu.set_title + + set_title + title + + + + title : + a new name of this Nautilus.PropertiesModel + + + + + Sets a new name of this Nautilus.PropertiesModel. + + + + + Nautilus.Menu.get_title + + get_title + + + Returns the title of this Nautilus.PropertiesModel. + + + + + Nautilus.Menu.get_model + + get_model + + + Returns a GListModel containing Nautilus.PropertyItem objects. + + + + + + +
+ diff --git a/docs/reference/nautilus-python-provider-reference.xml b/docs/reference/nautilus-python-provider-reference.xml new file mode 100644 index 0000000..4a87e3a --- /dev/null +++ b/docs/reference/nautilus-python-provider-reference.xml @@ -0,0 +1,13 @@ + + + + + Provider Interfaces + + + + + + diff --git a/docs/reference/nautilus-python-ref.xml b/docs/reference/nautilus-python-ref.xml new file mode 100644 index 0000000..470b014 --- /dev/null +++ b/docs/reference/nautilus-python-ref.xml @@ -0,0 +1,33 @@ + + +%entities; +]> + + + nautilus-python Reference Manual + Reference Manual for nautilus-python &version; + For nautilus-python version &version; + + + Adam + Plumb + + + + This reference describes the classes of the nautilus-python module. + + + + + + + + + + + + + + diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..60d0de1 --- /dev/null +++ b/examples/README @@ -0,0 +1,15 @@ +To try any of the examples, copy them over to: + + $XDG_DATA_DIR/share/nautilus-python/extensions/ +or: + ~/.local/share/nautilus-python/extensions/ + +FYI, it is still possible to load plugins from the old locations. + +Then restart nautilus. + +Hint: if you're testing an extension that you're developing, it may +be useful to start a 'private' instance of nautilus, like this: + $ mkdir /tmp/testing + $ export TMPDIR=/tmp/testing + $ nautilus --no-desktop diff --git a/examples/TestExtension.py b/examples/TestExtension.py new file mode 100644 index 0000000..3268de8 --- /dev/null +++ b/examples/TestExtension.py @@ -0,0 +1,42 @@ +from gi.repository import Nautilus, GObject +from typing import List + + +class TestExtension(GObject.GObject, Nautilus.MenuProvider): + def __init__(self): + super().__init__() + print("Initialized test extension") + + def menu_activate_cb( + self, + menu: Nautilus.MenuItem, + file: Nautilus.FileInfo, + ) -> None: + print("menu_activate_cb", file) + + def get_file_items( + self, + files: List[Nautilus.FileInfo], + ) -> List[Nautilus.MenuItem]: + if len(files) != 1: + return [] + + file = files[0] + + item = Nautilus.MenuItem( + name="SimpleMenuExtension::Show_File_Name", + label="Showing %s" % file.get_name(), + ) + item.connect("activate", self.menu_activate_cb, file) + + return [ + item, + ] + + # Even though we're not using background items, Nautilus will generate + # a warning if the method isn't present + def get_background_items( + self, + current_folder: Nautilus.FileInfo, + ) -> List[Nautilus.MenuItem]: + return [] diff --git a/examples/background-image.py b/examples/background-image.py new file mode 100644 index 0000000..9105552 --- /dev/null +++ b/examples/background-image.py @@ -0,0 +1,58 @@ +from gi.repository import Nautilus, GObject, Gio +from typing import List + +SUPPORTED_FORMATS = "image/jpeg", "image/png" +BACKGROUND_SCHEMA = "org.gnome.desktop.background" +BACKGROUND_KEY = "picture-uri" + + +class BackgroundImageExtension(GObject.GObject, Nautilus.MenuProvider): + def __init__(self): + super().__init__() + self.bgsettings = Gio.Settings.new(BACKGROUND_SCHEMA) + + def menu_activate_cb( + self, + menu: Nautilus.MenuItem, + file: Nautilus.FileInfo, + ) -> None: + if file.is_gone(): + return + + self.bgsettings[BACKGROUND_KEY] = file.get_uri() + + def get_file_items( + self, + files: List[Nautilus.FileInfo], + ) -> List[Nautilus.MenuItem]: + if len(files) != 1: + return [] + + file = files[0] + + # We're only going to put ourselves on images context menus + if not file.get_mime_type() in SUPPORTED_FORMATS: + return [] + + # Gnome can only handle file: + # In the future we might want to copy the file locally + if file.get_uri_scheme() != "file": + return [] + + item = Nautilus.MenuItem( + name="Nautilus::set_background_image", + label="Use as background image", + ) + item.connect("activate", self.menu_activate_cb, file) + + return [ + item, + ] + + # Current versions of Nautilus will throw a warning if get_background_items + # isn't present + def get_background_items( + self, + current_folder: Nautilus.FileInfo, + ) -> List[Nautilus.MenuItem]: + return [] diff --git a/examples/block-size-column.py b/examples/block-size-column.py new file mode 100644 index 0000000..0607e8d --- /dev/null +++ b/examples/block-size-column.py @@ -0,0 +1,26 @@ +import os +from urllib.parse import unquote +from gi.repository import GObject, Nautilus +from typing import List + + +class ColumnExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider): + def get_columns(self) -> List[Nautilus.Column]: + column = Nautilus.Column( + name="NautilusPython::block_size_column", + attribute="block_size", + label="Block size", + description="Get the block size", + ) + + return [ + column, + ] + + def update_file_info(self, file: Nautilus.FileInfo) -> None: + if file.get_uri_scheme() != "file": + return + + filename = unquote(file.get_uri()[7:]) + + file.add_string_attribute("block_size", str(os.stat(filename).st_blksize)) diff --git a/examples/md5sum-properties-model.py b/examples/md5sum-properties-model.py new file mode 100644 index 0000000..7180780 --- /dev/null +++ b/examples/md5sum-properties-model.py @@ -0,0 +1,39 @@ +import hashlib + +from urllib.parse import unquote +from gi.repository import Nautilus, Gio, GObject +from typing import List + + +class MD5SumPropertiesModel(GObject.GObject, Nautilus.PropertiesModelProvider): + def get_models( + self, + files: List[Nautilus.FileInfo], + ) -> List[Nautilus.PropertiesModel]: + if len(files) != 1: + return [] + + file = files[0] + if file.get_uri_scheme() != "file": + return [] + + if file.is_directory(): + return [] + + filename = unquote(file.get_uri()[7:]).encode("utf-8") + + section_model = Gio.ListStore.new(item_type=Nautilus.PropertiesItem) + + section_model.append( + Nautilus.PropertiesItem( + name="MD5 sum of the filename", + value=hashlib.md5(filename).hexdigest(), + ) + ) + + return [ + Nautilus.PropertiesModel( + title="MD5Sum", + model=section_model, + ), + ] diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..186c22b --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,15 @@ +install_data( + 'README', + install_dir: docdir, +) + +install_data( + 'background-image.py', + 'block-size-column.py', + 'open-terminal.py', + 'md5sum-properties-model.py', + 'submenu.py', + 'TestExtension.py', + 'update-file-info-async.py', + install_dir: docdir / 'examples', +) diff --git a/examples/open-terminal.py b/examples/open-terminal.py new file mode 100644 index 0000000..d51b2fb --- /dev/null +++ b/examples/open-terminal.py @@ -0,0 +1,62 @@ +# This example is contributed by Martin Enlund +import os +from urllib.parse import unquote +from gi.repository import Nautilus, GObject +from typing import List + + +class OpenTerminalExtension(GObject.GObject, Nautilus.MenuProvider): + def _open_terminal(self, file: Nautilus.FileInfo) -> None: + filename = unquote(file.get_uri()[7:]) + + os.chdir(filename) + os.system("gnome-terminal") + + def menu_activate_cb( + self, + menu: Nautilus.MenuItem, + file: Nautilus.FileInfo, + ) -> None: + self._open_terminal(file) + + def menu_background_activate_cb( + self, + menu: Nautilus.MenuItem, + file: Nautilus.FileInfo, + ) -> None: + self._open_terminal(file) + + def get_file_items( + self, + files: List[Nautilus.FileInfo], + ) -> List[Nautilus.MenuItem]: + if len(files) != 1: + return [] + + file = files[0] + if not file.is_directory() or file.get_uri_scheme() != "file": + return [] + + item = Nautilus.MenuItem( + name="NautilusPython::openterminal_file_item", + label="Open Terminal", + ) + item.connect("activate", self.menu_activate_cb, file) + + return [ + item, + ] + + def get_background_items( + self, + current_folder: Nautilus.FileInfo, + ) -> List[Nautilus.MenuItem]: + item = Nautilus.MenuItem( + name="NautilusPython::openterminal_file_item2", + label="Open Terminal", + ) + item.connect("activate", self.menu_background_activate_cb, current_folder) + + return [ + item, + ] diff --git a/examples/submenu.py b/examples/submenu.py new file mode 100644 index 0000000..2cf167c --- /dev/null +++ b/examples/submenu.py @@ -0,0 +1,48 @@ +from gi.repository import Nautilus, GObject +from typing import List + + +class ExampleMenuProvider(GObject.GObject, Nautilus.MenuProvider): + def get_file_items( + self, + files: List[Nautilus.FileInfo], + ) -> List[Nautilus.MenuItem]: + top_menuitem = Nautilus.MenuItem( + name="ExampleMenuProvider::Foo", + label="Foo", + ) + + submenu = Nautilus.Menu() + top_menuitem.set_submenu(submenu) + + sub_menuitem = Nautilus.MenuItem( + name="ExampleMenuProvider::Bar", + label="Bar", + ) + submenu.append_item(sub_menuitem) + + return [ + top_menuitem, + ] + + def get_background_items( + self, + current_folder: Nautilus.FileInfo, + ) -> List[Nautilus.MenuItem]: + submenu = Nautilus.Menu() + submenu.append_item( + Nautilus.MenuItem( + name="ExampleMenuProvider::Bar2", + label="Bar2", + ) + ) + + menuitem = Nautilus.MenuItem( + name="ExampleMenuProvider::Foo2", + label="Foo2", + ) + menuitem.set_submenu(submenu) + + return [ + menuitem, + ] diff --git a/examples/update-file-info-async.py b/examples/update-file-info-async.py new file mode 100644 index 0000000..7e54ecb --- /dev/null +++ b/examples/update-file-info-async.py @@ -0,0 +1,30 @@ +from gi.repository import Nautilus, GObject + + +class UpdateFileInfoAsync(GObject.GObject, Nautilus.InfoProvider): + def __init__(self): + super().__init__() + self.timers = [] + pass + + def update_file_info_full(self, provider, handle, closure, file): + print("update_file_info_full") + self.timers.append( + GObject.timeout_add_seconds(3, self.update_cb, provider, handle, closure) + ) + return Nautilus.OperationResult.IN_PROGRESS + + def update_cb(self, provider, handle, closure): + print("update_cb") + Nautilus.info_provider_update_complete_invoke( + closure, + provider, + handle, + Nautilus.OperationResult.FAILED, + ) + + def cancel_update(self, provider, handle): + print("cancel_update") + for t in self.timers: + GObject.source_remove(t) + self.timers = [] diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..f266c81 --- /dev/null +++ b/meson.build @@ -0,0 +1,72 @@ +project( + 'nautilus-python', + 'c', + version: '4.1.0', + meson_version: '>= 0.59.0', +) + +gnome = import('gnome', required: get_option('docs')) +pkg = import('pkgconfig') +python = import('python') + +prefix = get_option('prefix') +libdir = get_option('libdir') +# Needs to be absolute for C constant. +datadir = prefix / get_option('datadir') +docdir = datadir / 'doc' / meson.project_name() + +python3 = python.find_installation('python3') +pygobject_major_version = 3 +pygobject_minor_version = 0 +pygobject_micro_version = 0 +pygobject = dependency('pygobject-3.0', version: f'>= @pygobject_major_version@.@pygobject_minor_version@.@pygobject_micro_version@') +libnautilus_extension = dependency('libnautilus-extension-4', version: '>= 43.beta') +if libnautilus_extension.version().version_compare('>= 49') + add_project_arguments('-DNAUTILUS_4_1_API', language: 'c') +endif +gmodule = dependency('gmodule-2.0', version: '>= 2.44') +python_dep = python3.dependency(embed: true) + +nautilus_extension_dir = libnautilus_extension.get_variable('extensiondir', pkgconfig_define: ['libdir', libdir]) + +py_so_filename = python3.get_variable('INSTSONAME') +python_libpath = python3.get_variable('LIBDIR') / py_so_filename + +conf = configuration_data() +conf.set_quoted('DATADIR', datadir) +conf.set('PYGOBJECT_MAJOR_VERSION', pygobject_major_version) +conf.set('PYGOBJECT_MINOR_VERSION', pygobject_minor_version) +conf.set('PYGOBJECT_MICRO_VERSION', pygobject_micro_version) +conf.set_quoted('PYTHON_LIBPATH', python_libpath) + +configure_file( + output: 'config.h', + configuration: conf, +) + +root_incdir = include_directories('.') + +if get_option('docs').enabled() + subdir('docs/reference') +endif +subdir('examples') +subdir('src') + +pkg.generate( + name: 'nautilus-python', + description: 'Nautilus-Python Components', + variables: [ + # TODO: Remove when bumping minimum Meson version to 0.62 + # https://mesonbuild.com/Release-notes-for-0-62-0.html#pkgconfiggenerate-will-now-include-variables-for-builtin-directories-when-referenced + f'prefix=@prefix@', + 'datadir=${prefix}/share', + 'pythondir=${datadir}/nautilus-python/extensions', + ], + dataonly: true, +) + +summary({ + 'PyGObject Version': 'pygobject-3.0', + 'Python Library': python_libpath, + 'Documentation': get_option('docs'), +}) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..00aa079 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,5 @@ +option( + 'docs', + type: 'feature', + description: 'Generate and install API docs', +) diff --git a/nautilus-python.doap b/nautilus-python.doap new file mode 100644 index 0000000..e226ebe --- /dev/null +++ b/nautilus-python.doap @@ -0,0 +1,27 @@ + + + nautilus-python + Python bindings for the Nautilus extension framework + + + + + + Adam Plumb + + adamplumb + + + + + + Jan Tojnar + + jtojnar + + + diff --git a/npins/default.nix b/npins/default.nix new file mode 100644 index 0000000..6592476 --- /dev/null +++ b/npins/default.nix @@ -0,0 +1,146 @@ +/* + This file is provided under the MIT licence: + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = + first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # If the environment variable NPINS_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + # (Taken from Niv for compatibility) + mayOverride = + name: path: + let + envVarName = "NPINS_OVERRIDE_${saneName}"; + saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name; + ersatz = builtins.getEnv envVarName; + in + if ersatz == "" then + path + else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" ( + if builtins.substring 0 1 ersatz == "/" then + /. + ersatz + else + /. + builtins.getEnv "PWD" + "/${ersatz}" + ); + + mkSource = + name: spec: + assert spec ? type; + let + path = + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else if spec.type == "Tarball" then + mkTarballSource spec + else + builtins.throw "Unknown source type ${spec.type}"; + in + spec // { outPath = mayOverride name path; }; + + mkGitSource = + { + repository, + revision, + url ? null, + submodules, + hash, + branch ? null, + ... + }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null && !submodules then + builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + } + else + let + url = + if repository.type == "Git" then + repository.url + else if repository.type == "GitHub" then + "https://github.com/${repository.owner}/${repository.repo}.git" + else if repository.type == "GitLab" then + "${repository.server}/${repository.repo_path}.git" + else + throw "Unrecognized repository type ${repository.type}"; + urlToName = + url: rev: + let + matched = builtins.match "^.*/([^/]*)(\\.git)?$" url; + + short = builtins.substring 0 7 rev; + + appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else ""; + in + "${if matched == null then "source" else builtins.head matched}${appendShort}"; + name = urlToName url revision; + in + builtins.fetchGit { + rev = revision; + inherit name; + # hash = hash; + inherit url submodules; + }; + + mkPyPiSource = + { url, hash, ... }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = + { url, hash, ... }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; + + mkTarballSource = + { + url, + locked_url ? url, + hash, + ... + }: + builtins.fetchTarball { + url = locked_url; + sha256 = hash; + }; +in +if version == 5 then + builtins.mapAttrs mkSource data.pins +else + throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/npins/sources.json b/npins/sources.json new file mode 100644 index 0000000..264a91b --- /dev/null +++ b/npins/sources.json @@ -0,0 +1,11 @@ +{ + "pins": { + "nixpkgs": { + "type": "Channel", + "name": "nixos-unstable", + "url": "https://releases.nixos.org/nixos/unstable/nixos-25.11pre870157.7df7ff7d8e00/nixexprs.tar.xz", + "hash": "1f5zj0dvb29i77qzcnxxzaasp38l98dvfmdabbs7yh8cw4wsy86p" + } + }, + "version": 5 +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..c66c503 --- /dev/null +++ b/shell.nix @@ -0,0 +1,8 @@ +{ + pkgs ? null, + doCheck ? true, +}: +import ./default.nix { + inherit doCheck pkgs; + shell = true; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..5e65446 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,18 @@ +nautilus_python = shared_module( + 'nautilus-python', + sources: [ + 'nautilus-python.c', + 'nautilus-python-object.c', + ], + dependencies: [ + libnautilus_extension, + pygobject, + gmodule, + python_dep, + ], + include_directories: [ + root_incdir, + ], + install: true, + install_dir: nautilus_extension_dir, +) diff --git a/src/nautilus-python-object.c b/src/nautilus-python-object.c new file mode 100644 index 0000000..5966bd1 --- /dev/null +++ b/src/nautilus-python-object.c @@ -0,0 +1,476 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * Copyright (C) 2004,2005 Johan Dahlin + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "nautilus-python-object.h" +#include "nautilus-python.h" + +#include + +#include + +#include + +#define METHOD_PREFIX "" + +static GObjectClass *parent_class; + +/* These macros assumes the following things: + * a METHOD_NAME is defined with is a string + * a goto label called beach + * the return value is called ret + */ + +#define CHECK_METHOD_NAME(self) \ + if (!PyObject_HasAttrString(self, METHOD_NAME)) \ + goto beach; + +#define CHECK_OBJECT(object) \ + if (object->instance == NULL) \ + { \ + g_object_unref (object); \ + goto beach; \ + } \ + +#define CONVERT_LIST(py_files, files) \ + { \ + GList *l; \ + py_files = PyList_New(0); \ + for (l = files; l; l = l->next) \ + { \ + PyObject *item = pygobject_new ((GObject *)l->data); \ + PyList_Append(py_files, item); \ + Py_DECREF (item); \ + } \ + } + +#define HANDLE_RETVAL(py_ret) \ + if (!py_ret) \ + { \ + PyErr_Print(); \ + goto beach; \ + } \ + else if (py_ret == Py_None) \ + { \ + goto beach; \ + } + +#define HANDLE_LIST(py_ret, type, type_name) \ + { \ + Py_ssize_t i = 0; \ + if (!PySequence_Check(py_ret) || PyUnicode_Check(py_ret)) \ + { \ + PyErr_SetString(PyExc_TypeError, \ + METHOD_NAME " must return a sequence"); \ + goto beach; \ + } \ + for (i = 0; i < PySequence_Size (py_ret); i++) \ + { \ + PyGObject *py_item; \ + py_item = (PyGObject*)PySequence_GetItem (py_ret, i); \ + if (!pygobject_check(py_item, &Py##type##_Type)) \ + { \ + PyErr_SetString(PyExc_TypeError, \ + METHOD_NAME \ + " must return a sequence of " \ + type_name); \ + goto beach; \ + } \ + ret = g_list_append (ret, (type*) g_object_ref(py_item->obj)); \ + Py_DECREF(py_item); \ + } \ + } + + +static void +free_pygobject_data(gpointer data, gpointer user_data) { + /* Some NautilusFileInfo objects are cached and not freed until nautilus + itself is closed. Since PyGObject stores data that must be freed by + the Python interpreter, we must always free it before the interpreter + is finalized. */ + g_object_set_data((GObject *)data, "PyGObject::instance-data", NULL); +} + +static void +free_pygobject_data_list(GList *list) { + if (list == NULL) + return; + + g_list_foreach(list, (GFunc)free_pygobject_data, NULL); +} + +static PyObject * +nautilus_python_boxed_new (PyTypeObject *type, gpointer boxed, gboolean free_on_dealloc) { + PyGBoxed *self = (PyGBoxed *) type->tp_alloc (type, 0); + self->gtype = pyg_type_from_object ( (PyObject *) type); + self->boxed = boxed; + self->free_on_dealloc = free_on_dealloc; + + return (PyObject *) self; +} + +#define METHOD_NAME "get_models" +static GList * +nautilus_python_object_get_models (NautilusPropertiesModelProvider *provider, + GList *files) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + PyObject *py_files, *py_ret = NULL; + GList *ret = NULL; + PyGILState_STATE state = pyg_gil_state_ensure(); + + debug_enter(); + + CHECK_OBJECT(object); + CHECK_METHOD_NAME(object->instance); + + CONVERT_LIST(py_files, files); + + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME, + "(N)", py_files); + HANDLE_RETVAL(py_ret); + + HANDLE_LIST(py_ret, NautilusPropertiesModel, "Nautilus.PropertiesModel"); + +beach: + free_pygobject_data_list(files); + Py_XDECREF(py_ret); + pyg_gil_state_release(state); + return ret; +} +#undef METHOD_NAME + +static void +nautilus_python_object_properties_model_provider_interface_init (NautilusPropertiesModelProviderInterface *interface) { + interface->get_models = nautilus_python_object_get_models; +} + +#define METHOD_NAME "get_file_items" +static GList * +nautilus_python_object_get_file_items (NautilusMenuProvider *provider, + GList *files) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + GList *ret = NULL; + PyObject *py_ret = NULL, *py_files; + PyGILState_STATE state = pyg_gil_state_ensure(); + + debug_enter(); + + CHECK_OBJECT(object); + + if (PyObject_HasAttrString(object->instance, "get_file_items_full")) { + CONVERT_LIST(py_files, files); + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX "get_file_items_full", + "(NN)", + pygobject_new((GObject *)provider), + py_files); + } + else if (PyObject_HasAttrString(object->instance, "get_file_items")) { + CONVERT_LIST(py_files, files); + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME, + "(N)", + py_files); + } + else { + goto beach; + } + + HANDLE_RETVAL(py_ret); + + HANDLE_LIST(py_ret, NautilusMenuItem, "Nautilus.MenuItem"); + +beach: + free_pygobject_data_list(files); + Py_XDECREF(py_ret); + pyg_gil_state_release(state); + return ret; +} +#undef METHOD_NAME + +#define METHOD_NAME "get_background_items" +static GList * +nautilus_python_object_get_background_items (NautilusMenuProvider *provider, + NautilusFileInfo *file) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + GList *ret = NULL; + PyObject *py_ret = NULL; + PyGILState_STATE state = pyg_gil_state_ensure(); + + debug_enter(); + + CHECK_OBJECT(object); + + if (PyObject_HasAttrString(object->instance, "get_background_items_full")) { + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX "get_background_items_full", + "(NN)", + pygobject_new((GObject *)provider), + pygobject_new((GObject *)file)); + } + else if (PyObject_HasAttrString(object->instance, "get_background_items")) { + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME, + "(N)", + pygobject_new((GObject *)file)); + } + else { + goto beach; + } + + HANDLE_RETVAL(py_ret); + + HANDLE_LIST(py_ret, NautilusMenuItem, "Nautilus.MenuItem"); + +beach: + free_pygobject_data(file, NULL); + Py_XDECREF(py_ret); + pyg_gil_state_release(state); + return ret; +} +#undef METHOD_NAME + +static void +nautilus_python_object_menu_provider_interface_init (NautilusMenuProviderInterface *interface) { + interface->get_background_items = nautilus_python_object_get_background_items; + interface->get_file_items = nautilus_python_object_get_file_items; +} + +#define METHOD_NAME "get_columns" +static GList * +nautilus_python_object_get_columns (NautilusColumnProvider *provider) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + GList *ret = NULL; + PyObject *py_ret = NULL; + PyGILState_STATE state = pyg_gil_state_ensure(); \ + + debug_enter(); + + CHECK_OBJECT(object); + CHECK_METHOD_NAME(object->instance); + + py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME, + NULL); + + HANDLE_RETVAL(py_ret); + + HANDLE_LIST(py_ret, NautilusColumn, "Nautilus.Column"); + +beach: + if (py_ret != NULL) + Py_XDECREF(py_ret); + pyg_gil_state_release(state); + return ret; +} +#undef METHOD_NAME + +static void +nautilus_python_object_column_provider_interface_init (NautilusColumnProviderInterface *interface) { + interface->get_columns = nautilus_python_object_get_columns; +} + + +#define METHOD_NAME "cancel_update" +static void +nautilus_python_object_cancel_update (NautilusInfoProvider *provider, + NautilusOperationHandle *handle) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + PyGILState_STATE state = pyg_gil_state_ensure(); + PyObject *py_handle = nautilus_python_boxed_new (_PyNautilusOperationHandle_Type, handle, FALSE); + + debug_enter(); + + CHECK_OBJECT(object); + CHECK_METHOD_NAME(object->instance); + + PyObject_CallMethod(object->instance, + METHOD_PREFIX METHOD_NAME, "(NN)", + pygobject_new((GObject*)provider), + py_handle); + +beach: + pyg_gil_state_release(state); +} +#undef METHOD_NAME + +#define METHOD_NAME "update_file_info" +static NautilusOperationResult +nautilus_python_object_update_file_info (NautilusInfoProvider *provider, + NautilusFileInfo *file, + GClosure *update_complete, + NautilusOperationHandle **handle) { + NautilusPythonObject *object = (NautilusPythonObject*)provider; + NautilusOperationResult ret = NAUTILUS_OPERATION_COMPLETE; + PyObject *py_ret = NULL; + PyGILState_STATE state = pyg_gil_state_ensure(); + PyObject *py_handle = nautilus_python_boxed_new (_PyNautilusOperationHandle_Type, *handle, FALSE); + + debug_enter(); + + CHECK_OBJECT(object); + + if (PyObject_HasAttrString(object->instance, "update_file_info_full")) { + py_ret = PyObject_CallMethod(object->instance, + METHOD_PREFIX "update_file_info_full", "(NNNN)", + pygobject_new((GObject*)provider), + py_handle, + pyg_boxed_new(G_TYPE_CLOSURE, update_complete, TRUE, TRUE), + pygobject_new((GObject*)file)); + } + else if (PyObject_HasAttrString(object->instance, "update_file_info")) { + py_ret = PyObject_CallMethod(object->instance, + METHOD_PREFIX METHOD_NAME, "(N)", + pygobject_new((GObject*)file)); + } + else { + goto beach; + } + + HANDLE_RETVAL(py_ret); + + if (!PyLong_Check(py_ret)) { + PyErr_SetString(PyExc_TypeError, + METHOD_NAME " must return None or a int"); + goto beach; + } + + ret = PyLong_AsLong(py_ret); + +beach: + free_pygobject_data(file, NULL); + Py_XDECREF(py_ret); + pyg_gil_state_release(state); + return ret; +} +#undef METHOD_NAME + +static void +nautilus_python_object_info_provider_interface_init (NautilusInfoProviderInterface *interface) { + interface->cancel_update = nautilus_python_object_cancel_update; + interface->update_file_info = nautilus_python_object_update_file_info; +} + +static void +nautilus_python_object_instance_init (NautilusPythonObject *object) { + NautilusPythonObjectClass *class; + debug_enter(); + + class = (NautilusPythonObjectClass*)(((GTypeInstance*)object)->g_class); + + object->instance = PyObject_CallObject(class->type, NULL); + if (object->instance == NULL) + PyErr_Print(); +} + +static void +nautilus_python_object_finalize (GObject *object) { + debug_enter(); + + if (((NautilusPythonObject *)object)->instance != NULL) + Py_DECREF(((NautilusPythonObject *)object)->instance); +} + +static void +nautilus_python_object_class_init (NautilusPythonObjectClass *class, + gpointer class_data) { + debug_enter(); + + parent_class = g_type_class_peek_parent (class); + + class->type = (PyObject*)class_data; + + G_OBJECT_CLASS (class)->finalize = nautilus_python_object_finalize; +} + +GType +nautilus_python_object_get_type (GTypeModule *module, + PyObject *type) { + PyObject *name_str = NULL; + g_autofree GTypeInfo *info = NULL; + g_autofree gchar *type_name = NULL; + GType gtype; + + static const GInterfaceInfo properties_model_provider_interface_info = { + (GInterfaceInitFunc) nautilus_python_object_properties_model_provider_interface_init, + NULL, + NULL + }; + + static const GInterfaceInfo menu_provider_interface_info = { + (GInterfaceInitFunc) nautilus_python_object_menu_provider_interface_init, + NULL, + NULL + }; + + static const GInterfaceInfo column_provider_interface_info = { + (GInterfaceInitFunc) nautilus_python_object_column_provider_interface_init, + NULL, + NULL + }; + + static const GInterfaceInfo info_provider_interface_info = { + (GInterfaceInitFunc) nautilus_python_object_info_provider_interface_init, + NULL, + NULL + }; + + name_str = PyObject_GetAttrString(type, "__name__"); + debug_enter_args("type=%s", PyUnicode_AsUTF8(name_str)); + info = g_new0 (GTypeInfo, 1); + + info->class_size = sizeof (NautilusPythonObjectClass); + info->class_init = (GClassInitFunc)nautilus_python_object_class_init; + info->instance_size = sizeof (NautilusPythonObject); + info->instance_init = (GInstanceInitFunc)nautilus_python_object_instance_init; + + info->class_data = type; + Py_INCREF(type); + + type_name = g_strdup_printf("%s+NautilusPython", PyUnicode_AsUTF8(name_str)); + + Py_XDECREF(name_str); + + gtype = g_type_module_register_type (module, + G_TYPE_OBJECT, + type_name, + info, 0); + + if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusPropertiesModelProvider_Type)) { + g_type_module_add_interface (module, gtype, + NAUTILUS_TYPE_PROPERTIES_MODEL_PROVIDER, + &properties_model_provider_interface_info); + } + + if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusMenuProvider_Type)) { + g_type_module_add_interface (module, gtype, + NAUTILUS_TYPE_MENU_PROVIDER, + &menu_provider_interface_info); + } + + if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusColumnProvider_Type)) { + g_type_module_add_interface (module, gtype, + NAUTILUS_TYPE_COLUMN_PROVIDER, + &column_provider_interface_info); + } + + if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusInfoProvider_Type)) { + g_type_module_add_interface (module, gtype, + NAUTILUS_TYPE_INFO_PROVIDER, + &info_provider_interface_info); + } + + return gtype; +} diff --git a/src/nautilus-python-object.h b/src/nautilus-python-object.h new file mode 100644 index 0000000..d226b1f --- /dev/null +++ b/src/nautilus-python-object.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * Copyright (C) 2004,2005 Johan Dahlin + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NAUTILUS_PYTHON_OBJECT_H +#define NAUTILUS_PYTHON_OBJECT_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct _NautilusPythonObject NautilusPythonObject; +typedef struct _NautilusPythonObjectClass NautilusPythonObjectClass; + +struct _NautilusPythonObject { + GObject parent_slot; + PyObject *instance; +}; + +struct _NautilusPythonObjectClass { + GObjectClass parent_slot; + PyObject *type; +}; + +GType nautilus_python_object_get_type (GTypeModule *module, PyObject *type); + +G_END_DECLS + +#endif diff --git a/src/nautilus-python.c b/src/nautilus-python.c new file mode 100644 index 0000000..d48d71c --- /dev/null +++ b/src/nautilus-python.c @@ -0,0 +1,295 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * Copyright (C) 2004,2005 Johan Dahlin + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#define NO_IMPORT_PYGOBJECT //To avoid a multiple definition, nautilus-python-object.c also includes and does the import. +#include +#include + +#include "nautilus-python.h" +#include "nautilus-python-object.h" + +#include + +static const GDebugKey nautilus_python_debug_keys[] = { + {"misc", NAUTILUS_PYTHON_DEBUG_MISC}, +}; +NautilusPythonDebug nautilus_python_debug; + +static gboolean nautilus_python_init_python(void); + +static GArray *all_types = NULL; + + +PyTypeObject *_PyNautilusColumn_Type; +PyTypeObject *_PyNautilusColumnProvider_Type; +PyTypeObject *_PyNautilusInfoProvider_Type; +PyTypeObject *_PyNautilusMenu_Type; +PyTypeObject *_PyNautilusMenuItem_Type; +PyTypeObject *_PyNautilusMenuProvider_Type; +PyTypeObject *_PyNautilusPropertiesItem_Type; +PyTypeObject *_PyNautilusPropertiesModel_Type; +PyTypeObject *_PyNautilusPropertiesModelProvider_Type; +PyTypeObject *_PyNautilusOperationHandle_Type; + +static inline gboolean +np_init_pygobject(void) { + PyObject *gobject = pygobject_init (PYGOBJECT_MAJOR_VERSION, PYGOBJECT_MINOR_VERSION, PYGOBJECT_MICRO_VERSION); + + if (gobject == NULL) { + PyErr_Print (); + return FALSE; + } + + return TRUE; +} + +static void +nautilus_python_load_file(GTypeModule *type_module, + const gchar *filename) { + PyObject *main_module, *main_locals, *locals, *key, *value; + PyObject *module; + GType gtype; + Py_ssize_t pos = 0; + + debug_enter_args("filename=%s", filename); + + main_module = PyImport_AddModule("__main__"); + if (main_module == NULL) { + g_warning("Could not get __main__."); + return; + } + + main_locals = PyModule_GetDict(main_module); + module = PyImport_ImportModuleEx((char *) filename, main_locals, main_locals, NULL); + if (!module) { + PyErr_Print(); + return; + } + + locals = PyModule_GetDict(module); + + while (PyDict_Next(locals, &pos, &key, &value)) { + if (!PyType_Check(value)) + continue; + + if (PyObject_IsSubclass(value, (PyObject*)&PyNautilusColumnProvider_Type) || + PyObject_IsSubclass(value, (PyObject*)&PyNautilusInfoProvider_Type) || + PyObject_IsSubclass(value, (PyObject*)&PyNautilusMenuProvider_Type) || + PyObject_IsSubclass(value, (PyObject*)&PyNautilusPropertiesModelProvider_Type)) { + gtype = nautilus_python_object_get_type(type_module, value); + g_array_append_val(all_types, gtype); + } + } + + debug("Loaded python modules"); +} + +static void +nautilus_python_load_dir (GTypeModule *module, + const char *dirname) { + GDir *dir; + const char *name; + gboolean initialized = FALSE; + + debug_enter_args("dirname=%s", dirname); + + dir = g_dir_open(dirname, 0, NULL); + if (!dir) + return; + + while ((name = g_dir_read_name(dir))) { + if (g_str_has_suffix(name, ".py")) { + size_t len = strlen (name) - 3; + g_autofree char *modulename = g_strndup (name, len); + + if (!initialized) { + PyObject *sys_path, *py_path; + + /* n-p python part is initialized on demand (or not + * at all if no extensions are found) */ + if (!nautilus_python_init_python()) { + g_warning("nautilus_python_init_python failed"); + break; + } + + /* sys.path.insert(0, dirname) */ + sys_path = PySys_GetObject("path"); + py_path = PyUnicode_FromString(dirname); + PyList_Insert(sys_path, 0, py_path); + Py_DECREF(py_path); + } + + nautilus_python_load_file(module, modulename); + } + } + + g_dir_close (dir); +} + +static gboolean +nautilus_python_init_python (void) { + PyObject *nautilus; + GModule *libpython; + + if (Py_IsInitialized()) + return TRUE; + + debug("g_module_open " PYTHON_LIBPATH); + libpython = g_module_open (PYTHON_LIBPATH, 0); + if (!libpython) + g_warning("g_module_open libpython failed: %s", g_module_error()); + + debug("Py_Initialize"); + Py_Initialize(); + if (PyErr_Occurred()) { + PyErr_Print(); + return FALSE; + } + + debug("Sanitize the python search path and set sys.argv"); + PyRun_SimpleString("import sys; " + "sys.path = [path for path in sys.path if path]; " + "sys.argv = ['nautilus']"); + if (PyErr_Occurred()) { + PyErr_Print(); + return FALSE; + } + + /* import gobject */ + debug("init_pygobject"); + if (!np_init_pygobject()) { + g_warning("pygobject initialization failed"); + return FALSE; + } + + /* import nautilus */ + g_setenv("INSIDE_NAUTILUS_PYTHON", "", FALSE); + debug("import nautilus"); +#ifdef NAUTILUS_4_1_API + PyRun_SimpleString("import gi; gi.require_version('Nautilus', '4.1')"); +#else + PyRun_SimpleString("import gi; gi.require_version('Nautilus', '4.0')"); +#endif + nautilus = PyImport_ImportModule("gi.repository.Nautilus"); + if (!nautilus) { + PyErr_Print(); + return FALSE; + } + +#define IMPORT(x, y) \ + _PyNautilus##x##_Type = (PyTypeObject *)PyObject_GetAttrString(nautilus, y); \ + if (_PyNautilus##x##_Type == NULL) { \ + PyErr_Print(); \ + return FALSE; \ + } + + IMPORT(Column, "Column"); + IMPORT(ColumnProvider, "ColumnProvider"); + IMPORT(InfoProvider, "InfoProvider"); + IMPORT(Menu, "Menu"); + IMPORT(MenuItem, "MenuItem"); + IMPORT(MenuProvider, "MenuProvider"); + IMPORT(PropertiesItem, "PropertiesItem"); + IMPORT(PropertiesModel, "PropertiesModel"); + IMPORT(PropertiesModelProvider, "PropertiesModelProvider"); + IMPORT(OperationHandle, "OperationHandle"); + +#undef IMPORT + + return TRUE; +} + + +static void +nautilus_python_check_all_directories(GTypeModule *module) { + GList *dirs = NULL; + + // Check ~/.local/share first + dirs = g_list_append(dirs, g_build_filename(g_get_user_data_dir(), + "nautilus-python", "extensions", NULL)); + + // If nautilus is built in a non-standard prefix + // Check nautilus prefix's DATADIR + gchar *prefix_extension_dir = DATADIR "/nautilus-python/extensions"; + dirs = g_list_append(dirs, g_strdup (prefix_extension_dir)); + + // Check all system data dirs + const gchar *const *temp = g_get_system_data_dirs(); + while (*temp != NULL) { + gchar *dir = g_build_filename(*temp, + "nautilus-python", "extensions", NULL); + if (g_strcmp0(dir, prefix_extension_dir) != 0) { + dirs = g_list_append(dirs, dir); + } else { + g_free (dir); + } + + temp++; + } + + dirs = g_list_first(dirs); + while (dirs != NULL) { + gchar *dir = dirs->data; + nautilus_python_load_dir(module, dir); + dirs = dirs->next; + } + + g_list_free_full (dirs, g_free); +} + +void +nautilus_module_initialize(GTypeModule *module) { + const gchar *env_string; + + env_string = g_getenv("NAUTILUS_PYTHON_DEBUG"); + if (env_string != NULL) { + nautilus_python_debug = g_parse_debug_string(env_string, + nautilus_python_debug_keys, + G_N_ELEMENTS (nautilus_python_debug_keys)); + env_string = NULL; + } + + debug_enter(); + + all_types = g_array_new(FALSE, FALSE, sizeof(GType)); + + nautilus_python_check_all_directories(module); +} + +void +nautilus_module_shutdown(void) { + debug_enter(); + + if (Py_IsInitialized()) + Py_Finalize(); + + g_array_free(all_types, TRUE); +} + +void +nautilus_module_list_types(const GType **types, + int *num_types) { + debug_enter(); + + *types = (GType*)all_types->data; + *num_types = all_types->len; +} diff --git a/src/nautilus-python.h b/src/nautilus-python.h new file mode 100644 index 0000000..8261878 --- /dev/null +++ b/src/nautilus-python.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * Copyright (C) 2004,2005 Johan Dahlin + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NAUTILUS_PYTHON_H +#define NAUTILUS_PYTHON_H + +#include +#include +#include + +typedef enum { + NAUTILUS_PYTHON_DEBUG_MISC = 1 << 0, +} NautilusPythonDebug; + +extern NautilusPythonDebug nautilus_python_debug; + +#define debug(x) { if (nautilus_python_debug & NAUTILUS_PYTHON_DEBUG_MISC) \ + g_printf( "nautilus-python:" x "\n"); } +#define debug_enter() { if (nautilus_python_debug & NAUTILUS_PYTHON_DEBUG_MISC) \ + g_printf("%s: entered\n", __FUNCTION__); } +#define debug_enter_args(x, y) { if (nautilus_python_debug & NAUTILUS_PYTHON_DEBUG_MISC) \ + g_printf("%s: entered " x "\n", __FUNCTION__, y); } + +extern PyTypeObject *_PyNautilusColumn_Type; +#define PyNautilusColumn_Type (*_PyNautilusColumn_Type) + +extern PyTypeObject *_PyNautilusColumnProvider_Type; +#define PyNautilusColumnProvider_Type (*_PyNautilusColumnProvider_Type) + +extern PyTypeObject *_PyNautilusInfoProvider_Type; +#define PyNautilusInfoProvider_Type (*_PyNautilusInfoProvider_Type) + +extern PyTypeObject *_PyNautilusMenu_Type; +#define PyNautilusMenu_Type (*_PyNautilusMenu_Type) + +extern PyTypeObject *_PyNautilusMenuItem_Type; +#define PyNautilusMenuItem_Type (*_PyNautilusMenuItem_Type) + +extern PyTypeObject *_PyNautilusMenuProvider_Type; +#define PyNautilusMenuProvider_Type (*_PyNautilusMenuProvider_Type) + +extern PyTypeObject *_PyNautilusPropertiesItem_Type; +#define PyNautilusPropertiesItem_Type (*_PyNautilusPropertiesItem_Type) + +extern PyTypeObject *_PyNautilusPropertiesModel_Type; +#define PyNautilusPropertiesModel_Type (*_PyNautilusPropertiesModel_Type) + +extern PyTypeObject *_PyNautilusPropertiesModelProvider_Type; +#define PyNautilusPropertiesModelProvider_Type (*_PyNautilusPropertiesModelProvider_Type) + +extern PyTypeObject *_PyNautilusOperationHandle_Type; +#define PyNautilusOperationHandle_Type (*_PyNautilusOperationHandle_Type) + +#endif /* NAUTILUS_PYTHON_H */