... which should be used to properly remove a
GimpTileHandlerValidate from a buffer, instead of using
gegl_buffer_remove_handler() directly.
Use gimp_tile_handler_validate_unassign(), instead of
gegl_buffer_remove_handler(), in gimp_projection_free_buffer().
(cherry picked from commit 12530e21b2)
In GimpTileHandlerValidate, when allocating a new tile upon a
TILE_GET command, but not rendering the whole tile, clear the tile
data before rendering, so that the unrendered regions of the tile
contain zeros, rather than junk.
(cherry picked from commit e1e4ba9c8b)
This is my attempt to get better labels, shorter and also (hopefully)
improved English.
As Mitch states though, this is a Japanese-French-German conspiracy! So
any of you native English speakers out there, please review and suggest
proper English if needed. :-)
(cherry picked from commit 9cdedc98f8)
Adding spaces between function names and parenthese.
I would normally have just amended the contributed patches and pushed,
but gitlab is making our review process over-complicated with many
roundtrips with contributors, and review quality drops. Stating it here
for the records!
See commit 70945b8960 (where this cleaning
should have directly been done).
(cherry picked from commit 5c56f8cb3a)
anchor of LTR is top-left corner.
anchor of TTB-RTL is top-right cornner.
anchor of TTB-LTR is top-left cornner.
(cherry picked from commit 70945b8960)
This fish is used for text layers, so if we let it to be
lazy-initialized, the first time one writes text in a text layer, it
generates a few seconds delay, which is really not great.
(cherry picked from commit a03e52ea08)
In gimp_layer_convert(), avoid converting the drawable type when
the source and destination color profiles are equal, if otherwise
unnecessary. Otherwise, text layers get unnecessarily re-rendered
during conversion, and, by extension, during image duplication
(which happens when exporting to any format that requires merging
down the image). This may cause the text layer to appear
differently in the duplicated image, or even use a different font
if the original font doesn't exist.
(cherry picked from commit a826a19359)
When duplicating an image, copy the source image's is-color-managed
status to the duplicated image, instead of having the duplicated
image always be color managed. In particular, do this before
duplicating the layers, so that we don't convert the duplicated
layers from sRGB to the image's profile when duplicating an image
with a non-sRGB profile but with color management turned off.
(cherry picked from commit f38443f3b0)
Squashed commit of the following:
commit ee1ff7d502658cfa1248a13a3f0348495db07eda
Author: ONO Yoshio <ohtsuka.yoshio@gmail.com>
Date: Sun Jul 29 00:31:47 2018 +0900
Fixed that gimp-text-dir-ttb-* icons are lacked in Symbolic.
commit d87d012d697628da28fe90199cc04b95b72ba8ef
Author: ONO Yoshio <ohtsuka.yoshio@gmail.com>
Date: Sat Jul 28 16:23:10 2018 +0900
Fix a typo.
commit cf0238bf7df56c384cdf3b7ec69557d14740f853
Author: ONO Yoshio <ohtsuka.yoshio@gmail.com>
Date: Sat Jul 28 15:50:57 2018 +0900
Fixed seg fault error.
commit b07f60d06fa1a753fda5b4d46af01698c344154e
Author: ONO Yoshio <ohtsuka.yoshio@gmail.com>
Date: Fri Jul 27 17:15:34 2018 +0900
Add support for vertical text writing.
https://gitlab.gnome.org/GNOME/gimp/issues/641
(cherry picked from commit 587d9bbb03)
Just like it was until now, the default filtering should not be all
files, but only relevant files (i.e. XCF when saving, exportable images
when exporting and loadable images/XCF when opening).
Now all files will only be available through the "Show All Files"
checkbox.
This is simpler than previous implementations where the list was
proposing "All Files", "All Images" and "All XCF/export images". That is
just too much.
With this default, I get the "All Files" checkbox out of the expander so
that it is visible immediately even when the format list is unexpanded
(you don't want people to get pissed when not finding how to display all
their files).
(cherry picked from commit 6b4b3bad13)
... format selection.
Second step: add a "Show All Files" checkbox so that one can still
prevent view filtering even when forcing a load format.
This is useful when loading files with unusual extensions, for instance.
(cherry picked from commit 6369445874)
... format selection.
As discussed, the first step is to get rid of the filter list. Our extra
widget now has both roles of filtering the file list and forcing a
loading procedure.
(cherry picked from commit 9ae7827f9b)
In subdirs containing a generated foomarshal.h header, add the
generated sources to BUILT_SOURCES, so that they're generated
before the rest of the source files are built. Otherwise, since
there is no rule specifying the dependency between the rest of the
source files and foomarshal.h, and since foomarshal.h is not
checked into git (and hence doesn't exist when doing a clean
build), compilation of the said source files may fail if they're
built before foomarshal.h is generated.
(cherry picked from commit a5102a7dba)
In GimpFilterTool, bind the controller's lifetime to the lifetime
of the config object, rather than to the lifetime of the
corresponding tool widget; make the controller's widget pointer a
weak pointer to the widget, and bail out of the controller "set()"
functions when the widget pointer is NULL.
This fixes an issue arising when the properties of a config object
that outlives the widget change after the widget had died,
triggering a call to the controller's set() function, resulting in
a segafult when trying to access the widget.
(cherry picked from commit 78abe756f1)
When constructing a prop-GUI widget for an angle property with a
dial, use the the property's "direction" UI-meta, if exists, to set
the direction of the dial. Together with GEGL commit
7b0578073a0f20334b5a8a8fe57b649d9f302454, this fixes wrong dial
direction in certain ops that use clockwise angles.
(cherry picked from commit 6976e87dac)
... and rename "clockwise" to "clockwise-delta"
Add a boolean "clockwise-angles" property to GimpDial, which, when
set, causes the dial legs' angles to be measured clockwise, rather
than counter-clockwise. The property is FALSE by default.
Rename the "clockwise" property, which controls the direction of
the measured delta between the two angles, to "clockwise-delta", to
avoid confusion, and adapt the rest of the code.
(cherry picked from commit 0c477564ad)
... from layer context menu
In gimp_text_tool_set_layer(), do nothing if the input layer is the
currently-edited layer, otherwise we get a CRITICAL.
(cherry picked from commit 6b1d77b11c)
In the dynamics editor, use the neutral curve color, which depends
on the current theme, for the "fade" curve, instead of hard-coding
it to dark gray, which is hardly visible with dark themes.
(cherry picked from commit b2a9bb4688)
Add a gimp-register-file-handler-priority procedure, which can be
used to set the priority of a file-handler procedure. When more
than one file-handler procedure matches a file, the procedure with
the lowest priority is used; if more than one procedure has the
lowest priority, it is unspecified which one of them is used. The
default priority of file-handler procedures is 0.
Add the necessary plumbing (plus some fixes) to the plug-in manager
to handle file-handler priorities. In particular, use two
different lists for each type of file-handler procedures: one meant
for searching, and is sorted according to priority, and one meant
for display, and is sorted alphabetically.
(cherry picked from commit b4ac956859)
In GimpToolCompass (and, as a consequence, in the measure tool),
update the measured angle when the shell is scaled, rotated, or
flipped, so that we always satisfy the compass's constrains, and
render correctly.
(cherry picked from commit a810c6b60b)
When using a GimpToolCompass in 3-point mode, add a small gap after
the angle arc to the line corresponding to the "second" non-origin
point, so that it's visually distinguishable from the line
corresponding to the "first" point. This has significance for the
measure tool, since it determines the direction of the rotation
when straightening the image (the first point is rotated toward the
second point.)
(cherry picked from commit 0f03f9e9f5)
... does not restore the measure points
Halt the measure tool after straightening, thus removing the
expectation that undoing the operation should restore the original
points.
Halting the tool, rather than making undo work "as expected",
sidesteps several issues:
- Implementing undo correctly is tricky, since image-undo and
tool-undo are handled separately.
- In fact, the measure tool doesn't provide tool-undo, so that
image edits can be undone while the tool is active without
affecting the tool, and it's not clear that we want to change
this behavior. However, this makes undoing a straighten
operation a special case, and it's not entirely clear what the
behavior should be when undoing other kinds of transformations,
or when the measure points had changed since the straighten
operation.
- Perhaps most importantly, measure tool points are restricted to
the pixel grid, which means that when measuring an angle
against an orientation that's not fully horizontal or vertical
in image space (either using a 3-point angle, or when the
canvas is rotated), the resulting transformed point after
straightening doesn't generally land on the pixel grid, causing
it to be rounded, which can result in a non-zero angle after
the rotation. This is especially ugly, since clicking
"straighten" again at this point would cause another non-
trivial rotation.
(cherry picked from commit 2e08c9164a)
Rename XCF property PROP_SAMPLE_POINT to PROP_OLD_SAMPLE_POINT and add
new PROP_SAMPLE_POINT.
The new property saves the sample point's pick mode plus some padding
for whatever else we might want to add. Always save the old property
too so nothing changes for older GIMP versions, and avoid loading the
old property if the new one was loaded before.
(cherry picked from commit 47a008be97)
Bind the "orientation" property of the measure-tool options to the
tool's compass widget's "orientation" property, instead of manually
synchronizing their values.
(cherry picked from commit 7a91aabf37)
Add an "orientation" option to the measure tool, corresponding to
the "orientation" property of GimpToolCompass (i.e., it controls
the orientation against which the angle is measured, when not in 3-
point mode.) The orientation is "auto" by default, so that the
angle is always <= 45 deg. Note that the "orientation" option
affects the tool's "straighten" function, so that the layer is
rotated toward the current orientation.
Use the "pixel-angle" and "unit-angle" properies of
GimpToolCompass to read the measured angle, instead of duplicating
the angle-measurement logic, in particular, so that we benefit from
the improvements/fixes of the previous commit.
(cherry picked from commit cb3b7a1ba5)
Add an "orientation" property to GimpToolCompass, which can be one
of "auto", "horizontal", or "vertical", and which controls the
orientation of the line against which the angle is measured, when
not in 3-point mode (previously, the line would always be
horizontal.) When "orientation" is "auto", the orientation is
automatically set to either horizontal or vertical, such that the
measured angle is <= 45 deg.
Keep the line horizontal, or vertical, in display-space, rather
than in image-space, so that the compass works correctly even when
the canvas is rotated and/or flipped.
Fix the compass's behavior when the image's horizontal and vertical
resolutions are different, both with and without dot-for-dot.
Add "pixel-angle" and "unit-angle" read-only properties, which
return the measured angle either with or without taking the image's
resolution into account, respectively. These properties will be
used by the measure tool in the next commit, instead of having it
implement its own angle calculation.
(cherry picked from commit d2f33cf1be)
Fix gimp_constrain_line() and friends to properly constrain line
angles when the image's horizontal and vertical resolutions are
different, and dot-for-dot is disabled.
(cherry picked from commit 4fefab1798)
Remember the sample point's GimpColorPickMode in the sample point
itself, so it is remembered across switching between images.
Not persistent in the XCF yet tho...
(cherry picked from commit a0129504c8)
This is just some preparation for fixing issue #1805, but actually
"target" is a much better name so I went the full way and also changed
GUI labels and the color picker tool options config property
accordingly.
If anyone notices at all, how horrible is it to lose your saved pick
target...
(cherry picked from commit b140b283dc)
In gimp-parallel, always flush the async-operations queue (by
executing all remaining operations on the caller thread) when
setting the async-pool thread count to 0 (as happens when setting
GEGL_THREADS=1, per the previous commit,) and not only when
shutting GIMP down. Otherwise, pending asynchronous operations
can "get lost" when setting GEGL_THREADS to 1.
Additionally, in gimp_gegl_init(), initialize gimp-parallel before
before connecting to GimpGeglConfig's "notify::num-processors"
signal, so that the number of async threads is set *before*
GEGL_THREADS, in order to avoid setting GEGL_THREADS to 1 while
async operations are still executing.
Also, allow setting the number of gimp-parallel-distribute threads
while a gimp-parallel-distribute function is running (which can
happen if gimp-parallel-distribute is used in an async operation,
as is the case for histogram calculation), by waiting for the
parallel-distribute function to finish before setting the number of
threads.
(cherry picked from commit 432a884715)
When GEGL_THREADS=1, concurrent access to the same buffer is not
safe, which can result in errors if asynchronous operations are
allowed to run in parallel to the main thread (see
https://gitlab.gnome.org/GNOME/gimp/issues/1721#note_265898.)
Disable parallel execution of asynchronous operations when
GEGL_THREADS=1 for now, to fix this. Ultimately, GEGL should be
able to remain thread-safe even when GEGL_THREADS=1. Note that we
want to execute asynchronous operations on a separate thread even
when GEGL_THREADS=1, since the goal here is mainly to avoid
blocking the main thread during their execution, rather than
speeding their execution up (in particular, it's benecifical to run
asynchronous operations in parallel even on a single-core machine,
while parallelizing GEGL operations generally isn't.)
(cherry picked from commit 408540659f)
In GimpContainerTreeView, don't process updates in response to a
selection-change if the selection is empty (for the reason this is
necessary in the first place (though not in this particular case),
see commit f9a71fb6de5a2e65e0d88c6b7aaa39f589d6cdc4.) When
clearing the container-view's context, we deselect all items after
setting the context to NULL, in which case
gimp_view_renderer_draw() warns, breaking one of our tests.
...not found if language changed since last session
For various reasons, (gimp-context-get-brush, pattern, gradient, ...)
can return "Standard" which is the untranslatable name of the internal
fallback object.
Therefore, we must accept "Standard" as fallback in all PDB functions
that take brush, pattern, gradient etc. names.
(cherry picked from commit 397ae027ba)
...and successfully fails
Commit d2ad2928 removed "gradient-repeat" from GimpPaintOptions, not
considering that it is also used in the PDB.
Move "gradient-repeat" from GimpGradientOptions back to
GimpPaintOptions, and add a comment that it is only used by the
gradient tool, not for painting.
(cherry picked from commit c3d37140eb)
- "LCh" intead of "LCH"
- "CIE LCh" instead of "CIELCh"
- "HSV Hue" instead of "Hue (HSV)" for all models/components
(cherry picked from commit 926dc070ef)
In GimpContainerTreeView, work around a GTK bug which can cause the
window containing the tree view to stop processing updates,
resulting in an apprarent freeze, until update-processing is
explicitly requested. This can be triggered by adding layers to a
layer group until the layers-dialog tree view is almost full, but
still doesn't have a scrollbar, and then duplicating the group.
This doesn't seem to affect GTK3, so not applying to master.
Don't destroy the color frames when the number of points changes.
Instead, simply hide them so they keep their color model, but add an
upper limit of an arbitrary number of 16 frames to keep around.
(cherry picked from commit 370680f9bc)
Use gimp_babl_is_valid(), added in the previous commit, to validate
image-type/precision combinations in various functions.
(cherry picked from commit 49ca383fa4)
... (valgrind reports Invalid read)
Add gimp_babl_is_valid(), which takes a GimpImageBaseType and a
GimpPrecision, and determines whether the image-type/precision
combination is valid. Use this function to validate that loaded
XCFs use a valid type/precision combination, before trying to
create the image. Otherwise, we get a CRITICAL, and eventually a
segfault, when the combination is invalid.
Use the same function to validate the arguments of
gimp_image_new().
(cherry picked from commit a0a62656d2)
Introduce GIMP_PATTERN_MAX_SIZE (10000) and GIMP_PATTERN_MAX_NAME (256)
and validate pattern dimensions and pattern name length against them.
Add GIMP_BRUSH_MAX_NAME and validate that too.
Also make sure that the names are properly terminated, and some
cleanup.
(cherry picked from commit 9b56ca8c1d)
In app_exit_after_callback(), call gimp_gegl_exit() before
gegl_exit() when performing a quick shut-down in stable versions,
so that gimp-parallel, and, in particular, the async thread pool,
is properly shut down. Code running in the async thread pool may
use GEGL (in particular, now the drawable previews are rendered
asynchronously), and calling gegl_exit() while it's still running
is unsafe.
(cherry picked from commit ed033b1cb5)
In GimpAction, instead of connecting the action-history log
function to the action's "activate" signal as a user-provided
handler, call it directly from the default handler.
In subclasses of GimpAction, chain to the parent's activate()
function before emitting the "selected" signal, so that we always
log the action in the history before responding to it.
This allows us to avoid the hack in commit
6544ce4301.
(cherry picked from commit 114d49510f)
In xcf_write_int8(), avoid calling g_output_stream_write_all() with
data == NULL and count == 0, in which case it raises a CRITICAL and
doesn't set bytes_written, which we proceed to use uninitialized.
This can happen, e.g., when writing an empty parasite.
(cherry picked from commit 8e798e9cf2)
In gimp_color_profile_new_from_icc_profile() and
gimp_image_validate_icc_profile(), don't raise a critical when
encountering an empty profile, but rather reject it gracefully with
an error.
(cherry picked from commit 10f33b080b)
... (Invalid read reported by valgrind)
In gimp_image_parasite_validate(), don't segfault when validating
a "gimp-comment" parasite of size 0 (i.e., whose data is a 0-byte
array, not an empty string), and just consider it invalid.
(cherry picked from commit f384a0713d)
... (Invalid read reported by valgrind)
In xcf_read_int8(), avoid calling g_input_stream_read_all() with
data == NULL and count == 0, in which case it raises a CRITICAL and
doesn't set bytes_read, which we proceed to use uninitialized.
This can happen, e.g., when reading an empty parasite.
(cherry picked from commit 6ebadea7c1)
In gimp_action_history_activate_callback(), bail if history.gimp is
NULL, instead of dereferencing it. This can happen if GIMP is shut
down during the execution of a temporary procedure, such as a
script-fu script. See the code comment for details.
(cherry picked from commit 6544ce4301)
Remove the now-useless "independent" parmaeter. It is supplanted
by the new gimp_parallel_run_async_independent() function.
(cherry picked from commit 00d034a1d4)
Add an "async" field to the dashboard's "misc" group, showing the
number of async operations currently in the "running" state (i.e.,
all those GimpAsync objects for which gimp_async_finish[_full]() or
gimp_async_abort() haven't been called yet).
(cherry picked from commit aa382650a1)
Preview generation for layer groups is more expensive than for
other types of drawables, mostly since we can't currently generate
layer-group previews asynchronously. Add a preferences option for
enabling layer-group previews separately from the rest of the
layer/channel previews; both of these options are enabled by
default. This can be desirable regardless of performance
considerations, since it makes layer groups easily distinguishable
from ordinary layers.
(cherry picked from commit 30cc85fd63)
In the preferences dialog, make the "dither images when promoting
to floating point" option insensitive when the "promote impoprted
images to floating point precision" option is unchecked.
(cherry picked from commit 5b9bc0aadd)
In GimpViewRendererDrawable, use
gimp_drawable_get_sub_preview_async(), added in the previous
commit, to render drawable previews asynchronously. While the
preview is being rendered, either keep showing the previous
preview, or render a placeholder icon.
This commit also fixes an issue where, under certain conditions, a
drawable preview would be rendered, even when layer/channel
previews are disabled in the preferences.
(cherry picked from commit 8a81bfd2f1)
... which is an asynchronous version of
gimp_drawable_get_sub_preview().
We currently support async preview generation for drawables whose
buffer isn't backed by a GimpTileHandlerValidate tile handler
(i.e., anything other than group layers), since preview generation
fir such drawables may involve processing the corresponding graph,
which isn't thread-safe.
When the GIMP_NO_ASYNC_DRAWABLE_PREVIEWS environment variable is
defined, all drawable previews are synchronously generated.
(cherry picked from commit d79e3fbd6f)
Remove the "independent" parameter of gimp_parallel_run_async(),
and have the function always execute the passed callback in the
shared async thread-pool.
Add a new gimp_parallel_run_async_full() function, taking, in
addition to a callback and a data pointer:
- A priority value, controlling the priority of the callback in
the async thread-pool queue. 0 is the default priority (used
by gimp_parallel_run_async()), negative values have higher
priority, and positive values have lower priority.
- A destructor function for the data pointer. This function is
called to free the user data in case the async operation is
canceled before execution of the callback function begins, and
the operation is dropped from the queue and aborted without
executing the callback. Note that if the callback *is*
executed, the destructor is *not* used -- it's the callback's
responsibility to free/recycle the user data.
Add a separate gimp_parallel_run_async_independent() function,
taking the same parameters, and executing the passed callback in
an independent thread, rather than the thread pool. This function
doesn't take a priority value or a destructor (and there's no
corresponding "_full()" variant that does), since they're pointless
for independent threads.
Adapt the rest of the code to the changes.
(cherry picked from commit b74e600c12)
and remove all other tool options parent setting/unsetting and
property copying code. Also select a tool at the end of
tool_manager_init() so it is in sync with what the tool options
manager does.
(cherry picked from commit 37f69457b7)
tool_options_manager_tool_changed(): also copy the non-global paint
options of the new tool to the global paint options, so they get used
when "global_foo" is enabled.
(cherry picked from commit 1b858eb4ad)
tool_options_manager_paint_options_notify(): sync properties between
tool paint options and global paint options if the property is global
*or* the active tool is involved.
tool_options_manager_global_notify(): don't mess with the active
tool's connection to the user context or its properties at all, it is
always fully connected to the user context anyway.
(cherry picked from commit 54257da7c4)
The way we currently manage tool options, and particularly copy things
around for "global_brush", "global_pattern" etc. sucks, is spread
across files, happens only on tool change, is thus buggy and leads to
all sorts of small inconsistencies.
This new manager will replace all of that stuff, and it does it in one
place, and will keep the user context, the global paint options, and
all tool options connected permanently, and only connect/disconnect
things when settings change, so everything is always in a consistent
state.
Pushed for review only, nothing is used yet.
(cherry picked from commit ef952f2926)
In GimpMeter, use cairo_path_extents() for getting the history
graph's extents, rather than cairo_clip_extents(), since the latter
may also include clipping applied by GTK.
(cherry picked from commit b8e08cddbc)
According to some bug reports, it seems that under some (unknown)
conditions we might save an empty custom gradient file on exit (for
equally unknown reasons). The only difference in the way we save
internal data files, such as the custom gradient, compared to
gimp_data_save(), is the fact that we currently don't explicitly
close the output stream, but rather only unref it.
The output stream should be implicitly closed (and hence flushed)
upon destruction, but maybe the unreffing is not enough to
guarantee that it's actually destroyed (maybe it spawns an extra
reference for some reason, who knows.) Anyway, let's just
explicitly close it, which also gives us a chance to catch and
report any errors occursing during flushing/closing (which,
altenatively, might be the culprit).
Additionally, a few more error-reporting improvements, to match
gimp_data_save().
(cherry picked from commit a72f7f1ace)
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
(cherry picked from commit b5890e05b8)
GIMP_BRUSH_MAX_SIZE was already defined (as 10.000 pixels per dimension,
which is big for a brush) in gimpbrush.h. Let's just use this to
validate the size returned by the header.
(cherry picked from commit b3de0bb7a5)
The "move-current" flag does not apply to selection mode and our current
code was simply setting the radio buttons insensitive while showing the
same labels on both buttons. This was not wrong per-se, yet very
confusing.
Instead let's just hide the radio buttons in selection mode, and update
the option title to "Move selection" (old label of both buttons) to keep
this mode as understandable as possible.
(cherry picked from commit 7cbbb8cba8)
When defining a dashboard group, allow specifying multiple
variables as input to the group meter's LED. The LED is active
when any of the specified variables evaluates to TRUE, and its
color is the combination of the active variable colors.
Remove the swap-busy variable, and use swap-reading and
swap-writing as inputs to the swap group's LED instead, so that the
LED's color indicates whether the swap is currently being read-
from, written-to, or both.
(cherry picked from commit 716510cb83)
Put the center_image_on_size_allocate() code into the canvas'
size-allocate callbacck.
As a side effect we now have a flag in GimpDisplayShell which
indicates that there will be a size allocate before the next frame, so
simply skip drawing the canvas completely. This fixes new images
jumping around when they are first shown.
(cherry picked from commit c0480f502d)
(this fix is actually a side effect from fixing something else in
master)
The flag `free_selection_string` is used to track an array of strings
with some of them being static and others allocated. This should have
been an array of boolean but we can't change it because it is public API
(though it should really not have been!).
So let's just allocate every string of the `selection` array instead,
which makes the boolean flag useless now.
... --enable-relocatable-bundle option.
This will allow to use this option for more than MyPaint brushes. For
macOS and Windows, we default to "yes" and "no" for other OS, though it
is always possible to set an explicit value.
(cherry picked from commit 8da2646372)
As asked by Samm and solid_black on IRC.
Apparently tested and the change is fine, while getting rid of
deprecated API. I cannot test myself.
(cherry picked from commit 1b9729d46d)
We should not have essential signal connections (such as setting tool
options from brush properties) implemented in the tool options GUI
files, because they are not active until the options GUI is created.
Also, that magic is simply too hidden in the options GUI files.
Move the signal connections and the brush property copying code to
gimppaintoptions.c where is can also be done cleaner.
However, this must only be done for the main tool options instance
that is used for the GUI. Therefore, add a "gui_mode" boolean to
GimpToolOptions and set it to TRUE for all main tool options.
(this is ugly, but much less ugly and much less hidden than all the
places where code lives (like tool_manager.c) that can now be moved
into GimpToolOptions and its subclasses, and implemented cleanly
there).
(cherry picked from commit cb0e6c65d0)
GTK always returns 72 dpi due to API used. This patch using Cocoa
directly instead. Tested on Retina and non-hidpi displays.
GTK+2 version of commit 5b6126146a.
Cf. MR !14.
... metadata by default".
Also for other metadata, and doing it both for the tooltip and the label
of the option.
(cherry picked from commit 50bcc8db3c)
Let the split and replicate segments dialogs keep their own data and
don't use GimpGradientEditor struct members. Remove redundant members
and indent the struct.
(cherry picked from commit b8e75a0201)
This reverts commit d997b2b897.
This is not needed anymore since gimp_widget_load_icon() always returns
a non-NULL GdkPixbuf now. Cf. commit 32931c4606.
We were already doing so when an icon was simply absent from the icon
theme. But we may still end up in cases where the icon is seemingly
present, yet it fails to load (for instance the image file is
corrupted). When this happens, let's also try to load the wilber-eek
fallback.
Note that it doesn't completely stops gimp_widget_load_icon() from
possibly returning NULL (in the case where "gimp-wilber-eek" is also
missing/corrupted for instance), so calling code must still account for
possible NULL return value.
If "gimp-swap-colors" or "gimp-default-colors" are present in the theme,
yet broken somehow, GIMP would crash because it was not checking if the
icons had been successfully loaded.
Just make the relevant checks and output on standard error that the swap
and/or default color areas are invisible.
Set the tooltip in GimpColorHexEntry itself and remove all other
tooltip setting. This just moves the translatable string sround in
libgimpwidgets/, and even removes it from app/.
(cherry picked from commit 2b8b780b6a)
Return an optional tooltip from gimp_procedure_get_sensitive(), in
GimpPlugInProcedure, build that tooltip from the image types the
procedure works on.
(cherry picked from commit 63817485c0)
... to satisfy the inter-variable dependencies, so that the READING/
WRITING variables are based on the READ/WRITTEN values of the
current sample, and not the previous one.
(cherry picked from commit 51793b114a)
... and gimppaintcore-loops
When a rectangle argument is NULL, use the extents of the
corresponding buffer, instead of raising a CRITICAL, to match the
old behavior.
(cherry picked from commit 8a881ca61a)
Don't show percentage for the swap read/written fields, and make
sure their history underlays are displayed correctly even if the
swap limit changes.
(cherry picked from commit fda671841c)
Add "read" and "written" fields to the dashboard swap group, which
report the total amount of data read-from/written-to the tile swap,
respetively. These fields are non-active by default. When these
fields are active, show a color underlay in the swap group's meter,
indicating when data was beging read-from/written-to the swap.
Improve the swap busy indicator (used as the meter's LED), so that
it's active whenever data has been read-from/written-to the swap
during the last sampling interval, rather than at the point of
sampling.
(cherry picked from commit 6b9aba3067)
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
(cherry picked from commit 993bbd354e)
... which are similar to g_ascii_strtoll() (except that
gimp_ascii_strtoi returns a gint, and not a gint64), and
g_ascii_strtod(), however, they make error checking simpler, by
returning a boolean value, indicating whether the conversion was
successful (taking both conversion and range errors into account),
and return the actual value through a pointer.
(cherry picked from commit 3301c06163)
... which is a drop-in replacement for
g_data_input_stream_read_line(), however, it always returns a non-
NULL value when there's no error. If the end-of-file is reached,
an empty string is returned.
(cherry picked from commit e090b910c0)
same code as in GimpDeviceManager, should be only ever needed in the
presence of debug modules like GtkInspector.
(cherry picked from commit bf66882878)
...while other windows are on the second monitor if window positions
are saved at exit
Add some lines of code to color_area_color_clicked() which position
the already existing color dialog exactly like a newly created dialog
would be positioned by gimp_dialog_factory_add_dialog().
This should be part of GimpDialogFactory but let's wait for another
case before we generalize it.
(cherry picked from commit 1ae2b5d573)
When using the color-picker tool's info window, set the tool's
display when a color is picked, and the gui is updated, so that we
properly halt the tool when the display is closed. Otherwise, we
may segfault.
(cherry picked from commit 335023b127)
The memory group shows memory-usage information: the currently used
memory size, the available physical memory size, and the total
physical memory size. It can also show the tile-cache size, for
comparison against the other memory stats. The memory group is
active but contracted by default.
Note that the upper-bound of the meter is the physical memory size,
so the memory usage may be > 100% when GIMP uses the swap.
This is currently implemented for *nix systems with Linux-like
procfs, and Windows.
(cherry picked from commit 8d0766c1fc)
gimp_layer_create_mask(): make sure we don't do a gamma conversion
when initializing the mask from a channel. This was probably not the
last place to need this fix.
Also get rid of a second switch(add_mask_type), must be some leftover
from long gone logic.
(cherry picked from commit f815a2d922)
...upon exporting an image
Step 1: make it configurable just like "Export EXIF" etc.
app, libgimp: add "export-color-profile" config option
Add it to the preferences dialog, and pass it on to plug-ins in the
GPConfig message. Add gimp_export_color_profile() to libgimp.
Nothing uses this yet.
(cherry picked from commit 8c9c091021)
Mostly formatting and thortening variables. Only real change is adding
gimp_clipboard_new() and moving most init() code there.
(cherry picked from commit e0f46d1dc9)
Make the bottom-left entry request only minimal width, it expands
anyway. Also replace the "Columns:" label by a "grid" icon and set a
tooltip on the columns spinbutton.
Addresses Issue #1223 too.
(cherry picked from commit 0aa018dec2)
Replace "Selection Bounding Box" by simply "Selection" and add a tooltip
to the frame that says it's the bounding box.
Addressed Issue #1223.
(cherry picked from commit 33d2595d22)
... with a color profile other than the gimp built-in.
When initializing the smude tool's accum buffer, use
gimp_pickable_get_pixel_at(), instead of
gimp_pickable_get_color_at(), for picking the initial color to fill
the buffer with, so that we don't erroneously apply the image's
color tranform to it when the image has a profile. Previously,
this would result in wrong colors when painting from the drawable
edges inward, with flow < 100%.
(cherry picked from commit 5a07876c78)
gimp_eek(): simply increase gimp->busy so XCF saving calling
gimp_set_busy() and gimp_unset_busy() won't call the GUI layer and do
whatever windowing system calls to set busy cursors.
(cherry picked from commit eaddef595e)
... with a color profile other than the gimp built-in.
Remove the separate alpha-channel copy in
gimp_image_color_profile_srgb_to_pixel(). We no longer need it,
since GimpColorTransform already takes care of that itself.
We used babl_process() to copy the alpha, which would also
transform the input color from R'G'B' to the output color space.
When the same buffer was used for both input and output, this call
would overwrite the input to the subsequent
gimp_color_transform_process_pixels() call; when the output color
space was different than R'G'B', this meant we'd pass the input to
gimp_color_transform_process_pixels() in the wrong color space,
producing wrong results. This was the case when converting the
foreground color for use with the smudge tool.
(cherry picked from commit e58e2ec5dc)
resize_dialog_new(): create the preview with "popup = TRUE", so we
really get a preview of layer size and not of the layer within the
image context like used for the layers dialog.
(cherry picked from commit 93d28ceccc)
when the GimpDeviceInfo already has a device. This is not a programming
error that should trigger a bug report popup, it's something else about
non-uniqueness of device names, or whatever. Simply g_printerr() a more
useful message that can help to debug this and bail out.
(cherry picked from commit f06d0485e6)
...after program restart
GimpContext was always supposed to keep the names of objects (brush,
pattern, font etc.) around even if these objects don't exist, for
cases like refreshing the data in a GimpDataFactory (which worked
fine), but also for deserializing the names of objects which don't
exist *yet* (delayed loading, no-data or whatever).
This commit fixes the delayed loading case (particularly affects fonts):
gimp_context_deserialize_property(): always keep the name of the
object around when it is not found, not only in the no-data case.
gimp_context_copy_property(): always copy the object *and* its name to
the dest context.
Add GimpConfig::duplicate() and ::copy() implementations which chain
up for duplicating/copying all properties and additionally copy all
object names to the new/dest context.
(cherry picked from commit ed1e2b1524)
It seems it was simply forgotten. PROP_MASK_ALL is used at some very
central places, so this commit might fix a few subtle bugs, or
introduce new ones, everybody look for strange tool preset behavior
please :)
(cherry picked from commit b3690b48d9)
Same as we did for binfmt-style lines, if the executable part (for
instance in `pygimp.interp`) is not an absolute path, let's allow
ourselves to find it in the environment $PATH.
So basically our binfmt set for Python simply never worked since we just
set 'python' and not a full path, but current code was not looking in
the $PATH environment. This was dead code. Now it's fixed.
Current code of gimp_interpreter_db_resolve() was only resolving the
interpreter by the file extension when the file could not be opened for
reading or if it was empty/coult not be read. This basically made this
test completely useless.
Let's fix this. Now it will be run all the time, but simply at the end,
if shebang and magic failed.
In GimpScaleTool, fix scaling around the center-point, and make
sure the width and height are always >= 1 when updating the
transformation in response to a widget change.
(cherry picked from commit 1516bfc14b)
Get rid of GimpTransformGridTool::recalc_matrix() and
gimp_transform_grid_tool_recalc_matrix(), and have
GimpTransformGridTool and its subclasses use
GimpTransformTool::recalc_matrix() and
gimp_transform_tool_recalc_matrix() directly instead.
In order to break the GimpToolWidget::changed/
GimpTransformTool::recalc_matrix() loop, add a
GimpTransformGridTool::update_widget() vfunc, which subclasses
should override to update their tool-widget (instead of doing this
in ::recalc_matrix()), and ::widget_changed(), which is called when
the tool-widget changes (and which subclasses should override
instead of connecting to the tool-widget's "changed" signal
directly.) GimpTransformGridTool calls these functions as
necessary, instead of relying on extra parameters passed to
recalc_matrix().
Adapt all the direct and indirect subclasses of
GimpTransformGridTool to the change.
(cherry picked from commit 6a3fc6c1b9)
In GimpTool, always clear tool->drawable upon halting, even for
tools that don't use it explicitly.
GimpTool sets tool->drawable in its default button_press()
implementation, and we potentially access it in
gimp_display_shell_initialize_tool(), so failing to clear it when
halting the tool may leave it as a dangling pointer, which can
result in a segfault when trying to initialize the tool in the
above function. In particular, this happens with the iscissors
tool.
(cherry picked from commit 58c96f596e)
In GimpCanvasTransformPreview, when the image mask is not empty,
make sure to align it with the drawable using a gegl:translate
node, before combining both at the gegl:opacity node. Otherwise,
the mask is applied at the wrong offset when the drawable's offset
is not (0, 0).
(cherry picked from commit d3a3c35317)
Make gimp_free_select_tool_halt() protected, and call it in
gimp_foreground_select_tool_set_trimap(), so that the free-select
subobject of the foreground-select tool is properly shut down
before switching to trimap mode. In particular, this clears the
free-select tool widget at the right point; failing to do this
leads to CRITICALs later on.
(cherry picked from commit e15733236c)
In GimpToolRectangle, call gimp_tool_rectangle_update_options()
when the "[xy][12]" properties change, so that the "x", "y",
"width", and "height" properties are updated accordingly.
In particular, we set these properties when committing an empty
rectangle select tool, to init the rectangle to the current
selection bounds, and this call is necessary so that the "x", "y",
"width", and "height" tool options are properly updated as well.
(cherry picked from commit 47b7e7be7d)
In gimp_image_set_colormap(), make sure the image's colormap always
has at least one color -- babl palette formats must have at least
one color.
If the function is called with 0 colors, use black. We still need
to support this case, in particular, since existing XCFs may have
an empty colormap, and since plug-ins can call
gimp-image-set-colormap with 0 colors.
(cherry picked from commit c16c68e63e)
Last commit reintroduced this bug.
Allow transforming invisible layers using transform-grid tools, by
adding a 'drawable' member to GimpTransformTool, and setting/
clearing it when initializing/halting a GimpTransformTool. In
gimp_transform_tool_check_active_item(), skip the visibility check
if the active item equals the GimpTransformTool's 'drawable'
member.
(cherry picked from commit cea6f1dc73)
Split gimp_transform_tool_get_active_item() into two functions:
gimp_transform_tool_get_active_item(), which returns the item
without checking for errors, and
gimp_transform_tool_check_active_item(), which returns the active
item while checking for errors. Adapt the rest of the code to the
change.
Remove the invisible_layer_ok parameter of
gimp_transform_tool_check_active_item(), and always return an error
when the active layer is invisible. This causes the flip and
measure tools to correctly reject invisible layers. Un-hide the
active item in GimpTransformGridTool before transforming, to avoid
rejecting layers that were hidden by the tool.
(cherry picked from commit 360b25b9a8)
... and various other palette formats
Change accidental 'G_IS_INPUT_STREAM (file)' argument validation to
'G_IS_INPUT_STREAM (input)'.
(cherry picked from commit ea6d997e56)
Derive GimpMeasureTool from GimpTransformTool (and
GimpMeasureOptions from GimpTransformOptions), so that we can reuse
GimpTransformTool's logic for the "straighten" function. This
simplifies the code, aligns the measure tool with the rest of the
transform tools in terms of transform-related options (it can now
transform selections and paths, in addition to layers, and the
resampling method and clipping behavior are adjustable,) and fixes
straightening of layer groups.
Rename the function from "auto straighten" to just "straighten".
Don't resize the canvas after straightening. Since we only
transform the active layer, and not the entire image, resizing the
canvas doesn't make much sense.
When in 3-point mode, rotate the second point toward the third
point, rather than toward the x-axis.
(cherry picked from commit b0cf2e435a)
While most of our transform tools use an interactive transform
grid, and have similar behavior, the flip tool is an odd one out.
The new "auto straighten" function of the measure tool introduces
another tool that performs transformations, while not behaving like
the rest of the transform tools.
Factor out the parts of GimpTransformTool that handle user
interaction into GimpTransformGridTool (with corresponding
GimpTransformGridOptions, and GimpTransformGridToolUndo), and only
leave the basic transform functionality and options in
GimpTransformTool (and GimpTransformOptions).
Derive all the transform tools (and transform-tool base classes)
that previously derived from GimpTransformTool, from
GimpTransformGridTool. The one exception is GimpFlipTool, which
still derives from GimpTransformTool directly. The next commit
will derive GimpMeasureTool from GimpTransformTool as well.
Never return an internal image/buffer/svg/curve from any
gimp_clipboard function if we are not the owner of the display's
clipboard. The clipboard is supposed to be a global thing, and we must
only offer to ourselves what would be pasted in any other app.
(cherry picked from commit 7d3a129ddd)
Add GimpPaintTool::paint_[xy] members, and periodically assign the
paint core's current coords to them in
gimp_paint_tool_paint_timeout(), while the main thread and the
paint thread are synchronized, during painting.
In gimp_paint_tool_draw(), fetch the current coords for the brush
outline from the above members during painting, instead of directly
from the paint core, to avoid a race condition with the paint
thread, so that we always use the correct coordinates at the time
the paint buffer was flushed back to the drawable.
(cherry picked from commit 5c17d2a43b)
...won't work with older GIMP?
Make gimp_image_get_xcf_version() return a "reason" string which lists
all reasons why the image can't be saved with compatibility for older
GIMP versions. Display the reason as tooltip on the compat hint label
in the save dialog.
(cherry picked from commit a4061a6b0d)
When creating a layer group, or a text layer, use the image's
default new-layer mode, instead of always using (non-legacy)
NORMAL.
(cherry picked from commit 7c7b6eb537)
Instead just transform the measurement extremities appropriately to
still map to the same points.
To do so, I also added out parameters to gimp_image_resize_to_layers()
so that calling code can get offsets from old origin (as well as new
image dimensions).
(cherry picked from commit d56a8d439e)
In particular, this tool should not make huge rotation where the top
ends up in the bottom and it should not depend on whether we started the
measure tool from the left, right, bottom or top. This is fixed by using
atan() instead of atan2().
Also make a proper tooltip text. Help id is unneeded most likely though.
Finally do some cleaning and alignment.
(cherry picked from commit ba1d937dfb)
gegl:recursive-transform-plus is an extension of
gegl:recursive-transform, allowing multiple transformations to be
applied simultaneously; it will eventually be merged back into
gegl:recursive-transform. See GEGL commit
9829bc22e85526d789c4e80c05949d4c6202a207.
The GUI uses the new TRANSFORM_GRIDS controller, allowing adding,
duplicating, and removing transformations, and controlling them
through on-canvas transform grids.
(cherry picked from commit 99828a697a)
... which is similar to the TRANSFORM_GRID controller, supporting
multiple transformation matrices.
Implement the TRANSFORM_GRIDS controller in GimpFilterTool, using
the new GimpToolWidgetGroup to display multiple transform grids.
(cherry picked from commit 5e953ece85)
GimpToolWidgetGroup is a tool widget acting as a container for
child widgets, multiplexing widget events and demultiplexing tool
events. It can be used by tools to display multiple widgets
simultaneously.
The group keeps track of the current focus widget, and hover
widget. Certain events are only dispatched to/forwarded from these
widgets.
The hover widget is determined by performing a hit test for all the
children, starting from the last child. The first widget returning
GIMP_HIT_DIRECT, if any, is selected as the hover widget;
otherwise, if the current focus widget returns GIMP_HIT_INDIRECT,
it's selected; otherwise, if exactly one widget returns
GIMP_HIT_INDIRECT, it's selected; otherwise, there is no hover
widget.
The focus widget is set when clicking on a widget (or
programatically, using gimp_tool_widget_set_focus()).
Additionally, the group can raise the clicked widget to the top of
the stack (see gimp_tool_widget_group_set_auto_raise().)
(cherry picked from commit 4ef06b9922)
... which emits the "changed" signal, for use in subclasses to
notify the tool about widget changes not resulting from property
changes.
(cherry picked from commit 614cdcc0a8)
... which takes the same arguments as GimpToolWidget::hover(), and
performs a hit-test, returning one of the following values:
- GIMP_HIT_DIRECT: The point corresponds to one of the widget's
elements directly.
- GIMP_HIT_INDIRECT: The point does not correspond to one of the
widget's elements directly, but the widget otherwise responds
to press events at this point.
- GIMP_HIT_NONE: The widget does not respond to press events at
this point.
Unlike hover(), hit() should not have any side effects.
(cherry picked from commit 385203f4d6)
... by having them disable item highlights, and any other proximity
indication, when the cursor leaves the widget.
(cherry picked from commit 5e736c697f)
... which should be called on a widget when the cursor leaves the
widget, i.e., when it stops receiving hover events.
Have the default implementation clear the tool status.
(cherry picked from commit be7eff980e)
The next few commits are going to add support for using multiple
tool widgets simultaneously. As a first step, add a notion of a
focused tool widget, by adding gimp_tool_widget_{set,get}_focus(),
which tools/subclasses can use to control focus, and a
corresponding "focus-changed" signal, which tools/subclasses can
use to respond to focus changes.
(cherry picked from commit eeed9c413b)
specified by GimpDataLoaderEntry structs. Remove the same code from
GimpDataFactory and make it an abstract base class that only serves as
an interface for actual implementations. Also move around some stuff
in GimpDataFactory and remove virtual functions that were a bad idea
in the first place.
(cherry picked from commit 73da7c9a54)
When Control-Button2-Zooming, remember the start point, pass it to
gimp_display_shell_scale_drag() and force gimp_display_shell_scale()
to zoom around that point by passing GIMP_ZOOM_FOCUS_POINTER and
faking the point using gimp_display_shell_push_zoom_focus_pointer_pos().
(cherry picked from commit 792cd581a2)
so pull it to the parent class. Also remove the "no_data" parameter
from the data_init() virtual function and handle it in
gimp_font_factory_data_init() itself.
(cherry picked from commit d1b9f74c6f)
Sans-serif is also an actual font from the list and the standard font
is being used when there is really no font at all.
(cherry picked from commit 6b5fd27943)
Also, make sure we freeze() and thaw() the font container correctly,
so that all places keep their fonts across a refresh.
The only thing to make this actually work seems to be a bug in the
list views, grid views work perfectly.
(cherry picked from commit 1b1739bb06)
which contains all the font loading and refreshing including all async
stuff and is a complete replacement for gimp-fonts.c and GimpFontList.
(cherry picked from commit 0763ea2a69)
Virtualize a lot of functions and move their code into the default
implementation. Also connect to changes of the "path" property and
reload data automatically when the path changes. Add "wait" method
which is by default empty but is to be implemented by fonts.
(cherry picked from commit 01e4104236)
Make sure gimp_async_set_wait() and gimp_async_set_cancel() work
correctly, even if the set changes in nontrivial ways as a result
of waiting-on/canceling individual operations. This is purely
theoretic right now, but why not.
(cherry picked from commit ec5f4d03fa)
This is mostly core code which we want to keep in sync with master as
long as possible, so I picked this one even though not strictly
neccessary.
(cherry picked from commit 1b7d63cce9)
When font loading is finished, restore the font list in the
corresponding async completion callback, and not in the
"notify::empty" signal handler of the fonts async set
This solves a problem arising when gimp_fonts_wait() is called
*inside* a "notify::empty" signal handler, emitted when reloading
fonts (causing the "empty" property of the fonts async set to
switch from TRUE to FALSE): When the wait is over, "empty" will
switch back from FALSE to TRUE, however, since the "notify" signal
is non-recursive, the corresponding handler will not be called,
gimp_fonts_wait() will return *before* the font list is restored,
and the caller will see an empty font list. This can happen under
certain circumstances when reloading fonts while the text tool is
active.
(cherry picked from commit 0e19f159f5)
In the threshold and levels tools, use gimp_wait() to wait for
histogram calculation to complete before applying auto-adjustment,
so that a message is displayed in the meantime. Allow the
operation to be canceled, in which case we simply abort the auto-
adjustment, but let the histogram calculation continue.
Use gimp_fonts_wait(), added in the previous commit, to wait for
fonts to finish loading before operations that depend on font
availability. In particular, this includes font- and text-related
PDB functions, and text-layer rendering.
... which waits for font-loading to complete, using gimp_wait() to
show a message while waiting.
Note that we don't currently allow the wait to be canceled, since
it may have unpredictable effects on plug-ins, but the interface is
such that the wait might not complete, so calling code should be
prepared for that.
Add a GimpGui::wait() virtual function, and a corresponding
gimp_wait() function. The function takes an object implementing
the GimpWaitable interface, and a printf-style message, and waits
for the object to become ready, displaying the message as
indication in the meantime. The default implementation simply
prints the message to STDERR.
Implement the function in gui-vtable, using the busy-dialog plug-
in added in the previous commit, to display the message in a
dialog. Additionally, if the object implements the GimpCancelable
interface, provide a "cancel" button in the dialog, which, when
pressed, causes gimp_cancelable_cancel() to be called on the
object. Note that the function keeps waiting on the object even
after requesting cancelation; GimpTriviallyCancelableWaitable can
be used to stop the wait once cancelation has been requested.
Pass the current icon theme directory to plug-ins through the
config message, and add a gimp_icon_theme_dir() libgimp function
for retrieving it. Note that we already have a similar
gimp_icon_get_theme_dir() PDB function, which we keep around, since
it can be used to dynamically query for the current icon dir,
unlike the former, and since it returns a dynamically-allocated
string, while the rest of the config-related functions return
statically allocated strings.
Use the new function, instead of gimp_get_icon_theme_dir(), in
gimp_ui_init(). This allows gimp_ui_init() to run without making
any PDB calls. Consequently, this allows us to start plug-ins that
call gimp_ui_init() without entering the main loop in the main app.
We're going to add a plug-in that displays an interactive dialog
while the main app is blocking waiting for an operation to
complete, and we need to be able to start the plug-in without
entering the main loop, to avoid the possibility of arbitrary code
being executed during the wait.
Bump the protocol version.
While fonts are loading, show a GimpBusyBox with an appropriate
message above the text tool options, and make the options
themselves insensitive, and in font views, such as in the fonts
dialog (through gimp_container_editor_bind_to_async_set(), added in
the previous commit).
... which takes a GimpAsyncSet and a message, and shows a
GimpBusyBox with that message, instead of the container view, while
the async set is nonempty.
We're going to use this for font-loading indication in font views,
such as in the fonts dialog.
We already avoid rendering text layers while fonts are loading,
showing an appropriate message, but this will soon be replaced with
waiting for the fonts to finish loading.
Instead, don't allow the text tool to start at all while the fonts
are loading (showing an appropriate tool message, and a BAD cursor
modifier), and halt the tool when reloading fonts if it's already
started.
Replace the boolean fonts_loading member of Gimp with
fonts_async_set, which is a GimpAsyncSet object. This allows us
to easily respond to the completion of font loading and reloading,
as will be done in the next commits.
Additionally, move the call to FcConfigSetCurrent(), used to
activate the loaded font configuration, from the async thread to
the main thread, just to be on the safe side, and avoid calling
FcInitReinitialize() in gimp_fonts_reset() if font loading is still
in progress, which is unsafe.
GimpAsyncSet represents a dynamic set of running GimpAsync objects.
The objects are automatically removed from the set once they're
synced.
GimpAsyncSet implements the GimpWaitable and GimpCancelable
interfaces, allowing the entire set to be waited-on or canceled.
Additionally, GimpAsyncSet provides an "empty" property, which
indicates whether the set is empty or not. This allows responding
to the completion of all the GimpAsync objects through the set's
"notify::empty" signal, or drive UI changes through property
bindings.
GimpTriviallyCancelableWaitable is a proxy object for another
GimpWaitable object, implementing both the GimpWaitable interface
and the GimpCancelable interface. While waiting on the proxy
simply waits on the underlying waitable, canceling the proxy
doesn't affect the underlying waitable, even if it implements
the GimpCancelable interface as well, but rather causes subsequent
wait operations on the proxy to successfully complete immediately.
This essentially causes cancelation to abort only the wait, rather
than the underlying operation.
GimpUncancelableWaitable is a simple proxy object for another
GimpWaitable object, implementing only the GimpWaitable interface.
Its main purpose is to mask away the cancelability of an object
implementing both GimpWaitable and GimpCancelable.
In gimp_parallel_run_async(), lower the priority of threads
executing independent async operations. Independent operations
are generally potentially long-standing background tasks, which we
don't want to bog down the rest of the program.
This is currently only implemented on Linux and Windows.
The GIMP version string and the backtrace both look completely wrong
when pasted as-is on gitlab. Somehow all linefeed are gone.
This can be fixed by surrounding these as blocks (triple backticks),
using markdown syntax. Of course now the debug content is not for our
tracker only since packagers are encouraged to replace with their own
tracker URL, but this small markdown syntax is simple enough that it
should not break formatting on other platforms (as far as I know).
(cherry picked from commit d4ff504735)
In gimp_parallel_run_async(), when aborting a GimpAsync operation
in reponse to its "cancel" signal, properly clean up internal data
attached to the object, to avoid use-after-free if the signal is
emitted again.
(cherry picked from commit 3fa4c01bcf)
Add a boolean "independent" parameter to gimp_parallel_run_async().
When FALSE, the passed function is run in the shared async thread
pool; when TRUE, the passed function is run in an independent
thread.
Generally, async operations should run in the async pool, however,
it might be desirable to run long-standing operations, especially
ones that can't be canceled, in independent threads. This avoids
stalling quicker operations, and shutdown.
Adapt the rest of the code for the change. In particular,
initialize the font cache in an independent thread.
(cherry picked from commit ad8add6808)
In gimp_parallel_run_async(), connect to the returned GimpAsync's
"cancel" signal, and abort the operation in response if it's still
enqueued, i.e., if its execution hasn't started yet.
(cherry picked from commit 3958ffbe50)
Have GimpAsync implement the GimpWaitable and GimpCancelable
interfaces, added in the previous two commits, instead of providing
its own public version of the corresponding functions.
Add gimp_async_cancel_and_wait() as a convenience function for both
canceling an async operation, and waiting for it to complete.
Adapt the rest of the code to the change.
(cherry picked from commit e2c56ef407)
Fonts should not be blocking startup as this provides a very bad
experience when people have a lot of fonts. This was experienced even
more on Windows where loading time are often excessively long.
We were already running font loading in a thread, yet were still
blocking startup (thread was only so that the loading status GUI could
get updated as a feedback). Now we will only start loading and proceed
directly to next steps.
While fonts are not loaded, the text tool will not be usable, yet all
other activities can be performed.
(cherry picked from commit 2484dec7d5)
Improve the formalism of a GimpAsync object being "sycned"
(previously referred to as the main thread being "synced" with the
async thread), by both providing a gimp_async_is_synced() function,
separate from gimp_async_is_stopped(), and by improving the type
and function descriptions.
Make sure all previously added callbacks have been called after a
call to gimp_async_wait[_until](), even if these functions are
called from within a callback.
(cherry picked from commit a901c3c1f4)
Replace the custom threading code with a call to
gimp_parallel_run_async(). This simplifies the code, while
maintaining the current (blocking) behavior. In the future, we
might build upon this to actually load the fonts in the background.
(cherry picked from commit 3e92e7a449)
... which is similar to gimp_async_wait(), taking an 'end_time'
parameter, controlling how long to wait for the async operation to
complete.
(cherry picked from commit 68c57548fd)
The default stack size for new threads on MacOS is 512 KiB, making
our 512 KiB limit for stack-allocated buffers in
gimp_operation_layer_mode_real_process() too high. Lower it to
256 KiB.
(cherry picked from commit 367399e5c0)
In gimp_drawable_gradient(), pass the undo description ("Gradient")
to gimp_gegl_apply_operation(), so that its displayed as the
progress text while rendering the gradient, even when applying a
shaped gradient, in which case we end the progress after
calculating the distance map, causing the progress text be NULL
during rendering unless explicitly set.
(cherry picked from commit deee2f14f5)
... which is a drop-in replacement for gegl_buffer_copy(),
parallelizing the copy operation when the source and destination
formats are different, requiring a conversion.
(cherry picked from commit fded25b38c)
and remove all clipping hacks for drawing the canvas background, turns
out they never worked and we were relying on the pattern set on the
window, gah! This optimizes away one entire step of drawing of image
size, for each expose...
The zoom focus discussion on IRC suggests that everybody is annoyed
about centering behavior (or lack thereof), so here is a way to
explicitly center the image witout zooming.
... _even at low zoom levels_
Pass GIMP_ZOOM_FOCUS_POINTER to gimp_display_shell_scale() when
wheel-scrolling, and change the scaling code to really honor
GIMP_ZOOM_FOCUS_POINTER and not apply magic image centering.
This keep the same point centered under the mouse for wheel-scrolling
and the zoom tool (== when the zooming is really triggered at a
certain mouse position).
Implement GimpPickable::get_pixel_average(), added in the previous
commit, in GimpDrawable, GimpImage, and GimpProjection, using
gimp_gegl_average_color(), added in the commit before last. This
is significantly faster than the default implementation.
... which calculates the average color of the pickable over a given
area. Use this function in gimp_pickable_pick_color() when
sample_average is TRUE, and provide a default implementation which
calculates the average color using GimpPickable::get_pixel_at(), as
gimp_pickable_pick_color() did before.
The default implementation is rather slow; classes that implement
the GimpPickable interface can provide a faster specialized version
(see the next commit).
GimpDeviceInfo is a GimpToolPreset now, and using the user context
would cause the device info selected in the dialog to be set globally
as tool preset. Use a temporary context instead, the container view
just needs it because.
gimp_airbrush_stamp(), which is called during the airbrush timeout
to periodically stamp the airbrush, assumes the saved symmetry's
origin is the same as during the original call to
gimp_airbrush_paint(). However, since commit
bc09c71818, we clear the symmetry's
origin at the end of gimp_paint_core_paint(), resulting in an empty
symmetry with a NULL origin during gimp_airbrush_stamp(). As a
result, no dab is painted, and we segfault if there's active
dynamics.
Fix this by saving the symmetry's origin coords during
gimp_airbrush_paint(), and restoring them in gimp_airbrush_stamp().
We rely on GimpDeviceInfo's tool-options being non-NULL, so make sure
this is the case and fix NULL options with the current tool's options
after loading devicerc.
GimpDeviceInfo is the only way to store per-device settings like
color, brush etc. It used to be derived from GimpContext and therefore
limited to the context's properties, causing everything else (all
tool-individual options) to be lost on device change.
Derive it from GimpToolPreset instead, so it's capable of storing
arbitrary tool options.
Adapt things to the new class hierarchy and add a bunch of signal
handlers that make sure the active device's GimpDeviceInfo is updated
properly when the tool changes. Also change device switching
accordingly.
Change GimpDeviceStatus to only show the stuff that is relevant to
each device's tool.
And various small changes to make things work properly...
...like gaussian blur in indexed mode
In GimpDrawable's source node, after the filter stack, insert a node
that converts the pixels back to the drawable's format if the drawable
is indexed.
...in weird ways
In gimp_rectangle_tool_button_press(), when the press triggers a
GimpEditSelectionTool operation (like moving a floating selection),
make sure we don't call COMMIT on a zero-size rectangle, because that
would get special treatment by commit(). Instead, CANCEL a zero-size
rectangle so stuff behaves as if it has never been there.
In gimp_pickable_contiguous_region_by_seed(), use gegl_buffer_get()
to sample the mask buffer, instead of using a sampler. The sampler
is created at the beginning of the operation, and is subsequently
used after modifying the mask buffer, which should be avoided,
since the sampler may return outdated cached data.
We get a lot of packaging bugs for third-party builds in our tracker,
especially since our debug tool now opens directly our bug tracker.
It would be preferred if third-party packagers were to make a first
filtering of bugs and only reported once they knew for sure that the bug
is in core code, and not in packaging.
Our configure script will now propose a --with-bug-report-url option
allowing to set a different web address. This address will be the one
opening in the debug dialog.
... instead of gegl_buffer_sample()
GEGL commit 26f13cbfe9aaaa8c176162e54fdbb8af6876538e got rid of the
per-buffer cached samplers, making gegl_buffer_sample() much more
expensive, suitable primarily for one-off samples.
Use a sampler object instead.
That was an obvious faux ami with French.
Status changed to "press Enter to refine", with the requirement of
staying not too long (this is a status message, not documentation), and
that also announces what will be the next step.
In gimp_histogram_editor_validate(), clear the update timeout, so
that if we validate the histogram before the timeout (in
particular, if editor->histogram itself is clear) we don't end up
unnecessarily re-validating it at the timeout.
... which provides a set of higher-level lock-free atomic
operations.
Currently, the only two operations are
gimp_atomic_slist_push_head() and gimp_atomic_slist_pop_head(),
which atomically push/pop the first element of a GSList.
Code cleanup.
Improve function descriptions.
Improve function precondition checks.
Make sure the main thread is properly synced with the async thread
before calling the completion callbacks in the idle function.
Guarantee that all callbacks are called in FIFO order, even
callbacks added during the execution of other callbacks.
It is not obvious that you have to hit Enter to validate the first step
of Foreground Selection tool, i.e. the rough free selection. Adding this
information in status message.
Since Enter would only work once the free selection is closed or that
you have at least 3 points (then Enter closes the selection for you), I
also add gimp_free_select_tool_get_n_points() so that we can know how
many points were created from the Foreground Select tool, and only
update the status message when relevant.
In GimpHistogramView, connect the view to the bg-histogram's
"notify" signal, and update the view in response. Previously, we
only updated the view in response to the main histogram's "notify"
signal.
The curves tool only uses the bg-histogram, and after the switch to
asynchronous histogram calculation, in commit
49382e53d5, it failed to update the
histogram view after the calculation was complete.
In GimpCurvesTool, calculate the histogram of the target drawable
asynchronously, rather than synchronously, to avoid blocking the UI
while the histogram is calculated.
In GimpLevelsTool, calculate the histogram of the target drawable
asynchronously, rather than synchronously, to avoid blocking the UI
while the histogram is calculated.
In GimpThresholdTool, calculate the histogram of the target
drawable asynchronously, rather than synchronously, to avoid
blocking the UI while the histogram is calculated.
Additionally, fix the initial "low" threshold value for > 8bpc
images (127/255 => 0.5).
In GimpHistogramEditor, calculate the histogram of the active
drawable asynchronously, rather than synchronously, to avoid
blocking the UI (and the execution of PDB calls) while the
histogram is calculated. For large images, this can notably
improve responsiveness, as well as plug-in execution speed, while
the histogram dialog is mapped.
... which is similar to gimp_drawable_calculate_histogram(),
calculating the histogram asynchronously on a separate thread.
Note that when calculating the histogram of the drawable's source
node, the node is rendered synchronously on the main thread (if
necessary), and the histogram of the result is calculated
asynchronously on a separate thread.
... which runs a user-provided function asynchronously, returning a
corresponding GimpAsync object. This can be used to execute code
off the main thread, using the GimpAsync object to synchronize as
necessary.
Note that while the code allows for running multiple asynchronous
functions in parallel in a thread pool, we currently limit the pool
to a single thread, queueing overlapping async function, since we
have no use for parallel asynchronous functions at the moment.
GimpAsync represents an asynchronous task, running without blocking
the main thread. It provides functions that allow waiting for
completion, queueing completion callbacks, and requesting
calcelation. See the code for more details.
The interface and the implementation are intentionally limited for
the time being, to keep things simple, and are geared toward
asynchronous tasks executed on a separate thread (see the next
commit). The public interface is relatively general, however, and
we may extend the implementation to support other kinds of tasks at
some point, who knows...
To avoid an infinite loop, gimp_item_linked_is_locked() was temporarily
unlinking items before calling gimp_item_is_position_locked(). This
worked only based on gimp_item_real_is_position_locked() code which
called gimp_item_linked_is_locked() only when it was linked. It did not
take into account the fact that it was an abstract method which could
have other implementations. In particular the group layer implementation
would call in turn gimp_item_is_position_locked() on each child layer.
Basically temporarily unsetting the link was anyway a very ugly hack.
The point is simply that we are only interested by the value of the
`lock_position` flag for this item, without further "intelligence". For
this, use gimp_item_get_lock_position() instead.
Displays can be opened multiple times, which caused the device manager
to try to add their devices multiple times (which gets prevented with
warnings), and then remove the devices prematurely when the
multiple-opened display gets closed the first time (which is even
worse).
Add a simple hash that keeps track of how often displays are open, and
only add/remove their devices on first open and last close.
This actually happened with gtk-inspector on the gtk3-port branch, but
there is no reason this can't also happen in stable.
... directory in the configuration folder.
This subfolder should have been created already. Just in case it is not
(for any reason), just recreate it rather than popping up an error.
In the gradient-tool editor, when responding to an endpoint size-
entry "changed" signal, make sure there is a selected handle, and
bail otherwise. We can receive a "changed" signal without a
selected handle, if the endpoint is deselected while a change to
the size-entry's value is in progress, causing the the tool GUI to
be unmapped, and the changed value to be committed.
When in anti-erase mode, always return TRUE, since it's only
effective when the drawable has an alpha channel.
Also, remove an unnecessary #include in gimp_ink_tool.c.
... closing one of them crashes GIMP
GimpSymmetry keeps a strong reference to the drawable passed to
gimp_symmetry_set_origin() until the next call to set_origin(), or
until it's destroyed. This can unnecessarily extend the lifetime
of the drawable. In particular, it can extend the lifetime of a
floating selection past the destruction of the image mask, during
image destruction, which results in a NULL mask pointer in
gimp_layer_invalidate_boundary(), called when detaching the
floating selection as part of its destructor.
Add gimp_symmetry_clear_origin(), which clears the origin set using
gimp_symmetry_set_origin(), dropping the reference to the drawable,
and call it in gimp_paint_core_paint() after painting. This avoids
extending the lifetime of the drawable, and fixes the bug.
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
Add a GimpPaintTool::is_alpha_only() virtual function, which
subclasses can override to indicate whether painting only affects
the alpha channel (assuming FALSE by default). Override the
function in Gimp{PaintBrush,Ink,Clone}Tool, returning TRUE when the
current paint mode only affects the alpha (as per
gimp_layer_mode_is_alpha_only(); see the previous commit,) and in
GimpEraserTool, returning TRUE when the target drawable has an
alpha channel.
When the function returns TRUE, and the target drawable doesn't
have an alpha channel, or the alpha channel is locked, show a BAD
cursor modifier, and raise an appropriate warning when attempting
to paint.
... which determines if a layer mode's blend function only affects
the alpha, maintaining the backdrop's color. This is currently
true only for ERASE, SPLIT, and ANTI_ERASE modes.
When the operation doesn't have an input pad, composite it over the
input using gimp:normal, instead of gegl:over, for consistency with
the rest of our compositing code (although the result should be the
same).
... drifts/sharpens when applying additional gradients
In GimpDrawableFilter, don't use gegl:over for operations without
an input pad, since this only works if the filter's mode is
REPLACE. If the filter's mode is different, in particular, if it's
NORMAL, we end up compositing the operation's output against the
input twice: once in gegl:over, and again in the filter's
applicator. Notably, this happens for the gradient tool.
Instead, revert commit 5b80d3d3be
(with some additions to avoid constructing unnecessary nodes when
the operation has no input) and simply change the applicator's mode
to NORMAL if the oepration doesn't have an input, and the filter's
mode is REPLACE.
so plug-ins cannot thaw what they haven't frozen, and the code
can clean up frozen stuff left behind by crashed or broken plug-ins.
Also redo the cleanup code so it only keeps track of the undo group
counts and freeze counts of what *this* GimpPlugInProcFrame did
itself. That should make it even stricter against broken code that
could mess up internals.
Blend them on top of the source buffer using gegl:over like
GimpDrawableFilter does interactively. Fixes "Repeat Last" and
probably some other stuff for source OPs.
gimp_histogram_view_draw_spike(): we were shifting the bg_histogram to
the right by accidentially offsetting the 'i' variable, use a local
variable for the loop instead.
These procedures freeze/thaw the corresponding containers of the
image, allowing plug-ins that perform many changes affecting any of
these containers to suppress updates to the corresponding dialogs,
significantly improving performance.
... while the container is frozen
In GimpContainerView, do nothing in response to a
gimp_container_view_{select,activate,context}_item() call while the
view's container is frozen. While the container is frozen the view
is empty, and these functions can segfault.
It is not used anywhere anymore and can be replaced by the more powerful
gimp_stack_trace_print() (which can also allocate a string containing
the backtrace, hence is a proper replacement call).
g_alloca() is not very advisable, especially when it might be used to
allocate a big chunk of memory at once. It is better to allocate dynamic
memory with malloc(), or in particular with g_try_malloc() which won't
abort the program on failure.
This might be slightly slower (one of the advantages of memory on the
stack, though not even an absolute truth) but probably not by much, if
at all, and it's better to be safe anyway.
Still looking for possible crash case during gimp_font_list_load_names()
(cf. bug 795650). g_utf8_validate() segfaults if called with NULL.
Though looking at pango_font_description_to_string() implementation, it
doesn't look like it would ever return NULL. Yet it is worth
double-checking. We don't load font every second anyway.
Add more assertion checks (similar to commit d094ab7e56).
This is still not a fix per-se, but at least would make the code a bit
more robust. In particular FcObjectSetDestroy() could crash if somehow
FcObjectSetBuild() had returned a NULL pointer. And obviously
dereferencing a NULL fontset would crash as well.
Now if any of these happened, no fonts would be loaded. But at least
GIMP would not crash.
After the switch of random-seed properties from INT to UINT, their
upper bound results in a negative value when converted to a
gint32, causing a CRITICAL in the call to g_random_int_range().
Use g_random_double_range() instead, which has enough precision to
accurately represent all values in the range, and round the result.
Remove the log handlers registered in errors_init(), in
errors_exit(), and call errors_exit() before destroying the Gimp
instance, since the log handlers depend on it. This avoids
segfaulting if a message is logged after destroying the Gimp
instance.
In GimpTextTool, when starting the editor in response to a button
press, always set the text tool's image first, so that the style
editor picks the correct resolution for the text-size entry.
Currently the image is only set when clicking inside the active
drawable's bounds.
Some crash happens inside this function (cf. bug 795650) on Windows.
Because of very inaccurate trace on this OS, it is hard to determine the
exact issue. Let's at least add some basic check on function parameters.
This won't fix any core issue, but may make things a bit more robust and
bugs easier to detect.
As proposed on IRC. This will allow people to debug their fonts (for
instance when there are permission issues or whatnot) by knowing the
list of problematic fonts in an error dialog at startup (and not only on
terminal).
This is for Windows where we apparently need to call
g_win32_locale_filename_from_utf8() before feeding the path to
FcConfigAppFontAddFile().
Unfortunately as we discovered earlier (cf. commit ba06a0fe86), this
can sometimes return NULL. So we absolutely need to check for the path
not being NULL first.
This GError will either specify the font which failed to load (if
unique) or a vague message about fonts which fail to load.
Unfortunately right now, this message also goes to terminal because the
GUI is not ready yet.
Do not use FcConfigAppFontAddDir() because it seems to be half-loading
some fonts, even when they are not actually readable. On the other hand,
FcConfigAppFontAddFile() properly fails and does not leave the font list
in unstable state.
It doesn't look like it is actually much of a problem, but anyway it's
better to have non-absolute paths in config files when possible.
Thanks to jtojnar on IRC for reporting these (and MyPaint brush paths
from my previous commit).
Absolute paths not to be used in $XDG_CONFIG/GIMP/{version}/tags.xml.
These are actually only an identifier, and not used as a path at all
anyway. Moreover MyPaint brushes even generate checksum (which allows
to remap the GimpData appropriately even if the paths are changing).
But anyway it's better not to have absolute paths when we can prevent
so.
gimp_rectangle_select_tool_cursor_update(): always set a cursor and
cursor modifier even if no GimpToolRectangle widget exists, so we are
not stuck with the last set cursor after committing or halting the
tool.
Symmetric conical gradients only span half a revolution (unlike
assymetric ones, which span an entire revolution), and therefore
require only half the cache size.
Add a crop node to the GimpDrawableFilter graph, applied after the
filter's output, cropping the output to the filter area (the same
area used for the input crop node). If we fail to do this, filters
whose op's bounding box is bigger than the input region can affect
areas outside the drawable, when the filter is rendered as part of
the image graph (in contrast to being comitted). This is
particularly relevant to source ops, that may have an infinite
bounding box.
We probably didn't notice this until now, since before the recent
GimpProjection update-area changes, only the drawable's area would
get invalidated in response to changes in the filter, so regions
outside the drawable wouldn't normally get rendered. However, this
could still have been triggered by causing regions outside the
drawable to be invalidated by other means.
Add gimp_drawable_gradient_adjust_coords(), which adjusts the
gradient segment coords according to the gradient type, so that, in
cases where the gradient span is unrelated to the segment length,
the gradient cache (in GimpOperationGradient) is big enough not to
produce banding. Use the new function in gimp_drawable_gradient()
and in the gradient tool, instead of duplicating the logic.
Move the shapreburst coordinate-adjustment logic to the new
function, and add appropriate logic for conical gradients.
Remove the code that avoids using the gradient cache for conical
gradients from GimpOperationGradient.
Undo the part of commit fa9a4108c3
that moved cache generation from process() to prepare(). prepare()
is called after each property change, in order to calculate the
op's bounding box for invalidation. Since we only need the cache
for actual processing, generating it in process() avoids that
overhead.
In the various types of fill operations, and in fade operations,
use the paint composite-mode of the current paint mode, which is
the composite mode we use during painting, instead of AUTO, which
results in the default mode we use for layer compositing. This
effectively means that filling using any non-legacy, non-
subtractive mode can paint over transparent areas, rather than
being limited to nontransparent areas.
Invalidate the gradient cache while setting relevant properties,
and validate it, reconstructing if necessary, during prepare(),
rather than process(), to avoid the need to use a mutex.
Make sure the cache has at least two elements, corresponding to
the initial and final colors of the gradient, since both colors
might be needed, and to avoid division by zero.
Avoid using a cache if its necessary size is too big, or if the
gradient type is conical, since the necessary cache size for
conical gradients is unrelated to the gradient line length.
Improve index rounding during cache lookup.
Lots of indentation fixes.
When merging a pass-through group, change its mode to NORMAL first,
to avoid a critical when duplicating the group as a regular layer.
Preserve the group's blend/composite space/mode while changing its
mode (note that only the composite space currently matters, since
the other parmaeters are immutable for pass-through groups.)
In gimp_text_tool_connect(), when auto-removing empty text layers upon
text layer or tool change, make sure we don't try to remove a layer
that has already been removed, which can happen if this function is
reached *because* somehow the layer was removed externally (e.g. by
the user in the layers dialog).
We were only able to translate selections and layers (bot not channels
and paths) via the PDB, this new procedure fixes that. Deprecation of
old API and some more transform consistency to follow...
it used to be "text" which is almost always too extreme; use "text_aa"
instead which is half way between "text" and "base" and always gives a
reasonable contrast.
... it doesn't exist.
The tmp/ dir in the config folder should already be created by GIMP, but
just in case it is not there, try and create it, since all code calling
these assumes that it exists.
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
In gimp_image_reorder_item(), call gimp_item_start/end_move()
before/after reordering the item (and use an undo group, so that
the resulting undo actions are grouped together with the reordering
undo action,) so that if the item is a child of a group layer, and
reordering moves it out of the group in a way that causes the
group's mask to be resized, the mask will be properly restored when
undoing the operation.
After Alexandre Prokoudine's insistent demand! :-)
I am still not sure how wise this is, since this should be really
considered a "developer-only" option. Basically these tools are really
too buggy and unstable and we should not shine too much light on these.
The counter-argument is that doing so will favor the bitrot.
Well ok. At least let's add a big warning message at the top of the
Playground page, to make it very clear (if that were not already the
case) that basically this is not to be considered a secret feature, but
really more a "we are looking for contributors" option.
In the gimp-channel-combine-masks PDB wrapper, only push an undo step
if the modified channel is attached to an image. It's a completely
reasonable use case to combine unattached channels.
... when using default aspect ratio
The call to
gimp_{crop,rectangle_select}_tool_update_option_defaults() when
starting the crop/rectangle-select tools seems to no longer be
necessary, while it overrides user modification to the default
ratio's landscape/portrait orinetation (which only really matters
for the crop tool, since the rectangle-select tools' default ratio
is 1:1). Fix this by simply removing the call.
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
Commit ddfc7715cb changed the
airbrush periodic stamp behavior, so that instead of using the main
brush, it issued a full MOTION event, potentially using a different
brush when using a GIH brush.
Fix this, by renaming the "timeout" signal of GimpAirbrush to
"stamp", and by adding a new gimp_airbrush_stamp() function, which
should be used for painting the periodic airbrush dab in response,
instead of calling gimp_paint_core_paint() directly, and which
calls gimp_airbrush_paint() instead, as the old code did.
In order to call this function from the paint thread, we replace
the various gimp_paint_tool_paint_core_foo() functions, introduced
in the above commit, with a generic gimp_paint_tool_paint_push()
function, which takes a callback (and a data pointer) to run on the
paint thread, and queues it for execution (when not using the paint
thread, the function is called directly from the calling thread.)
...(Pixel, Position and Size, Alpha Channel) are enabled.
gimp_edit_selection_tool_translate(): add checks for locks and bail
out with a message if the item is NULL or locked.
gimp_move_tool_button_press(): refactor NULL and lock checks to look
more like the new code added above, and also check "lock-content" of
channels and masks: moving them changes their pixels.
GimpAirbrush currently performs painting and flushes the image on
its own during the airbrush timeout. This is unsafe w.r.t. the
paint thread, since the timeout is run on the main thread, while
paint commands should run on the paint thread.
Add a "timeout" signal to GimpAirbrush, and simply emit this signal
during the airbrush timeout, rather than actually painting.
Connect to this signal in GimpAirbrushTool, and use
gimppaintool-paint to perform the actual painting, in a thread-safe
manner (see the previous commit.)
We'd like subclasses of GimpPaintTool to be able to issue paint
commands to the tool's paint-core (in particular, see the next
commit.) Since paint commands should be executed on the paint
thread, the subclasses must not call the paint-core functions
directly, but should rather let gimppainttool-paint issue the
commands on their behalf.
Reorgainze gimppainttool-paint to make it usable for this purpose
by subclasses. In particular, add
gimp_paint_tool_paint_core_paint() and
gimp_paint_tool_paint_core_interpolate(), which call the
corresponding paint-core functions on the paint thread.
Additionally, rename the {start,end,flush}_paint() virtual
functions of GimpPaintTool to paint_{start,end,flush}(), and rename
gimp_paint_tool_is_painting() to gimp_paint_tool_paint_is_active(),
so that all the gimppainttool-paint-related stuff are grouped under
the same namespace.
Don't unconditionally overwrite all the proc's description, author
etc. Instead, try to preserve them and append the "Deprecated" notes
to the help texts and generated comments.
Only affects one procedure because we killed the meta info of all
other deprecated procs so far, but now we don't have to do that any
longer.
Add new PDB group "drawable_edit" which has all procedures from the
"edit" group which are not cut/copy/paste.
The new group's procedures don't have opacity, paint_mode
etc. arguments but take them from the context instead. Unlike the old
gimp-edit-fill, gimp-drawable-edit-fill now uses the context's opacity
and paint_mode.
The new gimp-drawable-edit-gradient-fill procedure uses even more
context properties which are also newly added with this commit
(gradient_color_space, gradient_repeat_mode, gradient_reverse).
And some cleanup in context.pdb.
This is still WIP, nothing in the edit group is depcreated yet.
Rename gimpblendtool{.c,-editor.{c,h}} to
gimpgradientool{.c,-editor.{c,h}}. Note that this commit only
renames the files; the actual changes are done in the next commit,
so that git doesn't consider them new files.
Rename gimpdrawable-blend.h to gimpdrawable-gradient.h. Note that
this commit only renames the file; the actual changes are done in
the next commit, so that git doesn't consider this a new file.
Partially revert commits 4f2e078ccb
and b0beb0197a, since the changes
they introduced to some of the renamed files were big enough for
git to consider them entirely new files, hence we lost their
history. The next few commits fix this.
This commit also partially or entirely undoes followup commits
5f6dfc7617,
c3f98cccbd,
6b0f5136e0,
and 3736bfd189, which will be
restored by the next few commits as well.
The upper text will be centered on the top quarter of the bottom quarter
of the splash image, whereas the bottom text will be centered on the
bottom quarter of the bottom quarter of the splash (unless the splash is
too small, in which case the double of the layout pixel extents will be
used). Basically don't use absolute pixel values anymore for
positionning. This should all be done relatively since there are
nowadays all kind of display size (and positionning the text 6 pixels to
the bottom, as it was done, may be ok on low density displays, yet will
look ugly on high density screens).
Also write this down in the splash requirements in the release howto so
that splash designers are aware that the bottom quarter of their image
will have to be adapted for printing text.
In GimpBrushTool, remember the settings used for the last cached
brush boundary, and avoid creating a new copy if the settings
didn't change. This should lower the overhead of
gimp_brush_tool_flush_paint() when not using dynamics.
Using CIE Lab yields gradients that more closely resemble the perceptual
gradients but without the gamma based blending problems of linear-RGB / CIE
XYZ.
Commit f5cb1fed85, which performed
brush outline generation in GimpPaintTool in synchrony with the
paint thread, wasn't enough, since GimpSourceTool could still call
gimp_brush_tool_create_outline() directly during its
GimpDrawTool::draw() method, leading to the same race condition
when executed concurrently with the paint thread.
Partially revert the above commit, so that outline generation is
handled as before, as far as GimpPaintTool is concenered. Instead,
add GimpPaintTool::{start,end,flush}_paint() virtual functions; the
first two are called when starting/ending painting using the paint
thread, while the third is called during the display-update
timeout, while the main thread and the paint thread are
synchronized. This allows subclasses to perform non-thread-safe
actions while the threads are synchronized.
Override these functions in GimpBrushTool, and cache the brush
boundary in the flush() function. Use the cached boundary in
gimp_brush_tool_create_outline() while painting, to avoid the above
race condition, both when this function is called through
GimpPaintTool, and through GimpSourceTool.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
This includes migrating properly any custom shortcut (menurc), as well
as a few strings in tool-presets/, and finally "gimp-blend-tool" in
contextrc and devicerc.
File toolrc also has some occurrences, but we are already skipping it
anyway, same as whatever is under tool-options/.
Hopefully I missed nothing.
First WIP commit, adds:
- enum GimpGradientBlendColorSpace { RGB_PERCEPTUAL, RGB_LINEAR }
- linear blending mode for gradient segments
- tool options GUI for the blend and paint tools which use gradients
Don't flush the source pickable in gimp_source_core_motion(), as
this introduces a race condition between the paint thread and the
display-update timeout, when the source pickable is the image
containing the target drawable.
Flushing the source pickable shouldn't be currently necessary, and
either way, should happen during initialization.
Most expected behavior in normal transform is to see the preview,
whereas you usually don't want to see it in corrective mode. In 2.8
actually, it seems like it was not even possible to see the image
preview in corrective mode.
So let's set "show-preview" to these defaults when "direction" property
is updated. It is still possible to change it manually for any specific
use cases (i.e. you can hide the preview in normal transform, and
oppositely you can show it in corrective transform), but at least now
defaults are sane.
... or during rotation.
If checked before rotation, it works as expected, i.e. one sees only the
original or the rotated image.
While rotation is in progress: if unchecked, one sees neither the
original nor the image preview; if checked, one sees both original and
rotated preview.
Let's make the behavior consistent and only show exactly one version at
all time.
Invert zoom adjustment using the mouse or the keyboard when in
inverse mode. Take zoom factor into account when panning using the
keyboard. Fix motion cancelation.
... edges for MyPaint brush.
Adding the concept of "stateful" symmetry when a tool needs to make sure
of corresponding stroke numbers and orders while painting (i.e. stroke N
at time T+1 is the continuation of stroke N at time T). This is the case
for the MyPaint brushes and the ink tool.
GimpToolGyroscope is a tool widget providing canvas interaction for
3D rotation. The widget doesn't preset a UI, but rather
facilitates panning, rotation, and zoom, by dragging the canvas, or
using the keyboard.
Rotation is expressed using yaw/pitch/roll angles (performed in
this order). A zoom factor can be specified, which affects the
magnitude of the rotation per distance traveled. The widget can
operate in inverse mode, performing an inverse transformation.
Make sure a channel -> selection -> channel roundtrip never does any
gamma conversion.
In gimp_channel_duplicate(), make sure a created channel has the
right format, and the right data. Fixes selection -> channel.
When switching off quick mask, call gimp_item_to_selection() instead
if gimp_selection_load(), the latter was implementing a shortcut which
is now wrong.
Remove gimp_selection_load() which is now unused.
Unrelated: also remove gimp_selection_save(), it was an obvious
3-liner used only twice.
In GimpPaintTool, brush outline generation took place during
gimp_paint_tool_draw() even while painting. This function is run
concurrently with the paint thread. When using dynamics, this
introduced a race conidition between updating the brush mask in the
paint thread, and updating the brush boundary in the main thread.
Move brush outline generation during painting to
gimppainttool-paint.c, and perform it in the display-update
timeout, while the main thread and the paint thread are
synchronized.
After last commit, all paint tools work correctly with a separate
paint thread, so we can remove the option for specific paint tools
to opt out. Particularly, GimpMybrushTool now uses a separate
paint thread too.
Note that the separate paint thread can still be disabled through
the GIMP_NO_PAINT_THREAD environment variable.
Reorganize/clean up gimppainttool-paint. In particular, move all
paint-core interaction during painting to gimppainttool-paint.c, so
that we can have more control over what's going on; specifically,
enter the drawable into paint mode *before* starting the paint
core, so that it picks up the correct buffer. This fixes painting
with the paint thread using GimpApplicator, and enables us to use
the paint thread with GimpMybrushTool.
This function is unsafe during signal handling. And in any case, when
printing to stderr, I don't think we need to convert to UTF-8. Quite the
contrary, the system encoding may be more appropriate.
One additional fix for the gimp-channel-combine-masks procedure,
it needs both the combined *and* combined-to buffer in
gimp_gegl_mask_combine_buffer() to be treated specially.
Storing selections and layer masks as linear grayscale, but channels
as whatever-the-layers-are caused severe problems in images with
gamma-corrected layers: when combining channels with the selection,
they would go thorugh a gamma conversion before being combined, giving
unexpected results.
This commit changes all channels to always be linear, except in 8-bit
images, where they continue to be "Y' u8", for compatibility with old
XCF files, and because linear 8-bit can't really be used in
compositing (channels can be visible too).
To fix channel -> selection combinations also for these images, add a
small hack to gimp_gegl_mask_combine_buffer() which makes sure the
to-be-combined channel's pixels are always read as-is, without any
gamma conversion. After changing channels to linear, this makes no
difference except in the 8-bit images where we need this hack.
Add gimppainttool-paint.[ch], which takes care of painting during
motion events in GimpPaintTool. Perform the actual painting in a
separate thread, so that display updates, which can have a
significant synchronization overhead, don't stall painting.
Allow specific paint tools to opt-out of a separate paint thread,
and avoid it in GimpMybrushTool, since it doesn't seem to work.
The separate paint thread can be explicitly disabled by setting the
GIMP_NO_PAINT_THREAD environment variable.
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
Align rectangles added to the display paint area, in
gimp_display_paint_area(), to a coarse grid, to reduce the
complexity of ther overall area. This is similar to commit
49285463e6, however the alignment
happens in display space, instead of image space.
Last commit caused -xobjective-c to be passed during linking on
Mac, causing object files to be treated as source files. Add a
-xnone flag to AM_LDFLAGS, canceling the effect of -xobjective-c.
Additinally, add a -xobjective-c++ flag to AM_CXXFLAGS, so that we
can use Objective-C in C++ files on Mac, if we ever need to.
On Mac, pass -xobjective-c to the compiler through AM_CFLAGS, not
AM_CPPFLAGS, so that it's only used for C sources, and not C++
sources. In the latter case, it clashes with the -std=... flag,
spewing an error. Thanks, Partha :)
Statusbar progress updates that update the progress bar are
relatively expensive, slowing down operations that report progress
frequently. Only update the progress bar if a certain amount of
time has passed since the last update, to counter that.
In gimp_gegl_convert_color_profile(), when src/dest_rect is NULL,
use the extents of src/dest_buffer, instead of passing a NULL area
to gimp_parallel_distribute_area(), which results in a CRITICAL.
Additionally, only report progress on the main thread.
gimp-templates.c:143:15: warning: ‘strncpy’ output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation]
strncpy (dpi, "ppi", 3);
^~~~~~~~~~~~~~~~~~~~~~~
Need to check if we must override PixbufStyle's draw_layout() after
each theme change, not only at the beginning of themes_init(), so it
works also when the the pixbuf engine was not already loaded at
startup.
Commit cb239e60f6 introduced
artifacts when using the smudge tool with multithreads. Fix this
(caused by a wrong offset passed to an iterator) plus indentation
fixes.
Move gimp_brush_core_{subsample,pressurize,solidify}_mask() to a
separate gimpbrushcore-loops.cc file, so that they can be C++-ified
independently from the rest of the code. The next commit
parallelizes them.
The next commit is going to parallelize gimpbrush-transform using
the gimp_parallel_distribute_foo() functions. To spare us a lot of
boilerplate code, we're going to use C++ lambdas as callback
arguments to these functions.
This commit does the initial conversion of gimpbrush-transform.c to
C++, renaming it to gimpbrush-transform.cc. We do this in a
separate commit, so that the changes are small enough for git to
register this as a renamed file, rather than a new file, so that we
don't lose the file's history.
Add gimp-parallel.[cc,h], which provides a set of parallel
algorithms.
These currently include:
- gimp_parallel_distribute(): Calls a callback function in
parallel on multiple threads, passing it the current thread
index, and the total number of threads. Allows specifying the
maximal number of threads used.
- gimp_parallel_distribute_range(): Splits a range of integers
between multiple threads, passing the sub-range to a callback
function. Allows specifying the minimal sub-range size.
- gimp_parallel_distribute_area(): Splits a rectangular area
between multiple threads, passing the sub-area to a callback
function. Allows specifying the minimal sub-area.
The callback function is passed using an appropriately-typed
function pointer, and a user-data pointer. Additionally, when used
in a C++ file, each of the above functions has an overloaded
template version, taking the callback through a generic parameter,
without a user-data pointer, which allows using function objects.
Similar to commit 845eb522b6, I had a CRITICAL which happened on a
device_changed, triggering gimp_display_shell_update_focus(), this time
in focus in.
Remove the connect_after() hack from GimpImageWindow again and instead
add gimp_display_shell_canvas_realize_after() and restore the configured
ruler visibility there. Should work for all cases now.
Commit fd6d4931c8 accidentally
introduced a bug that caused Wilber's eyes to misbehave. This
commit is an attempt to fix this issue. Unfortunately, it seems
like the bug can still be triggered through a certain sequence of
actions...
Add "ellipsize" property to GimpColorFrame and set it to
PANGO_ELLIPSIZE_END in the the pointer information dockable.
Better cut off long numbers than make them expand the dock.
Use the recently-added gegl_tile_handler_damage_rect() function
during GimpTileHandlerValidate invalidation, instead of manually
voiding the tile pyramid. This function avoids voiding mipmapped
tiles entirely when only a subarea of the tile needs to be redrawn.
See GEGL commit 3210f4ffc3c569a2acd9483811cb141070112bc6.
gimp_image_window_constructed(): connect_after to the notebook's
"switch-page" signal so gimp_display_shell_appearance_update() is
called after gimp_display_shell_canvas_realize(). Just another hack
to fix the hack...
If variables are edited directly, in some cases, the GUI and the
symmetries may end up out-of-sync. The variable can only be edited
through property setting.
This value is actually used as a special value when removing a guide to
get rid of a symmetry, in particular it is set in the guides' callback
gimp_mirror_guide_removed_cb() for "removed" signal.
If not setting to 0, when adding back a symmetry, it starts with weird
low or high values near to border (whereas when set to 0, it is reset to
default position afterwards).
... parasite.
Not sure if that should be considered a bug. On one hand, it should
because that's core code. On the other hand, symmetry saving currently
uses parasites, which is a feature which can also be used by people
randomly. So "theoretically", there could be any data in a parasite and
we should not assume specific format.
Anyway still keep the error message but just print to standard error
output instead. Also print a bit more details (parasite name and
contents) as it would help for debugging when such a case were to occur.
Care for future changes of symmetries, by adding a version property. For
now, all symmetries are at version 0, and no real check is done. If any
symmetry bumps its settings in the future, it will have to override also
update_version() to change settings properly if necessary, according to
any new behavior.