We use US English which uses behavior. So we replace all occurrences of
behaviour.
Most notable is File Open behavior in preferences. Besides that several
mentions in function documentation and a few in comments.
Replaces "Solid Colors" option in Fill Path with Foreground/Background
Colors options. This allows users to fill with either, rather than
having to switch the foreground color each time.
GIMP_CONTEXT_PROP_MASK_BACKGROUND was added to the fill and stroke
contexts to allow the background color to be recognized.
In places where Solid Color was used as a default, Foreground Color is
now used instead.
This patch does the following things:
- An option "Merge menu and title bar" (this is hopefully more understandable
than calling it "Client-side decoration" or again "header bar") is added in
Preferences > Image Windows. This option triggers the restart warning.
Moreover when checked a small warning message will tell that in some cases, it
may not work (there are feedbacks of people having 2 title bars when using GTK
applications using CSD).
- For the reason evoked above (sometimes 2 title bars) and also because the CSD
concept seem really to divide people a lot (some love this as much as others
hate this), this new option "custom-title-bar" on GimpGuiConfig is FALSE by
default.
- When the option is checked, the image windows will use a GTK header bar
containing the menu, the window title (image name and information) as well as
the usual minimize/maximize/close buttons per your OS conventions.
- Since the header bar is set to be hidden when maximizing, if you checked "Show
menubar" for the "Default Appearance in Fullscreen Mode" in Preferences >
Image Windows > Appearance, the menu will be moved to its "old style"
position, i.e. above the canvas. This makes the menu possibly visible (if
relevant option is checked) even in fullscreen mode.
- I tweaked the Default theme to show the header bar with minimal height,
because I find GTK default theme's headerbar height unreasonably high
(especially if the point of the header bar is to save screen space). I am
unsure if this was the right move though, because maybe the default theme
should not do such choices (maybe this should go in the Compact theme?).
I don't see a reason why the quick mask menu was sharing the same
manager as the image menu (the main top menu and on-canvas). This was
why it was receiving all notifications to create menu items on <Image>,
as registered by plug-ins.
Giving it its dedicated manager makes sure this doesn't happen.
Use g_idle_add() instead of g_timeout_add(300ms), which makes
it respond instantly, while still keeping the actual zoom
call out of the slider callback.
Fixes#9500
By doing `gimp_display_shell_pointer_grab()`, we actually prevent events
from a tablet coming through. There doesn't seem to be a reason to use
it and it's not regressing in functionality either, so let's just remove
it.
Fixes: https://gitlab.gnome.org/GNOME/gimp/-/issues/8016
Note that it will only work for a model attached to a GimpMenu. In particular,
it won't work for the menu bar set to a GtkApplication with gtk_application_set_menubar().
In other words, it won't work on macOS where we let the OS handle the menu.
Use this for the "View > Zoom" and "View > Flip & Rotate" submenus which used to
display the zoom level and rotation angle. This regression is now fixed.
Since we now generate actions for GEGL ops, we might as well generate menu items
for these too.
What I did:
- Move the "GEGL Operation…" tool (generic dialog with a drop-down list of all
non-ignored GEGL ops) to Tools menu.
- Create a "GEGL Operations" submenu in Filters > Generic.
- Move "GEGL Graph" to the top of this new submenu.
- Generate a new menu item for each generated action tied to a GEGL plug-in,
alphabetically sorted.
Though the GEGL Operation tool is still useful as a generic dialog, let's
generate also per-operation (the ones not ignored and not already special-cased
in the rest of the GUI) tools and actions.
These "tools" are mostly hidden (e.g. not selectable in toolbox where it would
be a bit useless as they would show with the generic GEGL icon or none), but
they can be searched with the action search, shortcuts can be assigned and they
can be added to menus.
In particular on macOS, we want to show some default common actions (see
comments in !837) but gtk_application_prefers_app_menu() docs says that it will
always return FALSE on this OS. So we ignore this call on macOS.
Pre-GIMP-3.0 code logics would re-allocate several GimpMenuFactory or
GimpUIManager for no good reason. While it was still working with old GtkAction
code, with our new GAction-based code, we were ending up overriding an action
with a new version of the same action, while keeping reference to old actions.
This made for discrepancies of the enabled or visible state of actions.
The new code keeps singleton of some objects and references to already
registered GimpUIManager or GimpActionGroups objects and make sure no actions
with the same name are created twice.
Testing the 2 code paths is otherwise extremely annoying. Let's just add an
environment variable allowing us to run one or the other implementation if the
variable is set.
Since GAction don't have labels or visibility, it is up to every application to
fill the GMenuModel with such infos. In my previous implementation, I was simply
handling these in GimpMenuShell subclasses (GimpMenu, GimpToolbar and
GimpMenuBar) since we need them for tooltip support (unavailable from GMenu).
Nevertheless there are cases where we want to use GTK API directly with a
GMenuModel, in particular with gtk_application_set_menubar(). This is necessary
to handle the macOS specific code path, where we don't want our usual menu bar.
This OS has its own display of a software menu bar, directly in the desktop GUI.
See !558 for some screenshots of this.
So this commit moves around some code away from GimpMenuShell subclasses into
the new GimpMenuModel class. Now we use this new class instead of simpler GMenu
objects. It handles syncing with GimpAction-s, auto-updating labels, visibility
and sensitivity, as well as adding custom items (plug-in actions, recently
opened files, opened images, etc.).
My last commit message was slightly wrong. I had one last special case to
handle: the ability to only create sub-GimpMenuShell (i.e. at a specific path
other than the root).
We are using this ability in particular for tool options submenus.
I only translated the undo menu into GtkBuilder's .ui format for now.
The only missing part is that the icon is now shown.
Note that in various parts, I don't rely anymore on a bogus menu action (i.e.
"undo-popup" action in this case) which does nothing but has an associated label
and icon. I simply add the label and icon as submenu attribute directly in the
.ui file, which is translatable and whose strings should be parsed by gettext.
Eventually I'll just get rid of all the various "*-popup" or "*-menu" bogus
actions.
This demonstrates a first version of our replacing menu, using GAction and
GMenuModel. I had to make our own subclass of GtkMenu to process the model (from
a .ui XML file) for the following reasons:
* gtk_menu_new_from_model() doesn't support tooltips, which is a feature we use
quite extensively in GIMP: with all our filters, being able to give a longer
description is often useful; moreover we use tooltips to give hints about why
a menu item is deactivated as well.
Unfortunately it looks like GTK doesn't consider this lack as a problem and
don't plan on adding tooltip support.
See: https://gitlab.gnome.org/GNOME/gtk/-/issues/785
* I won't to avoid copying action's label and icons in the .ui file. This only
duplicates strings and would be a source of issues each time we change
action's strings (we'd have to do it in 2 places, which someone will
inevitably forget).
Now it still has various issues:
* The syncing between actions and menu items need to be cleaned up. It's still
in early demo code.
* It uses directly some Gtk*Action code because GimpRadioAction and
GimpToggleAction are not directly related right now (only through their
parents).
* gtk_application_set_menubar() might still be necessary on macOS as I think
it's what enables the native menu system on this OS. It means that we'll have
to edit the menu model to add back the labels (as this function does not
extract these from the linked action since GAction has no label or icon
concept).
* Icons are not taken into account right now.
* I'll have to verify if GimpAction with proxy work (but my guess is that right
now, it won't).
* Action's active state is not synced with menu item active state right now.
* Various actions are inserted live, such as opened images, opened views,
recently opened images, and so on. This needs to be implemented back.
* Plug-ins need to be able to create their own menu item into this new menu.
* For all these various reasons, I'm keeping the old menu around, for the sake
of comparison, until the time the new one becomes feature-full.
Part of this commit is inspired by !558 and obsoletes this MR.
gimp_display_shell_render() writes to a GeglBuffer backed by allocated memory
(shell->profile_data). Unfortunately while converting prevision in
gimp_image_convert_precision(), we change the "precision" property (hence the
source format) first, hence end up trying to write data in a too small buffer.
This crash was hard to find as it was not showing up on my machine (though it
did produce rendering artifacts!), unless I built both GIMP and babl with
`b_sanitize=address`.
Note that an alternate fix was to make sure that the profile_data buffer is big
enough (by calling gimp_display_shell_profile_update() before rendering), but
anyway the image is in an inconsistent state while conversion is in progress:
whereas the `src_format` is the new one, the `src_profile` is still the old one
(and cannot be changed before we finish converting).
Moreover the render happen regularly on progress signals, once after each
converted drawable. So each of these rendering step happens in an inconsistent
state, with the wrong profile set, some of the drawables converted and others
not yet.
We could still render properly if each drawable's buffer used space-aware format
(thus allowing different drawables to use different profiles/spaces), but it
feels over-engineering the problem. It might be much better to ignore rendering
steps while converting the image precision. Moreover it would obviously make a
faster conversion.
See discussions in #9136 for this crash, which didn't have dedicated report
AFAIK.
(cherry picked from commit de25be9210)
Note: on the `master` branch, even with sanitized code, I don't get the crash.
Yet this change seems relevant enough that I'm adding it.
When the clipboard contains raw image data or single layers, it's the same as
the normal "Paste" (and "Paste In Place" respectively). These actions are useful
if you want to copy a bunch of layers and paste them "merged" into a single
layers (since now the copy-paste of multiple layers will create multiple
layers).
It is somehow similar to the "Copy Visible" action except that it works on
selected layers only and work at paste time, making the action more versatile.
When dropping a buffer, we just consider it like common data pasting, hence we
leave the GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING algorithm decide what type of
paste it will be.
Reviewer's message (Jehan): This was a work-in-progress by Niels, which
we only keep in this state because Lukas worked over it. I have rebased
and fix-amended many broken part of this commit, because various things
had been changed in these areas of code since this commit was initially
written.
Now that we bumped our meson requirement, meson is complaining about
several features now deprecated even in the minimum required meson
version:
s/meson.source_root/meson.project_source_root/ to fix:
> WARNING: Project targets '>=0.56.0' but uses feature deprecated since '0.56.0': meson.source_root. use meson.project_source_root() or meson.global_source_root() instead.
s/meson.build_root/meson.project_build_root/ to fix:
> WARNING: Project targets '>=0.56.0' but uses feature deprecated since '0.56.0': meson.build_root. use meson.project_build_root() or meson.global_build_root() instead.
Fixing using path() on xdg_email and python ExternalProgram variables:
> WARNING: Project targets '>=0.56.0' but uses feature deprecated since '0.55.0': ExternalProgram.path. use ExternalProgram.full_path() instead
s/get_pkgconfig_variable *(\([^)]*\))/get_variable(pkgconfig: \1)/ to
fix:
> WARNING: Project targets '>=0.56.0' but uses feature deprecated since '0.56.0': dependency.get_pkgconfig_variable. use dependency.get_variable(pkgconfig : ...) instead
If we released first the modifiers, then the pointer button during
scrolling, we could end up blocked on scrolling. This makes sure the
button release is the finale scroll unlock, allowing modifiers to be
only used for starting the scroll.
It also fixes activating custom actions, by storing the action
description from the initial modifiers at press time, not release time.
The GimpColorProfileComboBox widget requires the profile chooser dialog
to be explicitly constructed. It doesn't create it by itself.
I guess I hadn't tested clicking this "Select color profile from disk…"
combo item during review. I only selected visible profiles in the list!
This adds a Soft-Proofing pop-over menu when right-clicking the toggle
in GimpStatusBar. It lets users toggle proofing, using BPC and showing
out-of-gamut colors. It also lets users change the profile and
rendering intent.
Opacity and brush size are among the 2 most common tool options which
people might want to often change, though we should likely later add all
other common types of tool settings angle, aspect ratio, spacing, etc.
I am also unsure using the enum action is the right call because what it
does is just taking into account the distance from initial click to
compute an opacity. Instead it might be more interesting to increase or
decrease slowly or rapidly by going right or left from the initial
click. We'll see. But it's a first step.
The mouse controller had many limitations:
* It was not per-device.
* It was a long hard-coded list of events, which made its evolution
annoying and scrolling the list boring.
* It was starting at button 8, while the first buttons were supposed to
be hardcoded interactions. And it stopped at button 12, while some
device might have more buttons nowadays. See !386.
* The "Grab event" does not seem to work in many cases, according to
feedbacks.
The new GimpModifiersEditor will now handle any button (except the first
button, which is reserved for tools), you can even override or change
default canvas actions (panning, rotation, etc.). It should not be
limited with a max button number either (though I haven't tested with a
device really having a lot of buttons since I don't have any such device
but I did emulate huge button numbers on my stylus with xsetwacom and it
did work well; hopefully I'll get feedbacks). And now it can even run
custom actions.
So basically it should deprecate the mouse controller as the modifiers
editor can do everything the controller could, and more (unless I missed
anything).
Custom actions are basically any action (currently GtkAction) which can
be assigned a shortcut. Now they can also be assigned to an input device
button (with modifier or not).
* The relative brush size change was not implemented anyway. Maybe later.
* Also changing the defaults to GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE
which I think might be the most understandable size variant.
* Finally re-label "Rotate" to "Rotate View" as per Aryeom's feedback
because just "Rotate" is indeed confusing as it could mean several
different actions in GIMP.
Actually I am renaming GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE into
GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, which allows to set the
brush size on-canvas, starting from center to border.
The new GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE now sets the brush size
from one border to another.
Space: panning
Ctrl-space: zooming
Shift-space: rotating
Ctrl-shift-space: constrained rotating
Note that these are still hardcoded, unlike the actions through
modifiers + pointer buttons.
For now GimpModifiersManager returns the same modifiers as what was
previously hardcoded and we have no GUI yet to change the settings. But
the core of the new feature is in place.
This object's goal will be to manage customized modifiers per input
device button, which is why I add it to GimpDisplayConfig. It is in its
own new config file (`modifiersrc` in config dir) because it requires
GDK types access (well I could have done without, but it would have been
less semantic, hence not as good of an API). Anyway it is only useful
when running GIMP as GUI.
The GUI widget and the usage code to make this actually useful will come
in upcoming commits.
… new action_pixel_size of GimpMyBrushTool.
MyPaint brush tool clearly shows the limits of my trick to have some
enum actions work with absolute values whereas others work with
per-mille values between the property min and max.
Indeed firstly MyBrush's "radius" value is logarithmic and can be
negative. Since the enum trick relies on the fact that negative values
are the semantic enumerated constants, it's broken in such case. The
second issue is that while it was acceptable to use int size for most
paint tools (even though they were double), here radius only goes from
-2.0 to 6.0; so using int values only would leave us with jumping brush
sizes.
So now I create a proper double action which simply takes pixel size and
use this from the on-canvas brush size changing. No weird trick, no int
or sign limitations.
I also add a new optional action_pixel_size in GimpToolControl.
Note: I'm also updating a bit the logic for the MyPaint brush outline
function gimp_mybrush_tool_get_outline(). Indeed after skimming a bit
through mypaint-brush.c code in libmypaint, I am not sure at all we need
to use the offset_by_random like this. And really this shown outline
seems more indicative than anything else when I see the actual size
printed by the various brushes. Finally here it was counter-productive
as I needed to get easily the logarithmic radius from the pointer
interaction on canvas.
Until now, it was only stopiing when releasing right click, but it's
actually more accurate when releasing the Alt key first as the button is
on the mouse/stylus (so releasing it can provoke small hand moves,
especially visible with stylus, I think). Now it stops whatever is
released first.
I started from mitch's patch (though code changed so it was not working,
yet I ended up with quite a different direction).
Modified from original proposition in #498:
* Do not mix opacity and brush size in a same action, one on horizontal
movement, the other on vertical. The problem is that it's hard to stay
perfectly horizontal or vertical, so you nearly necessarily change one
while changing the other and this would be frustrating.
* Do not just use modifiers, but modifiers + right click. The logics is
that left (or whatever is the first button) click is for the tool
actions. The middle click for navigation (panning, rotation, and even
layer navigation now). Right click for now is only for menu. With this
change, let's use right click for various settings-related changes
too. Also we already have people complaining with things like canvas
rotation happening unexpectedly even though it requires button clicks.
Imagine an action just made of modifiers! Many people would hit these
by mistake all the time!
* Focus on brush size only for now. Instead of just calling the action
repetitively with the "SElECT_NEXT" action as proposed in the original
patch by mitch, let's compute the actual size between the press and
release. This would allow to have a real visual hint and also would
make it a lot more useful and meaningful to be an on-canvas change.
Say you want to reproduce a stroke size on canvas. You can click the
center and expand to retrieve approximately the size without computing
it in pixels.
Limitations and future work:
* This is a first draft and I still want to test if it works well with
the "lock brush to view" and with scale factor > 1.
* I want to associate this with work done for #7034 so that visual hint
still appear even when we have no visual hint set.
* I am not so fond of with the way we use enum actions which doesn't
really make satisfying logics (I hacked a bit over it, but it's
getting ugly). I'm considering creating int/double actions to really
set some values with exact numbers through actions.
* Right now we need to stop the right click first. I want to be able to
stop the brush sizing with releasing Alt too.
* It would be nice to make this all more customizable, which is why I
called internal variable "mod1_setting". The goal will be to have
other types of actions possibly. Also it could be deactivatable for
people really not liking these or hitting these by mistake (while not
needing these). Same for the navigation shorcuts.
* Similarly the right-click menu could be deactivatable or switched to
other actions conditionally (through Preferences). It is doubtful how
useful it is (compared to using the same menus on top of the GUI)
though I don't want to just delete the option because some people
would clearly be used to it.
* I think we should start breaking down the whole tool events code a bit
more, in particular the function gimp_display_shell_canvas_tool_events().
* For more settings, a small on-canvas GUI could be of interest where
you could customize various values through sliders and buttons, and
also where you could put your favorite brushes or dynamics or whatnot.
It's not replacing the more complete dockable but could be a nice
quick version for fast editing.
Adds a simulation_bpc and simulation_intent to GimpImage to allow
plug-ins to access it
for CMYK import/export.
Four pdb functions were added to enable this access:
image_get_simulation_bpc (), image_set_simulation_bpc (),
image_get_simulation_intent (), and image_set_simulation_intent ().
Next, it updates menu options and code to support GimpImage's
internal simulation intent and bpc.
New 'simulation-intent-changed' and 'simulation-bpc-changed signal
are emitted via
GimpColorManagedInterface so that relevant tools
(such as the
CYMK color picker, GimpColorFrame, and future pop-overs)
are aware of these changes.
Adds a soft-proof toggle button to GimpStatusBar. It's only active when
a simulation profile is set on the current image. It stays in sync with
the View menu soft-proofing option as well.
Generated *enums.c now have an additional stamp no-op header include
(see last 2 commits). Sync this change into the autotools generation
scripts to prevent back and forth useless generation of these files each
time we switch from one build system to another.
They are nearly the same as initially, except that now they include an
intermediate stamp header which will be generated by the build system.
The only 2 enums which don't need these includes (and are not versioned)
are libgimp/gimpenums.c and libgimpthumb/gimpthumb-enums.c.
Our meson build system was not properly building the enums.c file,
because they are versionned.
I did a similar trick as what I did for the pdbgen, which is that I used
a wrapper script around the existing perl script, which sets proper
options and generate a stamp file in the end (which is considered by
meson as the actual custom target, not the C file since it is generated
in the source dir).
The most important part is that the stamp file is a generated header
source (not just a random text file) which is **included** by the
generated C file. This is what will force meson to regenerate the C file
if the header is updated, **then** build using this new version, not use
an outdated versionned version (which would make for hard to diagnose
bugs), through the indirection of the intermediate stamp header.
See #4201.
See also: https://github.com/mesonbuild/meson/issues/10196#issuecomment-1080742592
These changes make it possible to build against homebrew for mac
libraries. Homebrew stores it's libraries in seperate folders and so
blanket includes were not working.
PYTHONPATH is not needed and interferes with homebrew build.
This removes rate limiting of ruler and statusbar updates which were
required to get acceptable performance on mac for drawing on the canvas.
This requires the latest changes on in Gtk 3.24 to be incorporated.
Adds a simulation_profile to GimpImage to allow plug-ins to access it
for CMYK import/export.
Two pdb functions were added to enable this access:
image_get_simulation_profile () and image_set_simulation_profile()
Next, it updates menu options and code to support GimpImage's
internal simulation profile. Menu items are moved from View to Image's
Color Management section.
New 'simulation-profile-changed' signal is emitted via
GimpColorManagedInterface so that relevant tools (such as the
CYMK color picker, GimpColorFrame, and future dockable
dialogue) are aware of these changes.
There was one case where horizontally and vertically were mixed up in a
call to gimp_display_shell_scale_image_stops_to_fit.
The more usual order of parameters is first horizontal and then vertical.
So, let's fix the actual functions that have the illogical order
of vertically, horizontally instead of fixing the one call.
This brings it in line with the order in other functions and makes it less
likely we mistakenly mess up the parameters.
Besides that gimp_display_shell_scale_image_stops_to_fit also was not
declared as a local function, so we add that too.
Reviewer (Jehan) note: cherry picked from MR !274. Still deciding
whether this will be pushed to gimp-2-10 branch too.
Fixed Conflicts from !274:
app/dialogs/preferences-dialog.c
app/display/gimpdisplayshell-draw.c
app/plug-in/gimppluginmanager-call.c
libgimp/gimp.c
libgimp/gimp.h
libgimpwidgets/gimppreviewarea.c
libgimpwidgets/gimppreviewarea.h
libgimpwidgets/gimpscrolledpreview.c
Remove `gimp_display_shell_keyboard_grab()` and ...ungrab(), as there
doesn't seem to be any good reason to grab the keyboard away from the
compositor. More annoyingly, in some systems it will pop up a dialog
on each first click whether the user is okay with inhibiting shortcuts.
Performing zoom and rotation at the same time is inconvenient because
most of the time the user will want either zoom or rotation. This can be
solved by recognizing a "significant enough" zoom or rotation change
initiated by the gesture recognizer and then ignoring the other gesture.
Adds the new configuration option "drag-zoom-speed" to adjust the rate
at which mouse movement can zoom the canvas, ranging from 25% to 300%
of the base rate and applying to both drag-to-zoom modes.
This option can be found in the preferences dialog as:
Image Windows -> Zoom & Resize Behavior -> Drag-to-zoom speed
Adds a new configuration option "drag-zoom-mode" to choose whether to
zoom by distance of movement (newly added) or by duration of movement
(previous behavior) when zooming via dragging the mouse, defaulting to
distance.
This option can be found in the preferences dialog as:
Image Windows -> Zoom & Resize Behavior -> Drag-to-zoom behavior
Changes the behavior of gimp_display_shell_scale_drag() to factor in
the distance dragged, rather than just scaling a flat +/- 10% for each
detected movement event. The factor by which to change the scaling is
also altered from 10% at each movement event, to 1% compounded for
each pixel of distance dragged.
This makes zooming via Ctrl + Middle Click or Ctrl + Spacebar behave
more consistently and less jittery versus the previous method, while
offering more fine grained control.
We take a step back from the original MR which was proposing the "single
dot" cursor as a new "Pointer mode" option. I was really unsure this was
the best solution, especially reading again the whole original report.
It means that now nearly all of the original patch has been rewritten
another way, but let's leave the contributor commit as a start point to
get to where we are, and as acknowledgement of the contribution.
The reporter was annoyed by the crosshair when none were requested and
probably mostly for painting tools only (at least examples were about
brush or pencil, etc.) while showing outline. It looks to me like the
real issue was maybe when we were showing the big crosshair when using
the 4-arc fallback outline, for instance when using a dynamics changing
size. If so, this main issue is already fixed by my commit 64dc26064b.
No need of a new option for this, especially if the option can be as
confusing as a barely visible dot-cursor (I can already imagine the bug
reports of people tweaking random preferences and unhappy because the
pointer became invisible, while they don't know how they did it).
Instead I would say that when people specifically uncheck both "Show
brush outline" and "Show pointer" options, showing a huge crosshair
feels quite counter-productive. This is where I think that our small
unobtrusive cursor (probably a better name than "Single dot" by the way,
as it's not a single dot anymore) might be of use, the ultimate case
when someone really want a cursor as inconspicuous as possible, while
still having a visible feedback of the pointer position (even with
display-tablets, parallax issues make such a visual feedback important
to target where one paints).
So let's try this first and see how it goes.
… cursor position label.
This should now resolve any weird jumping around of the cursor label,
hence the GUI. Of course, it could actually still happen when going
really off-canvas (though the max computation takes into account
reasonable off-canvas moving, which is totally possible, especially now
that we can view off-canvas so people can just work there and the GUI
should definitely not do weird stuff there as well).
This issue was not confirmed to happen on Linux and Windows, but was
making ugly label resizes on macOS by just moving the cursor on canvas
normally. See video in:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Ironically enough though, it started to happen even on Linux/X11, at
least, after commit 1baeffc913, which was the commit meant to fix this
on macOS!
This max size computation algorithm should work well enough for any
normal on-canvas usage, and even some off-canvas (yet close enough)
usage.
Note: this code only takes into account the pixel position case, for a
first implementation, which is why it's not pushed immediately in this
form.
… in specific case when there is already a toolbox.
Even if there is already a toolbox in single window mode (hence it needs
neither to be created nor raised, as there is a single window), we still
want to return the dockable widget which can be used for other things.
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea7022 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
Since we are now allowed to move groups (which is the same thing as
multi-selecting all its children and moving them), it makes no sense
that this lock is disabled.
This works the same way as "Lock pixels" in that a locked grouped also
forbid moving children. And there was already some logics so that you
can't move a layer group if one of it's children is locked. So this lock
really works both ways and is a bit special.
Finally I cleaned up a bit the multi-layer selection logics and
messaging, as well as which lock to blink (similar to the previous
commit) for the "Lock position" case.
In particular, if painting on a layer whose parent's pixels are locked,
we were blinking an empty lock spot, which is confusing. Now
gimp_item_is_content_locked() will also return the proper item (when
relevant, i.e. when returning TRUE) which is locked. It may or may not
the same item as passed in (it may also be a parent item in particular).
See discussion in !572, #7840 and #7690. Note that this was reported on
macOS where the consequences were pretty dire, but it actually also
happens on other platforms, at least on Linux too (as confirmed in X11
with the GTK Inspector set to show graphics updates; on Wayland this
debug option doesn't work, but I assume it is the same).
I am not perfectly happy with this change either, because it is based on
part of the API which has various deprecated parts (hence doesn't exist
anymore on the main dev tree, i.e. it might have to be reviewed in GTK4;
of course, it's unsure, maybe the whole resize propagation to parent
containers is just better handled there and the problem won't exist
anymore).
In any case, it is cleaner than the proposition for this part of the
problem in !572 which is problematic (patching GtkLabel with a new API
which won't trigger resize even when actually needed, hence which likely
won't ever get accepted upstream because it's not right).
This change reduces to 3.33 times a second, the updates to the
status bar coordinates widget.
This dramatically improves frame rate on macOS retina displays
because it reduces the frequency of full screen updates which
are triggered by this widget updating and are very slow.
This makes the statusbar refresh changes mac only where the
benefit will be felt keenly, rather than saddling all
platforms with the change.
This moves to standard fullscreen behavior for Gimp.
Added benefit is that it no longer requires gdkquartz-cocoa-access.h
which the Gtk team wish to stop supporting https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4303.
Bug 756178 also no longer manifests, cdc7542d46
so it is now safe to do.
Finally, removes dependency on objective c in the app/display directory.
I cleaned many remaining places where the concept of linked item still
survived.
On loading an XCF file with linked items, we are now going to create a
named sets for the linked items, allowing people to easily select these
back if the relation was still needed.
We don't remove gimp_item_get_linked() yet and in particular, we don't
save stored items into XCF files. This will come in an upcoming change.
Not sure why but adding a handler to the "expose-event" signal of
GimpDisplayShell (similarly to how we do it in master branch on "draw")
just didn't work. But it works on the already existing signal handling
on the canvas instead (which actually is not a bad deal, as we also
remove the coordinates translation so maybe we should test this on
`master` too).
Note: why we are backporting all this logics to gimp-2-10 is because
changes in macOS BigSur broke the selection's marching ants the same way
they broke on Wayland and it was confirmed this fix worked for BigSur as
well, at least on the dev builds.
It is unnecessary to backport for Wayland (because GIMP 2.10 is based on
GTK2 which anyway works only through XWayland, hence doesn't have the
issue), we do it only for macOS BigSur (and further). Well at least the
fix will hopefully work on the stable branch, because I cannot test
myself.
See issue #5952.
(cherry picked from commit 6be014fc59)
Cherry-pick note: it was initially only for gimp-2-10 but actually also
works fine on the GTK3 branch and fixes some selection coordinates issue
when rotating the canvas.
… an API that went private in GTK 3.
Note from reviewer (Jehan): this API became public again in commit
gtk@242b76a7, available since GTK 3.24.29. Before this, the function
(gdk_quartz_window_get_nswindow()) was actually still in the ABI, so we
could declare the function locally before using it. This is an ugly
workaround, but it works.
What we do is providing both solutions depending on GTK version, leaving
build warnings as constant reminders so that we remember to get rid of
the workaround when we bump minimum GTK requirement.
Cf. discussions in gtk#2452 and gimp!483.
Since it appeared with GLib 2.68.0, we could not change this until we
bumped the dependency which has only become possible a few days ago
(since Debian testing is our baseline for dependency bumps). Cf.
previous commit.
As this is a drop-in replacement (just a guint parameter changed to
gsize to avoid integer overflow), search-and-replace with:
> sed -i 's/g_memdup\>/g_memdup2/g' `grep -rIl 'g_memdup\>' *`
… followed by a few manual alignment tweaks when necessary.
This gets rid of the many deprecation warnings which we had lately when
building with a recent GLib version.
This started as yet another report of leak by Massimo. But really the
leak of the GdkPoint created by the function
gimp_display_shell_push_zoom_focus_pointer_pos() is not only when
delta_y is 0. There are a few code paths in gimp_display_shell_scale()
when we would not pop this point. One of them is for instance when
window resizing in multi-window mode is allowed. There might be more
(but the code is convoluted enough not to be 100% sure if these are
possible with our specific case).
This specific function was initially created only to be used for unit
testing code (commit 7e3898da09), but it ended up being also used
internally (commit 792cd581a2). Since I see that the test for which
this code was initially created even seem broken right now (the assert
part for position check is commented out!), I even wonder if we should
keep it. We could indeed instead just add optional start_x|y arguments
to gimp_display_shell_scale(), which would be much cleaner. But I leave
it for now.
Instead I just make sure we clean the created GdkPoint after calling
gimp_display_shell_scale(). Also I get rid of the GQueue. It is clear in
the code that we are not expecting queuing interaction of several
positions. Worse right now, we could end up in weird cases where the
pushed points are not used when they should, then could end up being
used later in totally unrelated interactions (this would make the shell
position jump here and there). So let's just make it a single point.
Finally adding some appropriate comments in parts which are still a bit
wrong.
From years of discussions, it turns out that:
- The thumbnailed-Wilber icon replacing the generic icon of GIMP often
makes the application harder to spot in the icon list of running
processes.
- In single-window mode in particular, it makes even less sense as we
just show the one active image anyway.
- Even in multi-window mode, nowadays many OSes or desktop group windows
of a same application under one icon. So we end up with several image
windows under a thumbnail only showing the top image. This happens in
KDE, GNOME, Cinnamon and Windows at least apparently (as far as is
being reported).
- Some platforms would just use only the OS-declared icon and not care
about runtime-declared ones. This is apparently the case on macOS, and
also on GNOME when the desktop file is seen by the desktop
environment. So all our code about generating thumbnailed icon is
wasted on these platform anyway.
- When intensively testing the current behavior, I had cases when the
icon was not properly updated. We could of course investigate and fix
the issues, but considering all the previous points, it might make
more sense to simply drop the feature which is mostly useless, or
worse bothersome, hence simplify the code greatly.
- Finally API to set icons from GdkPixbuf data has been removed in GTK4.
So long term, trying to keep this whole machinery feels like just
making our life difficult for a feature which all OSes seem to
deprecate and which might not be possible anymore soon (or just get
harder and harder to implement).
Note that I don't use gtk_window_set_default_icon_name() because it
would use the icon from our theme, yet so far we are not sure it makes
sense for the application icon which we probably always want to be the
same, whatever the chosen theme. Finally I just list various common icon
sizes because GTK API doesn't seem to be clever enough yet. I can't just
give it 1 SVG image (e.g. with gtk_window_set_default_icon_from_file())
and hope it does the resizing at the last minute. It turns out it
doesn't and we get an extra-small icon. So instead, let's generate
common sizes ourselves from the same SVG.
The goal of this function is to give the focus to the active image
display. This is implemented as a core GimpDisplay virtual function
(with the actual implementation in GimpDisplayImpl), allowing to be used
even in core code, without actual GUI code (this was not necessary right
now, but I think it will be useful in future use).
This function is now called from the toolbox code (cf. 2 commits
earlier), avoiding code duplication. I also added a usage at the end of
toolbox_paste_received() so that a newly opened image by middle-click
paste in the toolbox directly gains focus.
I'm still very unclear why exactly but it would seem that just queuing
the redraw with an idle function is not enough. At least on Windows,
Jacob was having cases where opening an image would get stuck unless the
mouse was moved (causing draw events most likely).
So let's use a timeout function instead. Probably no need to queue the
idle followed by the timeout function as we had before commit
4fee04b839. Instead just directly queue a draw if relevant, then run the
timeout at regular interval (marching ants speed).
This way, we would queue a lot less canvas region unnecessary redraws.
We still remake the time-before-last-draw check in the draw() signal
handling before we want to update the marching ants index for draw
events coming for other reasons (canvas updates, moving/zooming on
canvas, exposition changes, etc.).
… displayed.
We should use the dimensions from the GimpDisplayShell not the the
GimpCanvas. Indeed the canvas is shorter when rulers are visible, hence
the selection next to the extreme sides (bottom and right sides of the
canvas) was not drawn.
As suggested in a comment (itself coming from an IRC discussion), we
should not use gdk_window_(begin|end)_draw_frame() functions as this
works on X, but not on Wayland anymore. Instead draw directly during
draw() call of the shell widget, and force it to happen regularly, to
update the marching ants, via gtk_widget_queue_draw_region().
This is tested and works on Wayland. Please everyone, test thoroughly to
make sure it works well in all situations, and also that we don't get
any unexpected slowdowns.
Since the symptoms are very similar, it is highly possible that it also
fixes the issue #5952 too, for selection not showing on macOS since Big
Sur 11 (maybe they changed the same way as Wayland did). Unfortunately I
can't check this myself. Please test, whoever has access to a macOS Big
Sur and can build GIMP!
When a selection exists, we are copying then pasting the selection
contents. In particular, with multi-layer selection, it means pasting a
merged result of the selected layers (like a sample merged but limited
to selected layers).
Yet when no selection exists, with a single layer selected, a cut in
particular would remove the layer fully, then a paste would copy it
elsewhere (in the same image or even on a different image). This was
still working, but not with multiple layers. This is now fixed and we
can now copy/cut then paste several layers (without merge), which is
sometimes a very practical way to move layers (sometimes simpler than
drag'n drop, especially between images).
As a consequence, the PDB function gimp_edit_paste() now also returns an
array of layers (not a single layer).
In some cases, in particular for actions generated from plug-in
procedure right now, we were displaying the reason of the insensitivity
(typically right now, only the drawable type is cited). This was done by
appending the reason to the tooltip, separated by 2 newlines, which
resulted in extra ugly design, no nice way to style this info directly
(with pango for instance if the widget display allows it, or on a
separate info widget in a possible future, or whatnot).
Also it would mean that the action search could match a disabled action
by mistake if a search word happens to be in the reason message.
This improves the situation with the following changes:
* gimp_action_set_sensitive() now takes an optional reason string to set
the reason message.
* Same for gimp_action_group_set_action_sensitive().
* gimp_action_get_sensitive() returns an optional reason string.
* gimp_procedure_get_sensitive()'s tooltip return value now becomes a
reason (it won't contain anymore the tooltip and the reason
concatenated, only the reason for separate processing).
Was caused by widget tool fixed_center_x and fixed_center_y coordinates set to
coordinates of mouse click instead of rectangle center after converting channel
selection bbox to rectangle.
Now rectangle fixed_center_x and fixed_center_y coordinates are always updated
when tool widget x1, x2, y1, or y2 coordinates are updated.
Closes#6487
This commit also makes snap to grid and snap to vectors work off-canvas.
Since we now have off-canvas viewing, it just makes sense that snapping
would work there too.
Note that I disable snap to grid when "Show All" is OFF. I am actually
unsure this is right (as "Show All" is a view action, and we usually
don't change behavior based on view actions; for instance snap to guides
are not disabled if guides are hidden). Yet I noticed we do this in
various other features when off-canvas. We kind of use this view flag as
a switch for features working off-canvas (for instance, color picking
works off-canvas only when "Show All" is ON). So let's keep the same
logics for now at least.
Snap to guide or snap to vectors will always work though, because guides
and vectors are always visible off-canvas (even when "Show All" is OFF).
They always have been (visible, not snappable off-canvas; now they are
both).
Our error/message handling code was checking if the status bar label was
big enough to hold the message by checking the GtkLabel allocation. This
means that error message ended up on status bar only if a status text
bigger than the error message was previously displayed.
Even setting gtk_widget_set_hexpand() or the "expand" container child
property on the label, I could not find a way for GTK to actually give
it as much space as possible on the status bar.
Instead, I am computing the full container box size, starting from the
label x coordinate (assuming the label is the last shown widget on the
status bar, as usually the progress bar and the cancel buttons are not
shown in the same time as the message label). This gives me a much more
appropriate result of the maximum size which this label can hold without
ellipsizing.
By default, GTK keeps on showing client-side decorations when going
fullscreen, as it might contain buttons or other functionality that
would be lost. As such, we have to make sure we hide the titlebar.
Getting to that titlebar to update its "visible" property needs a bit of
effort, since it's an internal child of the GtkWindow that isn't exposed
in any way, so we take a little detour using `gtk_container_forall()`.
When dropping a color, we fill all the selected layers with this color.
When dropping a buffer, multi-layer is same as no layers selected (i.e.
we paste once as a new layer, not multiple times).
Logics stay the same except I replace gimp_image_get_active_drawable()
by gimp_image_get_selected_drawables() to show I looked at this code.
Basically it doesn't look like we can really handle multiple layer
selected here, unless we want overly-long window titles.
This fixes default constraint values when multiple layers are selected.
In particular fixed aspect ratio defaults in Crop or Rectangle Select
tools, in layer mode, when several layers are selected, the default
aspect ratio is the layer's ratio if all layers have the same
dimensions, otherwise it's the image dimension ratio.
Also fixes a bug when trying to create the tool rectangle while multiple
layers are selected (the rectangle was always of size 0 at point 0).
Finally fixes the auto-shrink feature with multiple layers selected. The
rectangle will now auto-shrink to the smallest rectangle which
encompasses the contents of all selected drawables inside the existing
rectangle.
In gimp.css, don't set a minimum height for GimpDisplayShell
statusbars. Instead, in GimpStatusbar, set the widget's minimum
height to the maximum of its children's natural heights. Note that
we have to do this manually, instead of using a size group, since
GtkSizeGroup::ignore-hidden is deprecated (and nonfunctional) in
GTK3.
Right now I don't change the logics of any of the tools, except that the
GimpTool class now stores a list of drawables instead of a single
drawable. This can be later used on a case-by-case basis to make various
tools actually work on multiple drawables.
Partially revert commit c73710e410,
avoiding updating tool widgets unconditionally on tool resume in
GimpDrawTool -- it's too expensive in general.
Instead, handle display-shell changes in GimpToolWidget, by adding
GimpToolWidget::update_on_{scale,scroll,rotate} flags, which
subclasses can use to request an update on any of these events.
Set the flags as necessary for the affected widgets.
Wherever we store arbitrary-format colors in an opaque buffer, use
double for the buffer, instead of char, so that it has a strict-
enough alignment to handle all our used pixel formats.
Color picking on a single layer still works as it used to. On multiple
layer, it will now pick on the composited color, similarly to sample
merged if only selected layers were made visible.
The PDB/libgimp function gimp_image_pick_color() is also updated to work
on multiple drawables too, giving the same ability to plug-ins (the only
call to this function in core plug-ins have been updated).
I am currently unsure of this one. Since GimpCanvasLayerBoundary is a
GimpCanvasRectangle, it now shows the minimum rectangular boundary
containing all selected layers.
Should we instead show all individual layers boundary? I didn't choose
this because it would make the whole canvas much more messy, and also I
figure that layer boundaries are mostly used to get an idea of your
current working space extent, for instance if we were to resize the
canvas. Matter to discuss, I guess.
These actions raise a GimpViewableDialog. For this to work, I made this
widget work with a list of GimpViewable, not a single viewable anymore
(so maybe the widget class name should change?).
When this list contains only a single GimpViewable, it will display
exactly like before, with a viewable preview. With several viewables,
the preview won't show.
This allows to add masks to all selected layers at once, with the same
basic options for all masks, as set in the dialog.
After much thought, tests and discussions with Aryeom, we decided adding
back an active item concept additionally to the selected items ones is a
bad idea as it makes only usage unecessarily complex.
We will just have selected layers. Some kind of operations will work
when more than one item (layers, channels, vectors) are selected while
others will require exacty one item.
In particular, let's replace instances of gimp_image_(s|g)et_active_*()
by corresponding gimp_image_(s|g)et_selected_*(). Also replace single
item in various undo classes by GList of items.
Also "active-*-changed" GimpImage signals are no more, fully replaced by
"selected-*s-changed".
This is still work-in-progress.
When using "show all" by default, gimp_display_flush() can be
called during GimpDisplayShell construction, before the newly-
constructed shell is assigned to the display. Use an ugly hack to
just ignore the flush when this happens.