Use the "activate-link" signal instead of "clicked" on tip links, so
that we can stop signal propagation.
Otherwise it opens "http://docs.gimp.org/" everytime.
This new function is available from the released dev version 3.11.4. But
we don't want to require GTK+ master for the gtk3-port branch, so I
leave the old hack in a GTK_CHECK_VERSION() macro, to be removed later
when we update GTK+ required version.
This doesn't look as it should at all, but is entirely useable and
undeprecated, and I really want to keep the diff to master small. Will
fix after we switch to GTK+ 3.0.
- add new "device from event" apparatus that works on GTK+ 3.x
- fix the active device selection mechanism
- use the new device grabbing functions
- make sure we don't process events while we have a grab on
another device
- compensate for some really obscure (and likely broken) behavior
of XI2, it feels like we are the first real users...
for the time being, use gdk_window_get_device_position() instead of
gdk_device_get_axis() for X and Y, which gets rid of subpixel
coordinates, but at least returns values != 0. Also, don't ask
keyboard devices for coordinates.
Therefore, use the new get_area() functions to figure where to draw
from instead of the removed get_window() ones. Also adjust the tag
popup positioning code accordingly.
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.