GNOME issueshttps://gitlab.gnome.org/groups/GNOME/-/issues2022-08-31T16:26:19Zhttps://gitlab.gnome.org/GNOME/gimp-help/-/issues/335Reduce the number of xref links2022-08-31T16:26:19ZJacob BoeremaReduce the number of xref linksThe usage of `xref` links in our DocBook XML documentation can be confusing for translators and also documentation writers that are not very familiar with all DocBook details.
For example:
```
"Rendering intents are ways of dealing wit...The usage of `xref` links in our DocBook XML documentation can be confusing for translators and also documentation writers that are not very familiar with all DocBook details.
For example:
```
"Rendering intents are ways of dealing with colors that are out-of-<xref "
"linkend=\"glossary-gamut\"/> colors present in the source space that the "
"destination space is incapable of producing. There are four rendering "
"intents defined by the ICC:"
```
Here, the `glossary-gamut` link will specify what text will be inserted for the clickable link. Translators may think there is missing text for the link and may even add extra text and a closing `</xref>`, which would be invalid.
In most cases, it is probably better to use `<link linkend=\"glossary-gamut\">gamut</link>`. This way, it will be clear for translators what the text for the link will be. It also makes it easier for them to rearrange the sentence structure when needed.
This information should also be added to our manual/instructions for documentation writers.3.0https://gitlab.gnome.org/GNOME/librsvg/-/issues/864Document a reliable way to do the "replace elements with invisible ones after...2023-08-18T18:57:57ZFederico Mena QuinteroDocument a reliable way to do the "replace elements with invisible ones after querying their position" hackSee [what libwacom does and gnome-shell uses](https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5415), and #823 for a cool use in an electronics design app.
Thinking out loud:
* For "square" elements, replace a rectangle.
* For text ...See [what libwacom does and gnome-shell uses](https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5415), and #823 for a cool use in an electronics design app.
Thinking out loud:
* For "square" elements, replace a rectangle.
* For text elements, replace their font with the Ahem font, and explain how the metrics work.
See how the spec assumes that the DOM method `getBounds()` on an element with `display:none` should yield its correct bounds, anyway. Add a test for that.https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5424Document building process2023-11-04T04:03:08ZMaksym HazevychDocument building processHi! There is no current documentation on how to build GNOME Shell. I would appreciate it if you added this information to README or HACKING because it's unclear.Hi! There is no current documentation on how to build GNOME Shell. I would appreciate it if you added this information to README or HACKING because it's unclear.https://gitlab.gnome.org/GNOME/glib/-/issues/2577Better document G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT2022-01-07T15:25:19ZShaun McCanceBetter document G_FILE_MONITOR_EVENT_CHANGES_DONE_HINTIt would be nice to have more thorough documentation on when `G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT` is fired, and if it reliably fires. Currently, my file monitor is just triggering on all events, but I feel like I ought to be able to ...It would be nice to have more thorough documentation on when `G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT` is fired, and if it reliably fires. Currently, my file monitor is just triggering on all events, but I feel like I ought to be able to cut down on churn with `CHANGES_DONE_HINT`. But I don't know how to best use it.
Testing on my local system suggests it fires after `CHANGED` and `CREATED`, but not after `DELETED`, 'ATTRIBUTE_CHANGED`, 'RENAMED', 'MOVED_IN', or 'MOVED_OUT`. (I didn't test unmounting or the deprecated `MOVED`.) I don't know how much of this is dependent on my local system. I don't know if the event type is reliable. It's weird that `CREATED` gets it but `DELETED` doesn't. (I guess because creating involves `open` and `close`?)https://gitlab.gnome.org/GNOME/dia/-/issues/515Doc HACKING.md - File contains outdated information2021-12-26T23:21:28ZJim GunnarssonDoc HACKING.md - File contains outdated information## Version
Commit 0997887d97f01be28bf3886dfd3e2002de437930
## Description
The `HACKING.md` is great. It provide a description of the code base and
references to tools used for analysis.
## Issue
The file contains outdated information....## Version
Commit 0997887d97f01be28bf3886dfd3e2002de437930
## Description
The `HACKING.md` is great. It provide a description of the code base and
references to tools used for analysis.
## Issue
The file contains outdated information.
For instance
~~~
`render_object.h` (for doing picture-like objects).
~~~
This file was removed in commit b9181a2b73a1627b498f6d555415d5a656792b50 way
back in 2002.
There might be more outdated info in this file but I do not have a list.
Reference to doxygen is missing.
## Effects
Minor but it would be nice if the file was up to date with the code base.
## Setup
None
## Test case
Nonehttps://gitlab.gnome.org/GNOME/libadwaita/-/issues/362Document how to recolor individual widgets2022-08-04T11:17:08ZAlice MikhaylenkoDocument how to recolor individual widgetsA lot of styles were made with recoloring in mind, but how to actually do that is an easter egg currently. We should document it.A lot of styles were made with recoloring in mind, but how to actually do that is an easter egg currently. We should document it.https://gitlab.gnome.org/GNOME/libsoup/-/issues/255Add example for soup_message_set_request_body() to docs2022-01-01T18:57:56ZElliott Sales de AndradeAdd example for soup_message_set_request_body() to docsThe result of `soup_message_send*` is an input stream. For the client side, this makes sense as I must read the response data from it.
However, `soup_message_set_request_body` also takes an input stream. I guess this is for ease of use ...The result of `soup_message_send*` is an input stream. For the client side, this makes sense as I must read the response data from it.
However, `soup_message_set_request_body` also takes an input stream. I guess this is for ease of use within libsoup, but from the client side, this seems backwards. I would expect to _write_ the request body to the server.
TBH, gio's streaming API can be confusing, so maybe this is okay in practice. In which case, this would be request for documentation, as there is an example of client-side download streaming, but not upload streaming.https://gitlab.gnome.org/GNOME/gitg/-/issues/338Isolate test suite from local environment2023-12-14T17:43:53ZGhost UserIsolate test suite from local environmentIf global config contains diff3 style
```
$ git config --global --get merge.conflictstyle
diff3
```
it will break the test suite (which expects default merge style format)
```
ok 7 /GitgTestMergeRef/merge-theirs-conflicts-no-checkout
...If global config contains diff3 style
```
$ git config --global --get merge.conflictstyle
diff3
```
it will break the test suite (which expects default merge style format)
```
ok 7 /GitgTestMergeRef/merge-theirs-conflicts-no-checkout
Bail out! gitg:ERROR:tests/gitg/tests-gitg.p/support-test.vala:59:gitg_test_assert_assert_file_contents: assertion failed ((contents) == (expected_contents)): ("<<<<<<< ours\nc file other content\n|||||||\n=======\nc file\n>>>>>>> theirs\n" == "<<<<<<< ours\nc file other content\n=======\nc file\n>>>>>>> theirs\n")
stderr:
(process:6): Gtk-CRITICAL **: 10:10:32.431: gtk_style_context_add_provider_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
**
gitg:ERROR:tests/gitg/tests-gitg.p/support-test.vala:59:gitg_test_assert_assert_file_contents: assertion failed ((contents) == (expected_contents)): ("<<<<<<< ours\nc file other content\n|||||||\n=======\nc file\n>>>>>>> theirs\n" == "<<<<<<< ours\nc file other content\n=======\nc file\n>>>>>>> theirs\n")
```
We need an initial setup that reads a global config file that overrides any other config
**NOTE**: Probably a local .config will work toohttps://gitlab.gnome.org/GNOME/gimp/-/issues/7252gegl_init() is a trap for the unwary in Python plug-ins non-interactive2024-03-22T17:39:38Zprogrammer_cedsgegl_init() is a trap for the unwary in Python plug-ins non-interactiveI have been updating some Python scripts from GIMP V2.10 to V2.99 and have used the Python scripts supplied in the V2.99.7 GIMP sources as examples. This applies to the Python scripts included in GIMP sources downloaded 15.9.2021 - commi...I have been updating some Python scripts from GIMP V2.10 to V2.99 and have used the Python scripts supplied in the V2.99.7 GIMP sources as examples. This applies to the Python scripts included in GIMP sources downloaded 15.9.2021 - commit 148fbb2244 and earlier versions.
Two of the scripts would work successfully when run interactively but failed with a segmentation fault in both of the non-interactive modes when the script called get_buffer() for a drawable (line 135). I found that the problem didn't occur if the script called GimpUi.init(). I then narrowed this down to needing a call of babl.init().
To save others having to investigate the same problem I suggest that the Python scripts (fogify.py and goat-exercise-py3.py for example) that ship with GIMP should be modified (I will do this and submit a merge request if requested).
The easiest modification would be to move the call of GimpUi.init() into the common path of the code that handles interactive and non-interactive modes.
The other approach would be to import babl (as per line 38 of the attached script) and then call Babl.init() (as per lines 200 and 201) if running in one of the non-interactive modes.
If the attached script is run interactively and then via "Filters/Repeat Last" it should work without a problem. If this is repeated with lines 200 and 201 commented out it will fail when run non-interactively.
[TransparencyCheck_GV3.py](/uploads/c6c44de0065b978fd391d0ee9a48d4db/TransparencyCheck_GV3.py)https://gitlab.gnome.org/GNOME/vala/-/issues/1197Add information about project structure in docs2021-06-27T12:27:56ZColin Kiamacolinkiama@gmail.comAdd information about project structure in docsWhile the folders are named appropriately, it would be great if there was table detailing the purpose of the code in each folder e.g “codegen - Handles generation of C Code, valadoc - Generates documentation” etc.
This way it’s much eas...While the folders are named appropriately, it would be great if there was table detailing the purpose of the code in each folder e.g “codegen - Handles generation of C Code, valadoc - Generates documentation” etc.
This way it’s much easier for newer contributors known exactly where to go to fix issues related to a certain part of the project.https://gitlab.gnome.org/GNOME/gimp/-/issues/6968plug-ins/pygimp/doc/pygimp.sgml unused for web's /docs/python/2022-01-27T03:30:53ZRalph Corderoyplug-ins/pygimp/doc/pygimp.sgml unused for web's /docs/python/Two versions of the documentation for Python plug-ins exists. What's published at https://www.gimp.org/docs/python/, which is where search engines take users, and the SGML source at https://gitlab.gnome.org/GNOME/gimp/-/blob/d9b102e1969a...Two versions of the documentation for Python plug-ins exists. What's published at https://www.gimp.org/docs/python/, which is where search engines take users, and the SGML source at https://gitlab.gnome.org/GNOME/gimp/-/blob/d9b102e1969a160187b10828bfbb45021bbe40b9/plug-ins/pygimp/doc/pygimp.sgml which appears to have extra content, e.g. the Script-Fu invocation of Python at line 2093 which comes after gimpshelf.
AIUI, discussion just now on #gimp, 2021-06-15 17:19 +0000, had schumaml and Jehan think something should be done so I volunteered to open an issue to raise its visibility.2.10https://gitlab.gnome.org/GNOME/gtk/-/issues/4039Add XML UI documentation2022-01-04T10:43:41ZliferooterAdd XML UI documentationThere is no good and centralized documentaion for GtkBuilder's XML UI. It makes creating XML UI's difficult.There is no good and centralized documentaion for GtkBuilder's XML UI. It makes creating XML UI's difficult.https://gitlab.gnome.org/GNOME/gnome-terminal/-/issues/364Code documentation is very bare minimum2023-06-21T07:32:16ZVarun GargCode documentation is very bare minimumDocumentation is too small, just describes how to build gnome-terminal. Some explanation around architecture and code structure will really help people contribute to the project. Documentation for Konsole is a good example.Documentation is too small, just describes how to build gnome-terminal. Some explanation around architecture and code structure will really help people contribute to the project. Documentation for Konsole is a good example.https://gitlab.gnome.org/GNOME/gtk/-/issues/4000GtkLabel got lots of changes in GTK4, but there is no Documentation on Migrat...2021-09-30T06:29:46ZMichael BuzgaruGtkLabel got lots of changes in GTK4, but there is no Documentation on Migrating from GTK 3.x to GTK 4Changes I am talking about are:
- gtk_label_set_pattern() /// Removed in GTK4
- gtk_label_set_angle () /// Removed in GTK4
- gtk_label_get_angle () /// Removed in GTK4
- gtk_label_set_track_visited_links /// Removed in GTK4
- gtk_label_...Changes I am talking about are:
- gtk_label_set_pattern() /// Removed in GTK4
- gtk_label_set_angle () /// Removed in GTK4
- gtk_label_get_angle () /// Removed in GTK4
- gtk_label_set_track_visited_links /// Removed in GTK4
- gtk_label_get_track_visited_links /// Removed in GTK4
and:
- gtk_label_set_line_wrap() =>> gtk_label_set_wrap()
- gtk_label_get_line_wrap() =>> gtk_label_get_wrap()
- gtk_label_set_line_wrap_mode() =>> gtk_label_set_wrap_mode()
- gtk_label_get_line_wrap_mode() =>> gtk_label_get_wrap_mode()https://gitlab.gnome.org/GNOME/gtk/-/issues/3932[Docs] class.StringFilter add example expression.2021-05-09T15:28:48ZTimo[Docs] class.StringFilter add example expression.In this section: https://docs.gtk.org/gtk4/class.StringFilter.html
It would be great to have an example how the expression would look like using the [stringList](https://docs.gtk.org/gtk4/class.StringList.html)
When you work with String...In this section: https://docs.gtk.org/gtk4/class.StringFilter.html
It would be great to have an example how the expression would look like using the [stringList](https://docs.gtk.org/gtk4/class.StringList.html)
When you work with StringList and SignalListItemFactory you will learn that in the binding function you get the string by:
ListItem->item->string
This made me think I need an expression doing the same.
But StringFilter already gets the item from the ListItem. So only the last stem is needed.
This was hard to debug because the error message just told me that my expression is wrong.
An example:
`setup for a filter for a model using the StringList` is setup as`https://gitlab.gnome.org/GNOME/gnome-weather/-/issues/171Add libhandy 1 requirement.2023-02-02T02:14:40ZEvan Welshcontact@evanwelsh.comAdd libhandy 1 requirement.We need to declare in `pkg.require` that we use libhandy 1. Luckily, GJS defaults to the highest version but we still log a warning on systems where libhandy 0 and 1 coexist.We need to declare in `pkg.require` that we use libhandy 1. Luckily, GJS defaults to the highest version but we still log a warning on systems where libhandy 0 and 1 coexist.https://gitlab.gnome.org/GNOME/vala/-/issues/1102Some thoughts about Vala runtime libraries?2020-11-06T19:10:43ZTAO ZUHONGSome thoughts about Vala runtime libraries?Which libraries should be listed in the runtime / standard library?
We should have a clear view to show newbies, and make them learn Vala more convenient.
Runtime / standard library
-------------------------------------
GLib 2.0 / libg...Which libraries should be listed in the runtime / standard library?
We should have a clear view to show newbies, and make them learn Vala more convenient.
Runtime / standard library
-------------------------------------
GLib 2.0 / libgee
Gui libraries
-------------------------------------
GTK3 / GTK4 / ...
Extend libraries
-------------------------------------
Soup / json-glib / libcurl / ...https://gitlab.gnome.org/GNOME/gedit-plugins/-/issues/38How to get plugins included / distributed with gedit2022-11-21T13:29:51ZPeter BittnerHow to get plugins included / distributed with geditWhat is the process of getting a plugin included in this repository? (Or even with GEdit itself?)
I maintain a [plugin to render reStructuredText](https://github.com/bittner/gedit-reST-plugin), and I'd like to give it more visibility, a...What is the process of getting a plugin included in this repository? (Or even with GEdit itself?)
I maintain a [plugin to render reStructuredText](https://github.com/bittner/gedit-reST-plugin), and I'd like to give it more visibility, align the project setup more with the existing, first-class plugins for easier maintenance, and finally give its users the chance to get it installed more easily.
**Note:** I'm not talking about outsourcing the maintenance. It's more about trying to understand the governance of GEdit and its plugins. And about making maintenance and distribution more sustainable, if possible. To help the GNOME project flourish, really. There are too many people that take it for granted that all this software is being maintained "by someone".https://gitlab.gnome.org/GNOME/gjs/-/issues/361Profiling gjs performance with perf and hotspot2024-03-11T05:42:41ZJonas DreßlerProfiling gjs performance with perf and hotspotSo it's a known fact that gjs is not very optimized for performance, let's change that! Here's an introduction about how to use perf and hotspot to get fancy flamegraphs and how to analyze them.
## How to profile
1) Install `perf` and ...So it's a known fact that gjs is not very optimized for performance, let's change that! Here's an introduction about how to use perf and hotspot to get fancy flamegraphs and how to analyze them.
## How to profile
1) Install `perf` and `hotspot`, luckily both in Fedoras repos
2) Now allow everyone to access perf events: `sudo sysctl kernel.perf_event_paranoid=-1`
3) That's pretty much it, now you can gather data using perf: `perf record --call-graph dwarf,65528 gjs expensivestuff.js`
Those options tell perf to record a callgraph using the dwarf method to unwind stacks and with an increased call-stack depth (this is the maximum depth, note that this will create *very* large files, 10 seconds and you're at 1gb, so keep profiling sessions short, the higher you choose this number, the less frames with an unknown entry function will appear).
You can also profile your active gnome-shell process by passing perf a pid: `perf record --call-graph dwarf,65528 -p PID`
4) Look at your results using `hotspot perf.data` and select the "Flame Graph" view to get a fancy graph
## Things to profile and how to analyze results
### Function call on a boxed-type object
For a careful analysis of the bottlenecks gjs currently has it's best to profile simple applications, let's start with the performance of calling a function on a boxed-type object:
```javascript
const Graphene = imports.gi.Graphene;
function test() {
const box = new Graphene.Box();
for (let i = 0; i < 1000000; i++)
box.get_width();
}
test();
```
The flamegraph for it should look something like this:
![image](/uploads/b15b99bd379d4216643a7b9e8138c8ef/image.png)
What you can see here are a few interesting things:
- We spend most of the time executing the JS (the whole "??" block)
- We're using the Ion JIT compiler (`js::jit::IonGetProperty` is called, the baseline compiler would be `js::jit::DoGetPropFallback`)
- Most of the time spent in JS is spent in the JS->C machinery, `gjs_invoke_c_function`, which is apparently very slow because it calls `g_registered_type_info_get_g_type()` twice. Looking at the code, this can easily be fixed by adding the GType to the argument cache.
### Getting a boxed-type property from a GObject
Now let's look at something else and get a boxed-type property from a GObject:
```javascript
const Clutter = imports.gi.Clutter;
function test() {
const actor = new Clutter.Actor();
for (let i = 0; i < 1000000; i++)
actor.allocation;
}
test();
```
This time we get a flamegraph like this:
![image](/uploads/a5d186d79c9651f5ac7760693229c515/image.png)
Some quick observations:
- We're using the Ion JIT compiler again, nice!
- A bit of time is spent with GC, freeing the boxed-type allocation property we retrieved
- Most of the time is spent getting the property, although not as one might expect inside `g_object_get_property()`, but in `gjs_value_from_g_value_internal()` building a new JSObject for the C-struct. What immediately comes to mind here would be introducing a C-struct -> JSObject cache.
### gnome-shell overview animation layout process
So we now know how getting properties and calling C functions looks in the flamegraph, time to start looking at some real-world data, let's have a look at the layout process of gnome-shell while opening the overview.
You might ask yourself now "how do you know the layout process when opening the overview is something interesting to look at?", so it's time for a quick shout-out to sysprof: With sysprof marks, you can easily spot that the "Layout" mark uses about 6ms of 8ms it takes us to come up the frame ("Frame Clock (frame)" mark) during the overview animation with a lot of open windows. So obviously that's something to look into if we want to consistently stay inside the time-budget we have for a single frame.
Now open a lot of windows, run `perf` attaching it to the gnome-shell process, and open and close the overview a bunch of times.
This is what the flamegraph will look like:
![image](/uploads/d0ba1777c785ec076f656b1c9da2bc5b/image.png)
What we care about here is `handle_frame_clock_frame()` which is called on every new frame (surprise!), and especially `clutter_stage_maybe_relayout()` which is the entry point of the layout process. As you can see, recursion is pretty deep in the layout phase and there's a large chunk of JS we can't figure out an entry point for. That doesn't mean we have to ignore this chunk though: By looking at the C functions it calls into, most notably `clutter_actor_allocate()` and `clutter_actor_get_preferred_*` (the search feature of hotspot comes in handy here as it might be hard to spot those functions), we find out that most of it are traces from the layout phase, so the size of the `clutter_stage_maybe_relayout` block here is probably misleading (which makes sense given that Sysprof reported of 6 out of 8 ms).
Now let's zoom in a little on the layout phase and look at the large block that includes `clutter_stage_maybe_relayout()` -> `st_widget_allocate()` -> JS -> `clutter_actor_allocate_available_size()`. With a little knowledge of the gnome-shell codebase we can figure out that this path must be allocating the `Workspace` actor which is the actor responsible for laying out all the windows in the overview, here's the upper part of that flamegraph:
![image](/uploads/e7e6601882ca9d93dd6521c775320450/image.png)
What we see is that we enter a JS allocation function (it's the allocation function of the `WorkspaceLayout` layout manager) and a lot of the time in there is spent getting properties (including another roundtrip through JS land and it appears to be a boxed-type GObject property, which means we're probably looking at `WindowPreview.boundingBox`).
Now what can we learn here? Well, the most important lesson is that getting properties from GObjects seems to be very expensive and a major bottleneck, in gnome-shell we might want to avoid accessing properties multiple time and instead assign our own "pointer" or copy of the property and use that instead. Also generally (and as expected), recursive processes like Clutters allocation machinery round tripping between C and JS land are a bad idea and should probably avoid JS land altogether (also for the sake of stack-trace readability :P).
## More cool stuff you can do with perf and hotspot
Another neat feature I think is worth knowing is that hotspot allows filtering the flamegraph for looking at a specific timespan or thread using the "Time Line" in the bottom part of the window.
That was a quick introduction into the most important things, there are a lot more cool things you can do with perf and hotspot, for example Off-CPU-Profiling to analyze synchronous IO or `sleep()` calls, look at [the hotspot repo](https://github.com/KDAB/hotspot#using) for how to do that. Maybe I'll do another writeup on that in the future, but I'll probably have to learn more about computers before I do that :)
[Here's a very interesting talk](https://www.youtube.com/watch?v=HOR4LiS4uMI) about using heaptrack (another great profiling tool from the KDE community) and hotspot by David Faure.
## What now?
Now go and have fun playing around with this and making GNOME faster :)
Before you start creating patches for gjs, I've already fixed the `g_registered_type_info_get_g_type()` occurrences when calling `gjs_invoke_c_function()` and the sometimes unnecessary calls into `gjs_get_string_id()` in `GIWrapperBase::resolve()`.
That was a lot more than I was planning to write, maybe I'll just reuse it for a blog post after all...https://gitlab.gnome.org/GNOME/gimp/-/issues/5768gimp_image_crop(): has no option for non-destructive cropping2024-03-21T18:59:58ZDorygimp_image_crop(): has no option for non-destructive croppingGIMP version: 2.10.22
Note: bug reporters are expected to have verified the bug still exists
either in the last stable version of GIMP or on updated development code
(master branch).
Operating System: Windows 10 and Arch Linux (kernel ...GIMP version: 2.10.22
Note: bug reporters are expected to have verified the bug still exists
either in the last stable version of GIMP or on updated development code
(master branch).
Operating System: Windows 10 and Arch Linux (kernel 5.8.10)
Package: Installer from gimp.org for Windows; Archlinux official package for Arch.
# Description of the bug
GIMP since 2.10.20 supported crop tool with "Delete Cropped Pixels" options, which, if unchecked, will only crop the image and not the layers, allowing "un-cropping" later if needed, even after saving the xcf, closing gimp, and reopening the xcf.
There currently seems to be no way to replicate this behavior using script-fu. AFAIK, the only procedure in script-fu, `gimp-image-crop`, always crop both the image and all the layers.
# Reproduction
Is the bug reproducible? Always
Reproduction steps:
1. Run `gimp -i -n -b -`
2. Paste in
```
(let* ((input-file "anyimagefilehere")
(output-file "out.xcf")
(image (car (gimp-file-load RUN-NONINTERACTIVE input-file input-file)))
(main-layer (car (gimp-image-get-active-layer image))))
(gimp-image-crop image
(/ (car (gimp-image-height image)) 2)
(/ (car (gimp-image-width image)) 2)
0 0)
(gimp-xcf-save 0 image main-layer output-file output-file)
(gimp-image-delete image))
```
3. Reopen `out.xcf` in another instance of GIMP
4. Observe that the main layer is now cropped to the top left quadrant of the image.
…
Expected result: There should be an option in `gimp-image-crop` to toggle cropping of the layers along with the image, or an alternative procedure to crop image without also cropping the layers.
Actual result: There is no way in script-fu to do non-destructive cropping.