1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-06 01:12:40 +02:00

Compare commits

...

325 Commits

Author SHA1 Message Date
Gabriele
cb5d8ac8a3 Merge branch 'gabrybarbe-fix-color-area-update' into 'master'
issue #14883: make color preview update immediate

Closes #14883

See merge request GNOME/gimp!2465
2025-10-05 00:38:42 +02:00
Bruno Lopes
d8d73266bc build/linux: Update poppler module to 25.10
Synced from
6d4124f7b8
2025-10-04 18:51:18 -03:00
Bruno Lopes
356c2baec5 gitlab-ci, build/windows: Remove forgotten comment about fixed #12284 2025-10-04 16:16:49 -03:00
Bruno Lopes
aea7042aa1 meson: Support Windows native paths (aka backslashes) on -Dprefix
Closes: #12284
2025-10-04 16:12:00 -03:00
Alan Mortensen
97944a5415 Update Danish translation
(cherry picked from commit d81cfcc325)
2025-10-04 12:48:26 +00:00
Alx Sa
a5182a010f tools: Fix missing cursor for MyPaint Brush tool
Resolves #15001
In the MyPaint Brushes v2 port (ea8b9dc1),
I implemented a cursor_update () function from the
parent class. However, I did not call the parent's
version of the function afterwards, so the MyPaint
Brush cursor was not being redrawn. This patch
adds the call to fix the cursor display issue.
2025-10-03 22:14:52 +00:00
Øyvind Kolås
9c2c5ff183 meson, app: depend on GEGL-0.4.64 2025-10-03 23:56:36 +02:00
Bruno Lopes
f09007507f Declare gexiv2 dependency on many targets (due to gimpmetadata.h)
Our build files were relying 'sysroot' to find gexiv2.h but this is
not possible with Apple Clang om which sysroot points to macOS SDK.
So, exotic environments like Homebrew were failing. Let's fix this.
2025-10-03 18:31:53 -03:00
Bruno Lopes
2b91551f4e gitlab-ci: Complete cbe56ff3 2025-10-03 09:03:26 -03:00
Bruno Lopes
cbe56ff388 gitlab-ci: Remove dangling MSYSTEM_PREFIX on Win job names
It makes them consistent with other non-Windows jobs so
easier to read.
2025-10-02 21:37:33 -03:00
Anders Jonsson
7cec3f52b9 .gitlab: fix template typo 2025-10-03 00:54:09 +02:00
Alx Sa
81c67e5614 tools: Don't commit Filter Tool without a filter
The Filter Tool is a "hidden" tool that we switch to
when applying a filter. Like other tools, it commits when
we save our image. However, we may no longer have an
active filter in the tool when we do so (like, after applying
an NDE filter). Because we check the drawable from the
filter to confirm whether we should force NDE or not,
this can cause a CRITICAL when we try to access a now
non-existent filter.

This patch extends the "if (filter_tool->filter)" check to
cover the full commit check process, to prevent the bug.
2025-10-02 12:07:25 +00:00
Øyvind Kolås
67fa72a94e meson, app: depend on babl-0.1.116 2025-10-02 13:22:29 +02:00
Yuri Chornoivan
6587256c3a Update Ukrainian translation 2025-10-02 08:21:41 +00:00
Bruno Lopes
ad9dbf2c8b tools: Drop bashism/gnushism in read command 2025-10-01 21:26:25 -03:00
Bruno Lopes
2f0bfc569b meson: Fix wrong debugging_format detection on clang-cl and msvc 2025-10-01 20:13:33 -03:00
Alx Sa
36330a271a tools: Prevent bucket fill on link/vector layers
Resolves #14993
We currently prevent paint tools from painting on
link or vector layers. However, we had not added this
protection to the bucket fill tool. This patch copies over
the relevant if statements to prevent this.
2025-10-01 13:23:09 +00:00
Jehan
baa4825880 app: use the new release/ alias URLs for the "Learn more" link of…
… Release Notes tab.
2025-10-01 14:40:18 +02:00
Jehan
8c910c2b6b tools: improve release stats.
- Interactively query the release version from standard input.
- Compute the logical previous version but also the previous release in
  time. For instance the logical previous release of GIMP 3.0.6 will be
  3.0.4 but the time-wise previous release will be 3.1.4.
- Some statistics will use the logical previous release whereas others
  the time-wise one.
2025-10-01 14:39:51 +02:00
Marco Ciampa
a025cfe41b Updated Italian translation 2025-10-01 12:37:59 +02:00
Jehan
41035c7589 plug-ins: fix memory management and handle multi-file zip.
We should not call archive_entry_free() since man
archive_read_next_header explicitly says that the returned entry is an
internal object:

> This is a convenience wrapper around archive_read_next_header2() that
> reuses an internal struct archive_entry object for each request.

The only reason why it was not crashing is that we were not properly
freeing the archive itself so internal objects were hanging! The man
archive_read says:

> Once you have finished reading data from the archive, you should call
> archive_read_close() to close the archive, then call archive_read_free()
> to release all resources, including all memory allocated by the library.

Therefore this code add archive_read_free() at the end and removes
archive_entry_free().

Furthermore we now verify if the zip archive contains any other file.
Unlike all other compression formats we were supporting until now, zip
is a full multi-file container format and we are always only trying to
read the first file listed in the archive. This likely means that this
file was not meant to be opened this way. In any case, still try to load
the first file as an image, yet raise a warning about the existence of
more files in the archive.
2025-09-30 20:14:01 +02:00
Jehan
7275569079 plug-ins: localize strings and improve extension list.
- Uppercase first letter of blurbs.
- Make the blurb and documentation strings localizable and localized.
- Add the compression format extension to the list of extensions. I am
  unsure why it was set as FIXME, because it does work perfectly (per
  tests) as a generic (de)compressor plug-in for any of the image
  formats we support. Not even this, but I am even putting the generic
  extension first, because sometimes we take the first listed extension
  of a load procedure to determine the source file format. Yet the only
  thing we can say *generically* about a file loaded by these procedures
  is that it was compressed with the associated container format!
- For the new zip-support, do not show xcf.zip and xcfzip extensions in
  the list. I don't think we want to promote these new extensions as
  standard XCF variants, even though in practice this will still work
  fine. Instead add hgt.zip (but again, after the generic zip, cf.
  previous point), because we know that this is a commonly used format
  combination for HGT files.
2025-09-30 19:53:36 +02:00
Jehan
dfafb7c6f2 NEWS: add new feature and clean out backported enhancements.
Various items have been moved to gimp-3-0 branch (commit f2c13d319e) and
some were already duplicated.
2025-09-30 17:50:39 +02:00
Aleksandr Prokudin
25d1b7f8c3 Update Russian translation 2025-09-30 17:12:29 +02:00
Bruno Lopes
0edf615333 libgimp: Improve .gir and .vapi dependencies by using unified list
To avoid bugs like: #14902
2025-09-30 11:29:51 -03:00
Aefgh Threenine
daf23e1a50 Update Thai translation 2025-09-29 23:54:22 +00:00
Alx Sa
b633b4b9c7 python: Remove layer offsets on ORA export
When exporting formats that use image procedures
(like PNG), if we don't remove the layer offsets then
the image is cut off on export. This is because we
size the image to the layer size, but then the layer offsets
move it off the canvas. This patch fixes the issue for
ORA export.
2025-09-29 18:55:20 -03:00
Yuri Chornoivan
cfa3fd6bb7 Update Ukrainian translation 2025-09-29 20:00:05 +00:00
Yuri Chornoivan
669685d1d8 Update Ukrainian translation 2025-09-29 19:51:36 +00:00
Alx Sa
f032153596 plug-ins: Add zip decompression support
This patch adds support for decompressing .zip files and
loading an image within. This allows us to load zipped
images like hgt.zip and other compressed formats.
2025-09-29 19:28:18 +00:00
Jehan
13639b1d3d NEWS: update. 2025-09-29 21:06:08 +02:00
Jehan
eb0bfe7bdb Issue #13553: pop an error dialog up only for specific GIO error.
This fixes 46d9a09698. There was a reason why this was not implemented
as an assert-type error nor as a user-facing error: network problems
happen.

We cannot pop an error up every time:

* The computer is offline! 😱 GIMP is not made to be run as a connected
  software and working on GIMP with a non-connected computer is a
  perfectly valid way of using GIMP.
* gimp.org is down (it's rare, but it happens and it should not have any
  impact to creators with GIMP).
* You are behind some kind of proxy or other complicated network
  configuration which GIO is not able to pass through.
* And any other reason which could make your GIMP not able to read the
  remote json file…

Instead let's check the more particular domain and error code, though
even this I hesitated between doing this change or simply reverting
commit 46d9a09698.
Indeed it's still quite a generic G_IO_ERROR_NOT_SUPPORTED error, so I
do hope we cannot get it in other normal conditions where reading a
remote link may fail. The last thing we want is GIMP popping up errors
which are neither bugs in our code, nor environment issues for which
anyone can do anything about.
2025-09-29 20:31:40 +02:00
Asier Saratsua Garmendia
393ca59e79 Update Basque translation 2025-09-29 17:59:37 +00:00
Jehan
3a698a05a1 plug-ins: only set the file if it's actually an inner XCF file.
Soon we will officially support .hgt.zip files (see !2483) but in fact,
even without this, the file-compressor actually support any other
formats we support, compressed into one of the container formats
supported by this plug-in.

This fixes such error message:

> gimp_image_set_file: failure to set file 'file:///home/jehan/Documents/gimp-splash-deleteme.png.gz' with extension 'gz'. The extension must be '.xcf' (or a compressed variant).
2025-09-29 17:46:33 +02:00
Jehan
f4a7da1ee3 app, pdb: similar to the previous commit, but for files loaded with…
… gimp_file_load().

We make sure that the load procedure associated to the file is the one
used for the inner-file (in case of imbricated files into container
formats).

Also let's set the imported file unless it's a XCF inner format.
2025-09-29 17:46:32 +02:00
Jehan
bb9d8df855 app: make sure we only consider the inner file load procedure to…
… determine if a file is XCF.

This was kinda already working for files loaded through the GUI. Yet the
code in file_open_file_proc_is_import() was assuming a file loaded
through the file-compressor plug-in is necessarily XCF.

Even though it is the original use, the code in file-compressor is
actually generic and is able to load any supported format additionally
compressed with gz, bz2 or xz.
Furthermore, we will soon support zip-ped imaged, explicitly to support
the format .hgt.zip which is quite common (see !2483). So remove any
logic of a file loaded by file-compressor as meaning it's a compressed
XCF.
2025-09-29 17:46:32 +02:00
Kolbjørn Stuestøl
78e68efd06 Update Norwegian Nynorsk translation 2025-09-29 15:15:57 +00:00
Ekaterine Papava
2fa82d51ee Update Georgian translation 2025-09-29 14:52:02 +00:00
Martin
f223dae9fe Update Slovenian translation 2025-09-29 13:21:27 +00:00
luzpaz
9daf5d2e5d libgimpconfig: fix typo in gimpconfig-params.c
Fixes source comment typo and modifies whitespace for readability.
2025-09-29 11:07:55 +00:00
Bruno Lopes
789af76a32 app: Move "Documentation" link one line up over (community) "Tutorials"
Users were thinking the tutorials are some kind of official docs,
but they are not maintained as the official GIMP help website,
they are more like informal documentation about GIMP made public.

Let's clarify this reordering the buttons.
2025-09-29 07:32:12 -03:00
Bruno Lopes
f9ba343558 build/windows: Stay on Inno 6.5.4 to avoid (potentially) broken 6.6.0 Dark Mode
It was announced by the devs on Google Groups that they are on preview state.

I will need time to conform our scripts to the upcoming 6.6.0.
So, let's not risk creating installers with broken UI.
2025-09-28 22:12:16 -03:00
Bruno Lopes
014aa5ae6f build/linux: Patch mypaint brushes on AppImage and Snap too
Following 2f6b7591
2025-09-28 21:39:00 -03:00
Bruno Lopes
47eac319b1 build/linux: Silence noisy warnings about GTK_MODULES
From GTK mouth:
https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.50/gtk/gtkmodules.c?ref_type=tags#L250
2025-09-28 19:58:25 -03:00
Bruno Lopes
3bde6195f6 build/windows, gimp-data: Prepare to Inno Setup 6.6.0 2025-09-28 18:19:18 -03:00
Bruno Lopes
b0689f565b build/linux: Little improvement on libheif plugins bundling 2025-09-28 08:25:27 -03:00
Bruno Lopes
1e46438ced build/linux: Fix libproxy/libpxbackend errors on Snap 2025-09-28 08:02:52 -03:00
Bruno Lopes
2b32496195 build/linux: Remove some uneeded lines after move to Trixie 2025-09-28 07:41:45 -03:00
Bruno Lopes
de62139894 build/linux: Fix GJS bundling on AppImage
It have an undeclared dependency on GioUnix typelib.
2025-09-28 07:40:20 -03:00
Bruno Lopes
f774ad7f16 Revert "Issue #13001: build/linux: Sandbox XDG_DATA_DIRS on AppImage"
This reverts commit bc095d5c83.

Sandboxing XDG_DATA_DIRS, while can fix the crash due to share/mime,
on the other hand makes impossible to call share/applications
associated with such mimes on host.

So, since we bumped the AppImage to Debian Trixie so the Glib
crash due to mime is gone, we can (and should) revert the
wrong sandboxing without problems.
2025-09-27 19:58:02 -03:00
Bruno Lopes
f53a843c3d gitlab-ci, build: Move to Debian Trixie on AppImage only
Fixes: #13001 #13106 #13492 #13647 #14779

AppImage jobs are now built with Trixie to adress #13001 and many others.

To have two Debian versions with less complexity possible, I needed to:
- Revert the prevalence of the AppImage CI (now nonreloc comes first);
- Revert the use of Clang on Debian (also to save 120MB from registry,
  since we now have 4 Docker images, each one with its own STEP cache!).
In short, .gitlab-ci.yml will look more like before I changing it a lot.
2025-09-27 18:58:18 -03:00
Bruno Lopes
46d9a09698 app: Use 'g_message' (like the help plug-in) when GVFSd-HTTP is not present
Closes #13553

Such issue tends to affect only AppImage users (e.g. when running it in
KDE installations). This is because AppImage files are not ran by
any host helper (e.g. snapd or flatpak) to connect to GVFSd and is
not possible to bundle GVFSd due to its own nature (it is daemon).

Since GVFS is listed in the INSTALL file as a required dependency, it is
fair enough to be more clear when it is not present, otherwise users will
have outdated GIMP without knowing (like happened in macOS in the past).

We are already doing this with GIMP help plug-in by the way. The
difference is that, at GIMP start, such techinical error message can
be surprising, but even so it is needed as feedback for fail on the
update check button in the end of day. Let's follow GIMP help on this.
2025-09-27 11:39:36 -03:00
Kolbjørn Stuestøl
355d695607 Update Norwegian Nynorsk translation 2025-09-27 11:44:30 +00:00
Alx Sa
714e9041d8 pdb: Set choice args to default in gimp-file-load
This patch resolves the same issue as 8021b464,
but for `gimp-file-load`.
2025-09-26 23:57:51 +00:00
Jehan
24c8f86c85 app: minor indentation cleanup. 2025-09-26 23:30:37 +02:00
Jehan
f50145c155 po: remove files which should not be in POTFILES.in.
This file is part of po-tags/ domain, and in fact, it's even in the
POTFILES.skip of the main po/ domain.
2025-09-26 21:53:28 +02:00
Gabriele
7f8298467b Issue #11869: use a custom AppMenu for macOS 2025-09-26 11:43:47 +00:00
Alx Sa
23a9758a7b libgimpwidgets: Update hex color as you type
This patch connects the gimp_color_hex_entry_events ()
function to "key-release-event" and adjusts the code
to update valid colors as you type. Pressing Enter
will work as before, converting back to the last valid
color if an invalid one is typed.
2025-09-25 11:48:17 +00:00
Jehan
0af9261980 app: fix rendering background of Colormap dockable.
The rgba variable would be used uninitialized. This needs to be moved
one loop level up so that the color extracted at each cell start
position is properly reused (and also so that the full transparent color
at no-entry position is properly set and reused too).
2025-09-25 01:27:54 +02:00
Martin
77d25750a7 Update Slovenian translation 2025-09-24 20:36:59 +00:00
luzpaz
155e951fa6 app: Fix description typo
This patch fixes a minor typo in a user-facing description within app/path/gimpvectorlayer.c  
This was found via codespell.
2025-09-24 17:24:28 +00:00
Jehan
5a22a9b931 app: make sure we don't crash dereferencing a NULL GError.
I think most, if not all, failure cases of file_open_with_proc_and_display()
should allocate a GError by now. But just in case we missed some edge
case, better not crash.
For instance, we were crashing when opening a remote file because of
this line before the previous commit was pushed.
2025-09-24 19:15:47 +02:00
Jehan
2187f0a49c app: fix opening remote files.
This got broken with commit 66cdecb0fa. It is now possible to open
remote files again.
2025-09-24 19:10:33 +02:00
luzpaz
91418131a0 app, libgimp*, pdb, themes: Fix description typos
This patch fixes minor typos in user-facing descriptions
and internal comments found by Codespell.
2025-09-24 16:50:15 +00:00
Yuri Chornoivan
645d23cd37 Update Ukrainian translation 2025-09-24 16:13:51 +00:00
Jehan
28fa2e5fc7 app, libgimp, pdb: new function gimp_link_layer_get_mime_type().
As discussed with NikcDC, this will be useful, for instance for the SVG
export to know the mime type of the linked file. If not PNG, JPG or SVG,
we may want to output a small warning that some viewers may not be able
to read such files, since the SVG spec makes the support of these 3
formats only as mandatory.
2025-09-24 16:11:01 +02:00
Bruno Lopes
c13bf1af19 build: Move loose scripts in meson subdir to tools
The build dir looks "prettier" without the meson subdir.
With prettier I mean: just the OSes subdirs.
2025-09-24 09:07:47 -03:00
Martin
9337c55599 Update Slovenian translation 2025-09-24 11:26:55 +00:00
Ekaterine Papava
947995248a Update Georgian translation 2025-09-24 05:09:40 +00:00
Jehan
abcfbfbca5 NEWS: update. 2025-09-24 03:06:56 +02:00
Jehan
b121ddd6f8 app, pdb: do not leak a GFile in gimp_temp_file() or any future…
… PDB API which will return a newly allocated GFile.

Though gimp_temp_file() was so far the only such case where a returned
GFile was being leaked, it may happen again. So the PDB must instead
assume that all returned GFile-s have their own reference and take over
said reference.

And therefore update all other functions to increase the internal
GFile-s reference counts.
2025-09-24 02:22:43 +02:00
Jehan
ba1de3b68e app, libgimp, pdb: add GimpLinkLayer base API.
Still more to be done, but this is the basic, working API.
2025-09-24 01:56:52 +02:00
Jehan
6552e3200d libgimp: add gimp_item_is_vector_layer() and fix some "Since" annotations. 2025-09-24 00:46:59 +02:00
Bruno Lopes
4d97212cf9 build/linux: Sync with Beta manifest regarding whitespaces 2025-09-23 16:56:32 -03:00
Yuri Chornoivan
54b64252df Update Ukrainian translation 2025-09-23 18:56:50 +00:00
Bruno Lopes
c79db4c15a gitlab-ci: Unify build jobs timeout by bumping them to 30min
While 20min is being enough, the jobs are completing
too close of the due time (due to awful runners like
OSU or Win32 stuckness). Let's prevent failures, then.
2025-09-23 15:38:25 -03:00
Bruno Lopes
cecb937a0b gitlab-ci: Reduce Flatpak timeout to 20min like AppImage and Snap, after ORAS 2025-09-23 12:18:03 -03:00
Bruno Lopes
fe4dbeb911 build/linux: ORAS works! Let's do some cosmetical changes on Flatpak deps script 2025-09-23 12:17:53 -03:00
Bruno Lopes
fdb4111e3f build/windows: Temporarely show flatpak deps building to see if ORAS caching is working 2025-09-23 11:52:18 -03:00
Bruno Lopes
72533aaf8e build/linux: Do not cache babl and gegl builds binaries to ORAS image
They should be passed only at artifact level.
2025-09-23 11:52:15 -03:00
Marco Ciampa
ccc4eacac3 Updated Italian translation 2025-09-23 16:14:49 +02:00
Bruno Lopes
8e9b7bfce6 build/linux: Test built packages binary caching on Flatpak with ORAS
If this works, our flatpak builds will behave like on AppImage,
Snap and Windows, I mean: with all precompiled binaries.
2025-09-23 10:37:42 -03:00
Sabri Ünal
17552c0e11 Update Turkish translation 2025-09-23 13:08:08 +00:00
Sabri Ünal
f428089947 Update Turkish translation 2025-09-23 13:07:56 +00:00
Rico Tzschichholz
6260590cf4 libgimp: Additionally pass gio-[unix,windows]-2.0 to vapigen
Fixes https://gitlab.gnome.org/GNOME/gimp/issues/14902
2025-09-23 08:41:05 -03:00
Jehan
c5e77fb8bb po-windows-installer: fix building the pot file.
When running `ninja gimp30-windows-installer-pot`, we had this error:

```
[0/2] Running external command gimp30-windows-installer-pot
/usr/bin/xgettext: warning: ITS rule file 'gimp-ms-installer-config.its' does not exist; check your gettext installation
/usr/bin/xgettext: warning: file 'build/windows/installer/lang/setup.isl.xml.in' extension 'xml' is unknown; will try C
```
2025-09-23 12:13:48 +02:00
Jehan
b50781730c NEWS: update. 2025-09-23 11:56:04 +02:00
Emin Tufan Çetin
2b669917c2 Update Turkish translation 2025-09-23 09:54:29 +00:00
Martin
7d22110cfb Update Slovenian translation 2025-09-23 07:33:11 +00:00
luming zh
86cc15cbf0 Update Chinese (China) translation 2025-09-23 00:31:05 +00:00
luming zh
865e6363e1 Update Chinese (China) translation 2025-09-23 00:24:04 +00:00
Jehan
789d82355c app, pdb: "Add Layer Mask" dialog asks whether to edit mask immediately.
While there are cases when you want to edit the mask straight away (this is
often the case when starting with a white or black mask), in many other cases,
the mask may be already as you want it per its initialization (e.g. when
initializing with a channel, selection, the alpha channel, etc.).

Until now, the Add Mask dialog was always switching to the "Edit Layer Mask"
mode by default, which forced an additional unneeded click each time you created
a mask (and were in a case where you initialize the mask as you want it
directly).

Now adding "Edit mask immediately" feature in the "Add Layer Mask dialog":

* It's checked by default to keep historical behavior.
* As most other dialogs, the last value is remembered, allowing people with
  repetitive workflow not to have to repeatedly set the settings each and every
  time.
* This default is also visible and settable in Preferences > Interface > Dialog
  Defaults.
2025-09-22 22:04:32 +02:00
Bruno Lopes
82cb3ae6fe gitlab: Print filenames in meson_health 2025-09-22 16:02:24 -03:00
Bruno Lopes
1a7f673b7d gitlab: Check gimp-data submodule too on meson-health job 2025-09-22 11:19:43 -03:00
Gabriele Barbero
8f57d4bdff gui: fix quit lose unsaved changes macOS
When quitting the application using "Quit" from the dock's right-click menu,
GIMP does not follow our standard quit procedure. Instead, macOS forces the
application to close, which may result in losing unsaved changes.

By adding a delegate that intercepts the applicationShouldTerminate call,
we ensure our quit code is used, preventing macOS from handling the shutdown
directly.
2025-09-22 13:29:52 +00:00
Jehan
aa9e437d42 tools: better logic for the splash image text.
Change of series must always have their own splash image (which will
stay the same within the whole series).
Development releases though will have a new splash image most of the
time (but it is not mandatory).

See rule edicted in commit Infrastructure/gimp-web-devel@061f544.
2025-09-22 12:39:23 +02:00
Jehan
ec4daa643e tools: use release news alias URL.
While we don't know the accurate URL of every release before
publication, we now know the alias it will have in the shape:
https://www.gimp.org/release/<version>

Cf. commit Infrastructure/gimp-web@bca40810
2025-09-22 12:30:08 +02:00
Bruno Lopes
308963c271 build/linux: Don't allow openjph update on Flatpak
It have broken includes starting with 0.23.0
2025-09-21 22:43:54 -03:00
Bruno Lopes
4d0fef9482 build/linux: Update graphviz module to 14.0.0 2025-09-21 22:41:14 -03:00
Bruno Lopes
d5f3fa77db build/linux: Improve bund_usr check added in 5bc2f26c 2025-09-21 21:37:25 -03:00
Jehan
dbf0c39bb3 app: use more recent harfbuzz API.
hb_ft_font_lock_face() (and unlock) exists since harfbuzz 2.6.5 and our
current requirement for this dependency is 2.8.2.

Fixes this compilation warning:

> app/text/gimpfont.c:1196:3: warning: ‘hb_ft_font_get_face’ is deprecated: Use 'hb_ft_font_get_ft_face' instead [-Wdeprecated-declarations]
>  1196 |   face = hb_ft_font_get_face (hb_font);
2025-09-22 00:43:11 +02:00
Bruno Lopes
56f72c24ba build/windows: Add .pdb bundling condition after bundle() improvement 2025-09-21 18:17:22 -03:00
Jehan
a0676125a1 app: fix build warning on Windows.
Fixes following warning, seen on CI:

> ./app/dialogs/about-dialog.c:549:7: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
2025-09-21 22:46:48 +02:00
Bruno Lopes
c472800eae build/windows: Do not build exiv2 on 32-bit since it uses ancient MSVCRT 2025-09-21 16:33:12 -03:00
Bruno Lopes
63b4d69e48 build/linux: Drop --permissive mode introduced in 5bc2f26c
It was an awful design of mine.
2025-09-21 14:44:11 -03:00
Jehan
70bf795dfb libgimp: avoiding a build warning on Windows.
Seen in the CI:

> ../libgimp/gimpui.c:406:1: warning: 'gimp_ui_get_foreign_window' defined but not used [-Wunused-function]
2025-09-21 19:18:30 +02:00
Bruno Lopes
a7c4320312 build/windows: Stop Windows script if bundle target do not exist 2025-09-21 11:32:17 -03:00
Bruno Lopes
5bc2f26cb0 build/linux: Stop AppImage script if bund_usr target do not exist 2025-09-20 20:31:24 -03:00
Lukas Oberhuber
cacb8d2035 clipboard: Fix #14639
This is the recommended fix from Gtk to use our own mime type rather than depend on a mimetype
that has a different expectation of payload.

This means drag and drop of colors uses `application/x-geglcolor` rather than `application/x-color` which expects an RGBA color rather than a structure.
2025-09-21 00:06:15 +01:00
Aurimas Černius
c8ed51bb52 Update Lithuanian translation 2025-09-20 20:39:03 +00:00
Sabri Ünal
264a65e0b3 Update Turkish translation 2025-09-20 15:29:10 +00:00
Alx Sa
e27353216c plug-ins: Fix display lag in Small Tiles
Resolves #14932

In Small Tiles, we update the preview whenever
the number of segments slider is dragged. However,
while we reacted to the slider moving, we actually grab
the number from the GimpProcedureConfig object.
As a result, there's a lag between the signal firing and the
config object updating, so we don't grab the latest change.
This patch alters the signal to run when "notify::num-tiles"
is called, resulting in the update function having the updated
number.
2025-09-20 15:21:45 +00:00
Sabri Ünal
49fc3ad0bd Update Turkish translation 2025-09-20 09:05:26 +00:00
Sabri Ünal
5b71d1a10d Update Turkish translation 2025-09-20 06:37:52 +00:00
Lukas Oberhuber
06bcef3273 macos plugins: Improves dock icon flashing from #12150
This means additional icons don't stick around. However, this is the easy workaround to turning everything into a proper plugin with .plist files.
2025-09-20 00:10:06 +01:00
Bruno Lopes
17b23b6f26 build/windows: Fix submission info code after Microsoft guys feedback
Thanks to https://github.com/kswanny and https://github.com/knangunu.
2025-09-19 09:23:23 -03:00
Bruno Lopes
413114f9d0 gitlab: Print message when 'branches-check' job have no errors 2025-09-18 07:49:10 -03:00
Bruno Lopes
c2f0afb4bd gitlab: Fix master exception on branches check 2025-09-17 22:38:24 -03:00
Bruno Lopes
b945d77ed7 gitlab: Do not check for master branch 2025-09-17 22:33:33 -03:00
Bruno Lopes
7c04605d14 gitlab: Add job to warn about "dead" branches
It is quite common for we developers (me included) to forget to
delete already merged branches. Let's fix this mess with a job.
2025-09-17 22:27:06 -03:00
Jehan
25edb3cc64 libgimpbase: let's use a stable version for "Since:" annotation. 2025-09-17 22:20:57 +02:00
Bruno Lopes
b773c3ac48 build/windows: Complete dirty 32-bit exiv2 workaround 2025-09-17 15:58:29 -03:00
Bruno Lopes
9551519f23 build/windows: Extremely dirty workaround for 32-bit sake 2025-09-17 15:51:39 -03:00
Bruno Lopes
a9d2700631 build/windows: More self_build organization to support MINGW32 2025-09-17 15:14:42 -03:00
Bruno Lopes
5375ca63d5 build/windows: Fix remaining Clang-oriented options of self_build on MINGW32 2025-09-17 14:45:33 -03:00
Bruno Lopes
78acdd8882 build/windows: Fix typo on Clang color check 2025-09-17 14:18:31 -03:00
Bruno Lopes
b5dda733dc build/windows: Fix failing build due to Clang color on MINGW32 2025-09-17 14:13:31 -03:00
Bruno Lopes
e17567d001 build/windows: Build exiv2 with Meson so make the .dll name expected by gexiv2 2025-09-17 09:30:32 -03:00
Bruno Lopes
4a0ea33bc5 build/windows: Uncomment .pdb installing on Meson mode of self_build function 2025-09-17 09:25:58 -03:00
Bruno Lopes
a2d106e3fa build/windows: Build exiv2 with setlocale patch 2025-09-17 07:36:03 -03:00
Jehan
4ebd340688 NEWS: update. 2025-09-17 12:30:14 +02:00
Bruno Lopes
15f047f6c0 build/windows: Restore comments on 2_bundle-gimp-uni_sym.py 2025-09-16 13:30:19 -03:00
Bruno Lopes
484d0fbcf4 build/linux: Fix PostScript support on Snap with proper env var 2025-09-16 12:10:24 -03:00
Bruno Lopes
b70186bc99 build/linux: Bundle needed files for PostScript support on AppImage 2025-09-16 12:10:21 -03:00
Marco Ciampa
4a656a1db0 Updated Italian translation 2025-09-16 15:26:56 +02:00
Anders Jonsson
cb565344e9 Issue #14878: fix missing spin boxes in Map to Object plug-in
Light position spin boxes in Map to Object could be missing
or shown when they shouldn't be due to reuse of a variable.

Fixes #14878
2025-09-16 10:37:02 +00:00
Bruno Lopes
c8971ac2ae build/windows: Try to fix failing .patch download on @creiter runners 2025-09-16 07:12:16 -03:00
Bruno Lopes
3ec63979d8 build/windows: Make possible to apply remote .patch on self builds 2025-09-15 21:00:09 -03:00
Bruno Lopes
c72e36c6a2 gitlab-ci, build/windows: Fix broken env after 5ccc5252 2025-09-15 19:21:45 -03:00
Bruno Lopes
5ccc525281 build/windows: Add colored output and .pdb support for Cmake self builds 2025-09-15 14:40:29 -03:00
Jehan
84eaa94842 plug-ins: align with __attribute__ keyword.
The bug in old Bugzilla #138357 report was happening on icc on ia64 with
-no-gcc option. It does look like after all these years, this is still a
GCC attribute, but we use the same attributes on babl and GEGL code. So
to be fair, it'd be useless to only forbid using it on GIMP code. And
that makes for much less ugly code.

Note that C11 has _Alignas() and C23 alignas() specifiers. These are
standard, but we are typically still more into C99 code. Let's see if we
move on to C11 some day… But for now, let's use __attribute__.

Also I am unsure how much this issue is still relevant nowadays. Maybe
even without specified alignment, it would now work fine with icc on
IA-64. 🤷
Or maybe it really doesn't matter that much because Itanium has been
discontinued in 2019, though I guess existing hardware will still be
around for a bit longer.
2025-09-15 19:36:29 +02:00
Alx Sa
bc7cc0b698 path: Update SVG tag when exporting paths
Per Martin Owens of Inkscape and Jonathan Watt,
one of the SVG specification editors
(https://jwatt.org/svg/authoring/#doctype-declaration),
we should not export the DTD with the GimpPath SVG.
This patch also adds an explicit SVG version to the
<svg> tag.
2025-09-15 17:28:33 +00:00
Alx Sa
602300ec8e pdb, app, libgimp, libgimpconfig: Stroke/Fill Vector Layer PDB
This patch adds additional API for setting the stroke/fill
properties of vector layers. You can now set/get color, stroke
width and stroke style via the PDB. Pattern get/set API is not
yet implemented.

This patch also updates a missing parameter check for GimpVectorLayer
in gimp_config_param_spec_duplicate (), and adds additional API
in /app to make it easier to safely retrieve GimpVectorLayerOptions.
2025-09-15 14:14:46 +00:00
Sabri Ünal
64e276c3b5 Update Turkish translation 2025-09-15 12:12:02 +00:00
Marco Ciampa
96394377e6 Fix in Italian translation 2025-09-15 09:52:28 +02:00
Juliano de Souza Camargo
a926e013da Update Brazilian Portuguese translation 2025-09-14 13:03:24 +00:00
Kolbjørn Stuestøl
2d74278860 Update Norwegian Nynorsk translation 2025-09-13 17:03:47 +00:00
Kolbjørn Stuestøl
e1e4c0f400 Update Norwegian Nynorsk translation 2025-09-13 16:59:09 +00:00
Bruno Lopes
5fc3c29f5c build/windows: Fix custom build options not being passed to Meson and Cmake 2025-09-13 09:32:37 -03:00
Nathan Follens
de4fb3470c Update Dutch translation 2025-09-12 23:30:17 +00:00
Nathan Follens
ddfce634a8 Update Dutch translation 2025-09-12 23:30:05 +00:00
Gabriele Barbero
9d64379b1c libgimpcolor, libgimpwidgets: make color preview update immediate
Previously, the `gimp_color_area_set_color` function compared the new color
to the current one using perceptual similarity. This caused small or gradual
color changes to be missed, resulting in a "laggy" update of the color preview
in GimpColorSelection.

Now, the check is performed on the actual color difference, and the preview
is updated every time the color changes, even for minimal variations.
This ensures the color preview is always immediate.
2025-09-13 00:44:51 +02:00
Bruno Lopes
527f4964fe build/linux: Update ghostscript module to 10.06.0
Synced from: 5ce8488408
2025-09-12 10:59:05 -03:00
Bruno Lopes
be2e47114d build/windows: Forgot '-and' in previous commit 2025-09-12 07:51:36 -03:00
Bruno Lopes
11b81e25a4 build/windows: Only use meson in pure Meson built dependencies 2025-09-12 07:44:26 -03:00
Jehan
4ca05cb38d app: fix crash when json parsing fails.
The argument is already a URI, not a GFile.
2025-09-11 23:31:03 +02:00
Jehan
bb9aad1e87 app: fix crash on invalid previously picked layer.
This happened to our artist in residency. She had a crash when
gimp_image_pick_layer() was apparently run with a non-NULL yet invalid
previously_picked layer. So let's make sure that we clear the stored
item pointer when the object gets finalized.
2025-09-11 23:31:03 +02:00
Bruno Lopes
4dceeb174a libgimp: Only list gio_specific on Glib 2.86 and newer
Since GioUnix-2.0 namespaces were buggy in previous versions
2025-09-11 12:16:34 -03:00
Jehan
9819457f31 meson: add deprecation warnings on GLib and GTK/GDK API usages.
I discover GLIB_VERSION_MIN_REQUIRED and GLIB_VERSION_MAX_ALLOWED. The
former will make so that we won't have deprecation warnings anymore if
ever we use a function which has been deprecated recently (as long as it
was not deprecated at the minimum required version). The latter will
make so that we get deprecation warnings for any function added after
the minimum required version.

Note that ideally both should be at the same version, but since we have
a bunch of GLIB_CHECK_VERSION() protected conditional code, we would get
compilation warnings even on correctly protected code. So just keep the
small discrepancy until we can finally bump our minimum requirement.

Also add the equivalent macros for GTK/GDK.
2025-09-11 16:23:57 +02:00
Jehan
7c947ef1af app, libgimpbase, plug-ins: deprecate GimpPixPipe.
This really feels like internal API which we'd want to keep private (and
used by core plug-ins only).

Also as Jacob noticed, it's not even included in libgimpbase/gimpbase.h
so plug-ins wishing to use this API need to include this file
specifically anyway (but the header is still installed and the API is
introspected).

Since we cannot remove these functions now that GIMP 3 was published,
for API stability, I am only deprecating them both in the C API with
macros and in the bindings with GObject Introspection annotations.
Therefore any third-party plug-in developer trying to use these
functions in a plug-in will get build-time or run-time warnings.

Then when we'll move on to GIMP 4 development, we can remove the
deprecation and simply make this file private-only use instead.
2025-09-11 16:23:57 +02:00
Ekaterine Papava
03beda6e2a Update Georgian translation 2025-09-11 10:56:59 +00:00
Bruno Lopes
a7d867c8bc libgimp: List gio_specific as dependency for .typelib
This is required starting with Glib 2.86.0.
2025-09-11 07:44:38 -03:00
Jehan
6584f92748 NEWS: update. 2025-09-10 18:42:17 +02:00
Kolbjørn Stuestøl
593f0abf09 Update Norwegian Nynorsk translation 2025-09-10 15:22:52 +00:00
Kolbjørn Stuestøl
a734b4a3a4 Update Norwegian Nynorsk translation 2025-09-10 15:21:39 +00:00
Estecka
0fd280db5c Issue #14777: Fix bad axis centering on zoom-out.
This was simply caused by two variables having been swapped.

Gimp 2 used to work properly because there were two separate mix-ups that
cancelled each other: one in the function arguments, and one in the code
itself. Gimp 3 had fixed the error in the arguments, but not in the code,
thus enabling the bug.
2025-09-09 17:44:55 +00:00
Nathan Follens
443d0a2f7b Update Dutch translation 2025-09-09 16:09:04 +00:00
Nathan Follens
ed01c1b7f4 Update Dutch translation 2025-09-09 16:08:54 +00:00
Nathan Follens
904f283932 Update Dutch translation 2025-09-09 16:08:39 +00:00
Bruno Lopes
9026d18039 app: Make possible to append _NT_SYMBOL_PATH 2025-09-09 12:57:46 -03:00
Sabri Ünal
8a5825b66f Update Turkish translation 2025-09-09 14:53:26 +00:00
Cheesequake
71caf7eb05 Issue #13746: change incorrect variable to check for changes in y-axis 2025-09-08 14:41:41 -03:00
Yuri Chornoivan
bf6092c728 Update Ukrainian translation 2025-09-08 14:06:30 +00:00
luming zh
6d74a880f9 Update Chinese (China) translation 2025-09-08 08:59:29 +00:00
Martin
1a953c5c73 Update Slovenian translation 2025-09-08 08:28:52 +00:00
Balázs Meskó
1564efb519 Update Hungarian translation 2025-09-08 06:38:12 +00:00
Alx Sa
3e96397770 dialogs: Add palette format filters to import dialog
GIMP supports importing a number of palette formats
such as Adobe Swatch Exchange and SwatchBooker.
However, this is not immediately apparent from the import
palette dialogue.
This patch adds the currently supported palette formats as
filters in the dialogue, both to let users hide irrelevant files from
view and to highlight which formats we support.
2025-09-08 01:40:41 +00:00
Alx Sa
c8cf2219ce libgimpbase, libgimpwidgets, tools, app: Remove warnings
This patch fixes a few (mostly Windows-specific) warnings on build.
* Hides functions like gimp_get_foreign_window () and variables
like transient_set that aren't used in Windows.
* Changes hollow_g_shell_quote () to not return a const gchar *,
since the value it returns is actually not const.
* Cast update_interval to double to remove warning about mixing
enums and doubles in division.
2025-09-07 18:41:13 +00:00
luming zh
2865aa7f03 Update Chinese (China) translation 2025-09-07 00:30:17 +00:00
Bruno Lopes
013f9c7f0c build/windows: Fix prefixes priority in libraries bundling 2025-09-06 19:46:50 -03:00
Bruno Lopes
8ea6e4031e build/windows: Add support to Cmake builds on self_build function
This can be useful in the future if we need to build some dependency that
does not use Meson (hope we will not need that but anyway)
2025-09-06 18:39:06 -03:00
Bruno Lopes
69359a16c1 build/linux: Update openexr module to 3.4.0 and add openjph module
Synced from: 4318fbbef2
2025-09-06 16:31:38 -03:00
Alx Sa
4d84ac748b Issue #12012: Don't require GUI for C source and HTML export 2025-09-06 19:25:57 +00:00
Bruno Lopes
1dcc8585ef gitlab-ci: Move from unmaintained Kaniko to Buildah
Closes: #14796

There is no other doable option than Buildah. I also tested the
other Kaniko alternatives pointed by GitLab documentation which
were Docker-in-Docker and Buildkit but none worked unprivileged.

Regression: our logs will be a bit more noisy compared to Kaniko.
See: https://github.com/containers/buildah/issues/6362
2025-09-06 16:05:40 -03:00
cheesequake
8a3fb8c08e Issue #14763: Clean new images whether linked layers or not.
Moving the gimp_image_undo_free and gimp_image_clean_all
functions outside the link layer check prevents the image getting
dirty. Hence, closing a new linked layer image without changes
doesn't open a save changes dialog anymore.
2025-09-06 17:33:58 +00:00
Bruno Lopes
4509ec92f5 build/windows: Revert wrongly pushed change 2025-09-06 14:33:52 -03:00
Bruno Lopes
ee43316839 meson: Fix .pdb installation condition on Linux and macOS 2025-09-06 14:17:57 -03:00
Alx Sa
0782b9166b display: Guard private->initial_monitor when NULL
On some systems, it is possible for gimp_image_window_switch_page ()
to be signaled when private->initial_monitor has been set to NULL but
we don't yet have a GtkWindow. This eventually produces a CRITICAL
when gimp_dialog_factory_add_foreign () is run with a NULL monitor.

This patch adds a condition so that gimp_image_window_session_update ()
is not run with a NULL monitor in those cases.
2025-09-06 16:01:07 +00:00
Gabriele Barbero
5a34856e38 core: fix wrong if condition in gimp_drawable_duplicate
Probably a typo: the wrong control variable was used in the if statement.
This caused a segfault when duplicating a drawable if new_filter was NULL.
2025-09-06 17:04:51 +02:00
Bruno Lopes
9ec28cec54 app: Fix stuck debug dialog on Xorg (X11) too 2025-09-06 10:45:04 -03:00
Bruno Lopes
d6d959c6c9 app: Add margin around buttons of gimpcriticaldialog
The dialog was inconsistent. Let's fix that.
2025-09-06 10:42:35 -03:00
Marco Ciampa
83c18ee0f2 Fix of frame term in Italian translation 2025-09-06 14:40:32 +02:00
Marco Ciampa
5a5e0b6fee Little fix in Italian translation 2025-09-06 14:18:56 +02:00
Cristian Secară
acf0920d82 Update Romanian translation 2025-09-06 11:56:07 +00:00
Jehan
58efcf6312 app: fix dropping a dockable above/below the only dock in a dockbook.
There is no bug report that I know of as it was reported directly by
Aryeom. When a dock had only a single dockbook, if we tried to move one
of the dockable to the above or below target areas, it would fail.

The reason is that we were not counting the dockables correctly so the
code thought we were trying to move from a dockbook containing a single
dockable (single tab).
2025-09-06 12:35:52 +02:00
Cristian Secară
e3c8910da7 Update Romanian translation 2025-09-06 09:46:06 +00:00
Alevtina Karashokova
01c1949dd5 Update Russian translation 2025-09-05 11:34:57 +00:00
Alx Sa
599a6c7afe core: Fix Lab & CMYK ACB palette import
Converts the babl formats for Adobe Color Book
Lab and CMYK formats to "float", to prevent a crash
when accessing u8 Lab colors that have negative values
and CMYK colors that are too dark.
2025-09-05 11:02:13 +00:00
Jehan
16bb162894 menus: add specific link layer actions in Layer menu. 2025-09-05 12:44:02 +02:00
Bruno Lopes
65258d6183 build/linux: Update poppler module to 25.09.1 2025-09-04 20:21:08 -03:00
Gabriele Barbero
6e80f98390 plug-ins: use a temporary image to get the buffer...
...with filters during Recompose

Previously, get_buffer_with_filters() inserted and removed a temporary
copy of a layer in the original image. This caused the image to appear
modified, adding entries in the undo history and prompting the user to save
changes, even though the image itself was not actually changed.

This patch modifies the function to create a temporary image and perform
the layer insert operation there. Filters are applied as before,
but the original image remains untouched, avoiding unwanted undo entries
and mark the image as modified.
2025-09-04 20:05:22 +02:00
Yuri Chornoivan
e18eaff1dc Update Ukrainian translation 2025-09-04 16:11:49 +00:00
luming zh
a4c780f6c9 Update Chinese (China) translation 2025-09-04 09:31:58 +00:00
Martin
0665e3fb5c Update Slovenian translation 2025-09-04 08:59:22 +00:00
Ekaterine Papava
9f9bf1003d Update Georgian translation 2025-09-04 07:17:19 +00:00
Ekaterine Papava
8b560f835e Update Georgian translation 2025-09-04 07:01:30 +00:00
Marco Ciampa
2a9eb5aa66 Small fix in Italian translation 2025-09-04 08:43:57 +02:00
Alx Sa
002b22c150 plug-ins: Fix ZDI-CAN-27793
GIMP ILBM File Parsing Stack-based Buffer Overflow
Remote Code Execution Vulnerability

Adds a check to file-iff.c to ensure the palette_size is
between 0 and 256.
2025-09-04 04:45:43 +00:00
luming zh
d27c580144 Update Chinese (China) translation 2025-09-04 02:28:31 +00:00
Bruno Lopes
4738472fcd tools: Drop bashisms on milestones info fetching 2025-09-03 21:13:34 -03:00
Jacob Boerema
4eb106f2bf plug-ins: fix ZDI-CAN-27823
GIMP XWD File Parsing Heap-based Buffer Overflow Remote Code Execution
Vulnerability.

Check offset in colormap is valid before writing to it.

Closes #14814
2025-09-03 18:38:53 -04:00
Alx Sa
53b18653bc plug-ins: Fix ZDI-CAN-27836
ZDI-CAN-27836: GIMP FF File Parsing Integer Overflow
Remote Code Execution Vulnerability

This patch increases the row_size data type to gsize and checks if it
would overflow based on the width given. It also makes sure the image
size does not exceed GIMP's image size limits.
2025-09-03 22:10:34 +00:00
Anders Jonsson
2012eef75c plug-ins: remove doubled word in dicom string 2025-09-03 23:03:07 +02:00
Jacob Boerema
fb31ddf322 plug-ins: fix ZDI-CAN-27878
GIMP WBMP File Parsing Integer Overflow Remote Code Execution
Vulnerability

We recently fixed one instance of not upgrading the size, but forgot
the other. Fix that here by casting to (gsize). While we're at it,
also add a warning, when reading more data fails unexpectedly.

Closes #14812
2025-09-03 15:25:55 -04:00
Jacob Boerema
0f309f9a8d plug-ins: fix dicom plug-in ZDI-CAN-27863
GIMP DCM File Parsing Heap-based Buffer Overflow Remote Code Execution
Vulnerability

This adds more safety checks and sets actual GError's instead of just
calling gimp_quit.

Closes #14811
2025-09-03 13:34:36 -04:00
Jehan
05e90b1cde app: optimize the detection of filters with aux input.
As reported by Liam, apparently for someone with a lot of filters, these
node creations just to check the aux input may add up noticeable time on
boot (it may also depend on the OS too? I didn't have any noticeable
delay personally).

Unfortunately we cannot know the presence of an aux input just with
class introspection because they can be registered by the op at runtime.

This optimization is therefore twofold:

* Since we know which filters have an aux input among all the ones with
  hardcoded actions, we also hardcode this data. It means we only do the
  actual check on non-hardcoded operations (third-party filters but also
  GEGL operations which are not specifically listed in our code).
* I only do these checks once, stored by name in a hash table, because
  filters_actions_setup() is actually run several times (for different
  menus).

This should improve startup time a lot for people who experienced this
delay.
2025-09-03 18:38:16 +02:00
Marco Ciampa
e4cb1e485e Small fix in Italian translation 2025-09-03 17:40:45 +02:00
Jehan
03f7cf58b8 tools: also parse milestone infos automatically. 2025-09-03 16:18:14 +02:00
Alx Sa
5f4329d324 plug-ins: Fix ZDI-CAN-27684
Prevent overflow attack by checking if
output >= max, not just output > max.
2025-09-03 13:41:10 +00:00
lillolollo
1a144f35a6 plug-ins: fix file-exr warning and a possible memory leak 2025-09-03 12:59:39 +00:00
Bruno Lopes
8287302b50 build/linux: Update Poppler to 25.09 and manually disable awful -DENABLE_GPGME
Ported from: a125318890
2025-09-03 09:38:43 -03:00
Marco Ciampa
98dbff1e99 Updated Italian translation 2025-09-02 21:14:26 +02:00
Bruno Lopes
53a1d07ffd tools: Remove last bashisms in new release-stats.sh
'paste' is a bit opaque but at least more portable.
2025-09-02 16:08:53 -03:00
Bruno Lopes
0191e0a485 tools: Drop bashisms on new release-stats.sh versioning evaluation 2025-09-02 15:53:58 -03:00
Anders Jonsson
fc4eb6730c plug-ins: add missing include to fix build 2025-09-02 20:02:01 +02:00
Bruno Lopes
459090836a gitlab-ci: Use 'ref:' on flatpak_ci_initiative.yml for CI safety
Not making use of 'ref:' makes GitLab fetch the latest version of
the *initiative.yml with the latest fixes and such. That would
not be a problem and even desirable maintenance-wise but that
allows GNOME to add anything on our .gitlab-ci.yml at any time.

This is hard to debug and can break our CI. For example,
see: https://gitlab.gnome.org/GNOME/citemplates/-/issues/35.
2025-09-02 14:58:12 -03:00
Jehan
81c844d2ca tools: tweak script so that it outputs statistics in release news format.
Though most of the stats we were pulling came from this, let's format it
exactly how we have done in many latest release news.
Also add automatic stats pulling too of our many side repositories.
2025-09-02 19:08:48 +02:00
Jehan
51ba945eb1 plug-ins: add reminder to obsolete scripts in favor of proper Script-fu plug-ins.
Closure of #10652 made me realize we should probably leave a warning
reminder.
2025-09-02 19:08:48 +02:00
Marco Ciampa
87def70e1e Updated Italian translation 2025-09-02 17:39:32 +02:00
Aleksandr Prokudin
35257782ca Update Russian translation 2025-09-02 02:35:51 +02:00
Balázs Úr
238718b667 Update Hungarian translation 2025-09-01 20:30:02 +00:00
Balázs Úr
95cbadd277 Update Hungarian translation 2025-09-01 14:01:03 +00:00
Athmane MOKRAOUI
88d6dfea04 Update Kabyle translation 2025-09-01 10:52:51 +00:00
luming zh
6b1834ec9e Update Chinese (China) translation 2025-08-31 23:46:06 +00:00
luming zh
10319fc883 Update Chinese (China) translation 2025-08-31 23:41:43 +00:00
Jehan
624f049e66 Post-release version bump to 3.1.5. 2025-09-01 00:35:08 +02:00
Bruno Lopes
0c5e5c0094 build/windows: Remove last remnant of $GIMP_BASE on Installer script
This completes 87101276
2025-08-31 16:22:30 -03:00
Jehan
50978f18b6 Release GIMP 3.1.4. 2025-08-31 19:24:36 +02:00
Bruno Lopes
cb4316d07a gitlab-ci: Always use the Debian image of our Registry
Some jobs were using the Debian image from Docker Hub registry:
- meson-health
- clang-format
- cppcheck
- sources-debian
- dev-docs
- dist-appimage-weekly

The reason was that we don't need a bigger image suited for builds
($CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER}), but
it relied entirely on luck. If we push too much commits in a day, it
could surpass the Docker Hub limit. So, let's use our own image always.
2025-08-31 13:28:53 -03:00
Jehan
a530892fb5 desktop: update release date. 2025-08-31 18:05:14 +02:00
Jehan
ad3ec69183 NEWS: update.
Forgotten new libgimp/PDB API.
2025-08-31 17:49:24 +02:00
Jehan
6c1c497ce0 libgimpwidgets: fix build warning.
This fixes the following warning when compiling with CLang:

> libgimpwidgets/gimppropwidgets.c:3961:11: warning: variable 'unit_type' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
>  3961 |       if (pspec_unit && GIMP_IS_PARAM_SPEC_UNIT (pspec_unit))

If a unit property name is set, it must be a valid unit property. Let's
check, output a CRITICAL and return NULL otherwise.
2025-08-31 17:49:24 +02:00
Jehan
b1e52381f5 libgimp*, plug-ins: add and use new GIMP_WARNING_API_BREAK() macro.
This macro will generate a #warning message when we'll move on to 3.99
series (which means we will be on our way to GIMP 4). And it will become
an #error message on 4.0.0, hence preventing us from releasing unless we
actually resolve all these warnings.

Resolution may mean actually breaking the API/ABI, or just deciding that
it's not a good idea in the end, or finding another solution. But
something will have to be decided.

Please everyone use this macro when you discover issues where it looks
like we could improve the API (in a breaking way) so that we don't
forget when approaching GIMP 4 (pushing further the improvement).

Updating the 2 place where I was already using a GIMP_CHECK_VERSION()
with #warning, and adding a new usage in the compose plug-in, per
discussion in MR !2424.
2025-08-31 17:49:24 +02:00
Bruno Lopes
27a89a0c8a build/linux: Update exiv2 module to 0.28.7 2025-08-31 12:50:42 -03:00
Jehan
a636aea98d Issue #14781: Moving link layers freezes GIMP.
Though I can't reproduce on Linux, the performance log seems to show we
spend too much time inside filters_actions_update(). Instead of creating
nodes at each update, let's just store the information about which
filter action has pad, since this should not change within the timespan
of a given session.
2025-08-31 11:56:51 -03:00
Bruno Lopes
62727a654c build/windows: Always run 'pacman -Suy' on 'gimp-win' job
Runners do not remember the MSYS2 repo cache between jobs since
they are not relying on any Docker caching.

The problem is that GIMP could link to different lib versions than
babl and GEGL, but that is the way local shell executors work anyway.
2025-08-31 11:58:09 -03:00
Yuri Chornoivan
2e05a4b1d9 Update Ukrainian translation 2025-08-31 14:41:16 +00:00
Alx Sa
0faa10ddd6 plug-ins: Remove metadata on J2K and PSB export
Exiv2 does not yet support metadata export for PSB
and J2K export. For now, we will turn off the metadata
options when exporting in these formats.
2025-08-31 13:22:28 +00:00
Yuri Chornoivan
d16fe453b6 Update Ukrainian translation 2025-08-31 12:50:56 +00:00
Kolbjørn Stuestøl
e5c04e449e Update Norwegian Nynorsk translation 2025-08-31 12:33:19 +00:00
Bruno Lopes
8a3603828b gimp-data: Bump commit to reduce RAM usage on icon scripts 2025-08-31 08:46:38 -03:00
Martin
4b252bddec Update Slovenian translation 2025-08-31 11:29:34 +00:00
Martin
b42ba20657 Update Slovenian translation 2025-08-31 11:21:00 +00:00
Anders Jonsson
c5ddbf5732 Update Swedish translation 2025-08-31 10:26:13 +00:00
Anders Jonsson
1e5be02d8c Update Swedish translation 2025-08-31 09:43:47 +00:00
Alx Sa
cf9d39c3d7 plug-ins: Fix Recompose for YCbCr decomposed images
The strings used in decompose.c's "decompose-type" do not match
the values of compose_type for YCbCr values. This means that when
using non-interactive Recompose, there's no match and the Recompose
fails. We'll need to wait until the next API break to fix the strings.
For now, we will do additional checks if the normal compose_type check
fails and also compare the four YCbCr types from Decompose.
2025-08-31 01:53:28 +00:00
Jehan
1365b8a08b NEWS: update. 2025-08-30 22:30:57 +02:00
Jehan
51ffd78d2a gimp-data: bump to fix Windows 32-bit build job. 2025-08-30 21:47:46 +02:00
Ondřej Míchal
d985b9b377 app: Align edit tool button with text entry
The button for opening the edit panel for editing a brush / gradient /
pressure curves looks misaligned because it is added to the end of the
horizontal box and its icon is aligned to the end of the button instead
of its center.

This adds puts the text entry and the edit button into the same
horizontal box and fixes the image alignment.
2025-08-30 19:10:02 +00:00
Liam Quin (ankh/demib0y/barefootliam)
760ef381fe fix crash on build or startup if extensions file does not exist 2025-08-30 18:41:03 +00:00
Corentin Noël
19e230e9cb plug-ins: Allow for more specific print settings with portals
In the case the "create-custom-widget" signal is not emitted (typically when
using the print portal), it is necessary to open a second dialog to fine-tune
the print settings.
2025-08-30 15:41:49 +00:00
Bruno Lopes
04622852fa build/linux: Update exiv2 module to 0.28.6
Ported from 91e327ab7a
2025-08-30 10:28:51 -03:00
Bruno Lopes
2f6b75913b Issue #14461: build/linux: Patch mypaint-brushes module with 'gridmap'
Alex's patch from https://github.com/mypaint/mypaint-brushes/pull/7

Since mypaint project is long time gone, we need to patch ourserves.
2025-08-30 10:25:03 -03:00
Jehan
883498916a desktop: update release date. 2025-08-30 14:01:22 +02:00
Jehan
8e2a0381d7 app: generalize code for filter action sensitivity.
Remove most of the per-action special-casing. This won't scale, and in
fact it already doesn't work well with all generated actions from GEGL
operations. Considering that any third-party operation will generate an
action too, this just can't work.

Instead we know that:

- Filters on group, vector and link layers must always be run
  non-destructively.
- Non-interactive filters are always run destructively and therefore
  cannot be run on group, vector or link layers.
- GEGL graph as well, unless a specific environment is set.
- All operations with auxiliary inputs cannot be run non-destructively
  (yet) either and therefore must also be deactivated on these layer
  types.

A few more actions are still special-cased (in particular regarding
being used on grayscale drawable or on formats with an alpha channel),
though it would be nice if we could generalize these somehow eventually
too.
2025-08-30 13:58:02 +02:00
Jehan
c732dfd4ca gimp-data: new splash image. 2025-08-30 13:00:18 +02:00
Jehan
38c379cd92 app: properly forbid paint tools to draw on link layers and forbid…
… filter tools to merge filters, both on link and vector layers.
2025-08-30 10:12:17 +02:00
Jehan
9a780bc7d4 app: missing break!
Argh! This got broken in commit 6e91826865.
2025-08-30 09:46:06 +02:00
Jehan
db18d739e5 app: cleanly downgrade link layers with NULL links.
This will be a bit more robust to potentially invalid files with a NULL
link.
2025-08-30 09:42:15 +02:00
Jehan
2c44689fe2 app, po: localize various strings which were blocked by string freeze. 2025-08-30 09:15:28 +02:00
Bruno Lopes
cc4821ffcb build/windows: Make $store_changelog handle <li demo=""> 2025-08-29 09:05:59 -03:00
Jehan
35b972c854 app, desktop: update demo tour for vector layers. 2025-08-29 13:15:24 +02:00
Asier Saratsua Garmendia
2a3d54bee9 Update Basque translation 2025-08-29 09:15:18 +00:00
Asier Saratsua Garmendia
c0d2a7fadd Update Basque translation 2025-08-29 08:47:23 +00:00
Asier Saratsua Garmendia
a5aaed7929 Update Basque translation 2025-08-29 08:22:22 +00:00
Jehan
4ed035affd gimp-data: bump to fix building with old librsvg (#14544). 2025-08-28 23:33:49 +02:00
Jehan
44d90a389e NEWS: update. 2025-08-28 23:20:44 +02:00
Jehan
4f3aee5e83 Issue #14759: link layers (of vector files) initial dimensions will fill…
… the whole canvas while keeping aspect ratio of the source image.

The previous dimensions were not entirely "out of the blue" since they
were taken from the file, but very often dimensions from vector images
are kinda bogus (apart from aspect ratio, they don't mean much) anyway.

Now we will just fill the canvas box by default.

When changing the source file of an existing link layer though (through
Link Layer properties), the dimensions will be within the current layer
bounding box.

Also I realized that we need to also store the link width/height in the
XCF because the buffer width/height may not be right (in case a
transform matrix was applied). This commit therefore breaks XCF file
with link layers made in the last 2 days. Since we have not made even a
dev release, it's probably fine to do this and not bump the XCF version.
2025-08-28 23:13:03 +02:00
Jehan
9519901150 libgimp, plug-ins: implement loading SVG breaking aspect ratio.
Previous implementation was always keeping ratio. If the width/height
argument were of a different aspect, librsvg simply fits the image with
original aspect within the box. Now we will appropriately scale
differently on both dimensions to have the image fill the whole box.

Note that this doesn't work with librsvg before 2.46.0 (not that it's
not possible, just that I haven't looked at how it should be implemented
there (which would be a different implementation anyway since there is
no cairo step).

Finally I add a build warning for when we'll prepare for GIMP 4, as the
pixel density arg needs to be split in 2 (each dimension can have its
own PPI), even though this is not really needed right now.
2025-08-28 23:13:03 +02:00
Jehan
d8712a525b plug-ins: fix compilation with librsvg < 2.46.0.
Note that it's not actually tested with an old librsvg, but only forcing
this code path with a new librsvg and fixing the compilation
errors/warnings which are outputted.
2025-08-28 23:13:03 +02:00
Jacob Boerema
640fb89f13 libgimpbase: improve parasite API documentation 2025-08-28 16:00:56 -04:00
Jacob Boerema
24ca35625b app: add "..." to Fill/Stroke command
Since it opens a dialog it should have ... at the end
2025-08-28 13:18:32 -04:00
Jacob Boerema
769b911018 app: add help ids for vector layer commands 2025-08-28 13:17:16 -04:00
Jacob Boerema
84b450b7bd app: Give Open as Link Layer it's own help id
Each menu command should have its own help id, so we define a new
help id for opening a link layer.
2025-08-28 12:18:05 -04:00
Bruno Lopes
4ec1368af9 build/linux: Remove 'x-checker-data' while not on stable Ghostscript
Following faf0fd74
2025-08-28 12:16:14 -03:00
Alx Sa
520aeacd8c widgets: Follow theme mode on Critical Dialog (Win)
Following the improvement in fe4cbb65, the Critical Dialogue
uses the native titlebar in Windows. This means it no longer
adapts to dark and light mode automatically.
Since we don't want GimpCriticalDialog to be dependent on
internal GIMP code, this patch copies over the fallback code
in gimp_window_set_title_bar_theme () (which sets the title bar
based on the background color) when the dialogue is realized.
2025-08-28 03:50:21 +00:00
Bruno Lopes
0fb3c8bb67 gimp-data: Bump commit again to drop UNIX-only EX_SOFTWARE 2025-08-27 22:01:38 -03:00
Bruno Lopes
1f0f8d1a2c gimp-data: Bump gimp-data to reduce stuckness on Windows 2025-08-27 21:46:59 -03:00
Bruno Lopes
be667ac007 app/core: Declare libarchive dependency introduced by 6597dabe
Otherwise, the '-I' param will not be set and Apple Clang will
fail on exotic environments like Homebrew on
which not everything is in the common 'includedir'.
2025-08-27 16:38:10 -03:00
Jehan
16a1283f07 Issue #14758: link layers resize can not be undone. 2025-08-27 19:36:02 +02:00
Jehan
1f79e4314e Issue #14760: fix wrong offset when scaling a link layer.
This commit also makes the scaling detection a bit more forgiving to
"imperfect" scale matrix by using an epsilon low enough that it probably
won't make much of a big difference, transform-wise, while it would make
a big difference quality-wise.
2025-08-27 19:35:56 +02:00
Jacob Boerema
55627934c5 plug-ins: add more file plug-in loading tests
Adds a few tga, j2k, wbmp and wmf tests.
2025-08-27 11:11:32 -04:00
Alx Sa
61c67d012b plug-ins: Fix CRITICALs and GUI issues in file-ps
Resolves #14761 (and other issues)
* Clears out the selection on GimpPageSelector on load so
that it does not try to "redraw" areas when the dialogue is closed
* Fixes layout on load dialogue to better match 2.10 (and use less
vertical space)
* Now that we have a unit property, replace the call to
gimp_label_string_widget_get_widget () with a direct connection to
changes in the config's "unit". This both fixes a CRITICAL caused by
setting a signal on a non-existent object, and restores the function
that adjusts the dimensions when the unit is changed from inches to
millimeters and back.
2025-08-27 13:02:59 +00:00
Ondřej Míchal
faf0fd7401 build/linux: Re-add ghostscript using a new release candidate
This is not a full new release but we might as well test the new
release-candidate to see if it fixes the build issues with GCC 15.

Partially reverts 4ae861f5ac
2025-08-27 09:39:49 -03:00
Gabriele Barbero
eeeaca928b tools: implement shortcuts in text tool...
...for toggle bold/italic/underline.

This commit adds support for common formatting shortcuts in the Text Tool:
- Ctrl+B: Toggle bold
- Ctrl+I: Toggle italic
- Ctrl+U: Toggle underline
2025-08-27 11:21:51 +00:00
Jehan
73979309ab po: add new localized source files.
Thanks to Anders for reminding me!
2025-08-27 11:34:04 +02:00
Jehan
97bf7e1bfa app: rework load/save of link layers.
- We now bump to XCF version 25 since vector layers were implemented in
  XCF 24.
- Fix some now broken code in saving/loading, also rename
  PROP_LINK_LAYER_DATA to simply PROP_LINK_LAYER and use the generic
  gimp_layer_from_layer() which I created in commit afb8867bce and is
  also used for text and vector layers.
- Add a PROP_TRANSFORM layer property. It is separate from
  PROP_LINK_LAYER because I will likely reuse this for other (all even)
  types of layers as well.
2025-08-27 11:34:04 +02:00
Jehan
95f1d768c3 app: link layers must still have a converted buffer.
Otherwise we may end up with discrepancy such as layers having a u8
buffer on a u16 image.
2025-08-27 11:34:04 +02:00
Jehan
66cdecb0fa app, menus, pdb: new file-open-as-link-layers action.
Revert the logic of opening all files as link layers back into loading
their current content as normal layers.
Instead just add a new action dedicated to open images as link layers
and add it to the File menu.

Per UX discussions with Aryeom.
2025-08-27 11:34:04 +02:00
Jehan
8280058c5a app: properly reapply the transform matrix after link layer source updated.
Also make sure that a link layer duplicate shows the proper contents
too!
2025-08-27 11:34:04 +02:00
Jehan
2821dbab58 app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.

For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!

Note nevertheless the following limitations in current implementation:

* The link layer with transformations will still show as a standard link
  layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
  the link info, then monitor the link again. A specific action in the
  contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
  perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
  will it work for the Transform actions. I will need to implement
  GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
  made any tests with layer masks yet, but this should be done next
  too).
* I think that the "scaled-only" property is now meaningless. It is now
  being replaced by the presence of the GimpMatrix3. Nevertheless I have
  still not removed this property.
* The load/save code has not been redone yet to include all these
  changes.

The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):

* Any intermediate interpolation methods are dropped when cumulating
  transform steps. Only the last interpolation is stored. This is
  because anyway the interpolation is only there as the best algorithm
  where we visually see the less quality loss. Applying several
  transformations as a single matrix will always be visually better than
  applying several matrices (whatever the intermediate interpolation
  methods chosen).
* This only works with the "Adjust" clipping method (basically no
  clipping) because 2 transform steps with clipping won't produce the
  same result as the multiplied matrix with clipping. It means that
  applying a transform with clipping will downgrade your link layer to
  being a normal layer.
  The only issue I have with this is how to best convey that clipping is
  a major setting setting here, which disables our less-destructive
  abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
  non/less-destructivity transforms. In particular any scaling (both
  through "Scale Image", "Scale Layers" and transform tools — since I
  added code to detect a matrix doing only scaling and optionally
  translation) done **first** will be completely non-destructive since
  we will simply reload the original vector source at the right
  dimensions. Any other kind of transforms will be appended through the
  cumulative matrix, as raster link layers. This also includes scaling
  done **after** other transforms, since we cannot easily move the
  scaling first (matrix multiplication is not commutative). This second
  level of scaling will therefore be *less* destructive, but still
  destructive.
  It is possible eventually to improve the whole thing if we add some
  day the ability to request loading a vector image with a transform
  matrix (it will then be up to each vector format plug-in to support
  this feature or not).

Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-27 11:34:04 +02:00
Jehan
7c7587bb2d app: replace #ifndef/#define macros by #pragma once. 2025-08-27 11:34:04 +02:00
Jehan
3e5fce27cb app: move logic to know if a link layer is being monitored to GimpLink.
Instead of keeping a "modified" property in GimpLinkLayer, we just check
if the link is being monitored. It's also a better wording because we
may "discard the link information" without actually modifying the layer
pixels.

Also I now actually shut down the file monitoring process. This can be a
bit expensive so when we don't need it, let's really free the
GFileMonitor.

This commit also fixes scaling of link layer (which got broken along the
way) and improves the undo code.

Note: I'll probably want to modify the XCF flags, but let's do this in
the end, depending on further changes too.
2025-08-27 11:34:04 +02:00
Jehan
4128c789f9 app: more efficient GimpLink rendering.
We now re-render a link (by loading its file) immediately upon setting
the new file, i.e. during the calls of gimp_link_new() or
gimp_link_set_file(). As part of this change:

* A GimpLink now stores a GeglBuffer. And this is changed each time a
  file change happens (per the GFileMonitor). In particular that also
  means that gimp_link_get_buffer() does not reload the image file at
  each call for no reasons, and gimp_link_is_broken() does not have a
  `recheck` argument either. This is much more efficient.
* These 2 functions also have a GimpProgress and GError now. We use this
  among other things to pass on a specific GimpProgress object. In
  particular, the image file dialogs now show correct loading
  progression again.
* As a general rule, the code is less confusing as we don't have to
  wonder whether a GimpLink is ready. We can assume it always is, from
  now on.

Note that gimp_link_duplicate() does not trigger a reload of the image
file. Since we assume that the source GimpLink is supposed to be
up-to-date already, we just copy its buffer as-is as an optimization.
2025-08-27 11:34:04 +02:00
Jehan
0b8397ff56 app: "Discard Links" and undo should trigger thumbnail update.
Even if no actual drawable change may have happen, let's manually
trigger an "update" signal, hence triggering thumbnail updates too, but
also contextual menu update in the Layers dockable.
2025-08-27 11:34:04 +02:00
Jehan
9b0f426fbd app: all images (except remote files, XCF and compressed XCF) opened as links.
This is still mostly a test of workflow. It is based on the idea that
link layers are normal yet enhanced layers: eventually we should be able
to have some improved less-destructive scaling/rotation (even without
NDE transform effects); you can manually drop the link anytime anyway
(hence getting back to the good old fully destructive workflow); any
pixel editing automatically drops the link too.

Now this still raises quite a lot of questions:

* The link can be confusing to people used to the old way and they may
  not realize that editing the original file separately would also
  update the render in this file (which may not be what they wanted;
  maybe they just wanted to grab a snapshot of this file at a given
  time).
* You could also want to link XCF files.
* You could also want to link remote files (especially in a controlled
  network environment).
* Linked images are currently taken as a whole; we definitely want layer
  support to handle multi-layer image formats (so that you could link
  only a single layer, or a collection of layers; do we want to be able
  to edit visibility of linked layers separately too? Would be neat). So
  how would we handle automatic linking when opening a file? Maybe we
  just reproduce the layer structure as link layers (one link layer
  monitoring only one layer from the linked file)?

Anyway this is work-in-progress, UX-wise.
2025-08-27 11:34:04 +02:00
Jehan
674939e225 app, libgimpbase, pdb: rework layer dialog.
This commit changes the following:

- It's now possible to set whether to store an absolute or relative path
  when editing link layer properties.
- New layer dialog doesn't propose an "Image link" fill type anymore.
  Link layers won't be created this way (see in a future commit).
2025-08-27 11:34:04 +02:00
Jehan
a60487aedd app: link layers can now be stored with relative or absolute paths.
By default, we set them as relative paths. This seems like the more
practical and allows for relocatable folders when one work with project
folders containing all their assets.

We don't have yet a way to set this to being absolute path, but it will
come in a further commit.
2025-08-27 11:34:04 +02:00
Jehan
2dac66d979 app: fix gimp_link_layer_duplicate() for modified link layers. 2025-08-27 11:34:04 +02:00
Jehan
f4a2158458 app: scale linked raster images back from source file.
Unless other types of edits have been done on a link layer (e.g.
painting), we avoid quality loss by multiple scaling of raster link
layers by always re-scaling from the source file.
2025-08-27 11:34:04 +02:00
Jehan
28bf061f4d app: properly handle vector images as link layers.
This commit was edited after GIMP 3.0, now that we have dedicated
support for loading vector images with GimpVectorLoadProcedure.

- By default, when loaded as GimpLinkLayer, vector images are loaded at
  a size so that they are exactly contained in the image.
- When scaled with Scale Layer dialog, link layers of type vector are
  re-loaded from the source file to always stay perfectly crisp.
2025-08-27 11:34:03 +02:00
Jehan
0b5aa01bb9 app: more rebasing after GIMP 3.0 release. 2025-08-27 11:34:03 +02:00
Jehan
f45244f991 app: fix branch after rebasing.
return_if_no_layer() doesn't exist anymore. The 2 layers actions are now
multi-layer aware.
2025-08-27 11:34:03 +02:00
Jehan
39185d43ba app: GimpLink should emit "changed" signal idly.
Even though G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT should normally
happen when we are *probably* at the last change of a set of changes,
the keyword is clearly *probably* as I had 5 or 6 of these events when
saving a single image.

There is no need for our link layer to reload a same image that many
times in under a second. Instead, just emit our "changed" signal in an
idly source to avoid uselessly duplicating events.
2025-08-27 11:34:03 +02:00
Jehan
6c86e80019 app: port branch to meson. 2025-08-27 11:34:03 +02:00
Jehan
3e6fed839a app: salvage link layers of dimension 0.
Similar to commit 06be074650, but now for
link layers. Their dimension are also determined by their contents so
anyway let's be more resistant from some forms of file corruption.
2025-08-27 11:34:03 +02:00
Jehan
6e91826865 app: add saving/loading of link layers. 2025-08-27 11:34:03 +02:00
Jehan
20083bcabe app: new link layers.
These are layers who content depends on another source (right now only
an external image). This can be useful when for instance working at
several people on a single artwork, hence being able to load new
versions of an image without even touching anything in the XCF (for
instance, say you draw an animated character while someone else is
taking care of the background).

Similarly to what we do for text layers, once you start modifying the
contents, it turns into a "normal" layer. The link information is still
available though, so it is possible to revert to the monitoring state
with the menu item "Monitor Linked Image" which appear when a link layer
became a normal layer.

This is not finale as I'm still experimenting. In particular, I have not
implemented XCF saving/loading yet for this new layer type.
2025-08-27 11:34:03 +02:00
Jehan
ac63b1d8fb app: new GimpLink object.
A GimpLink is just a class monitoring an image file and sending a
"changed" signal when it changes. This will be used to implement link
layers, whose contents is based on an external file.
This is only a simple first version. Future versions may also allow to
monitor specific layers in an image file, or a layer in the same XCF
image which you'd want to link instead of duplicating it.
2025-08-27 11:34:03 +02:00
Asier Saratsua Garmendia
d1dca0a881 Update Basque translation 2025-08-27 08:00:58 +00:00
Asier Sarasua Garmendia
8a771a2a51 Update Basque translation 2025-08-27 07:54:51 +00:00
Ondřej Míchal
33f6117539 plug-ins/filter-browser: Remove Pippins's copyright
This note was relevant when the plug-in used GEGL code for collecting
available GEGL operations. This is no longer the case and thus the
copyright can be dropped.
2025-08-26 23:50:37 +00:00
Jehan
b80a2341cf NEWS: update. 2025-08-27 00:07:12 +02:00
Cristian Secară
3ad4b063b0 Update Romanian translation 2025-08-26 18:40:05 +00:00
Ekaterine Papava
de2b54faa6 Update Georgian translation 2025-08-24 11:49:21 +00:00
331 changed files with 86878 additions and 66591 deletions

View File

@@ -13,7 +13,7 @@ spec:
test_pipeline:
description: 'Pipelines used only for testing'
options:
- GIMP_CI_MESON_GCC #trigger the Debian GCC build (rare usefulness)
- GIMP_CI_MESON_CLANG #trigger the Debian Clang build (rare usefulness)
- GIMP_CI_RASTER_ICONS #trigger the Debian Clang build without vector icons (rare usefulness)
- GIMP_CI_CPPCHECK #trigger cppcheck (static code analysis)
- none
@@ -30,7 +30,7 @@ workflow:
##################################################
## 1. On MERGE REQUESTS, the following are triggered:
## - Abbreviated Linux Clang build
## - Abbreviated Linux build
## - Building quality tests (static code analysis)
## - clang-format (static code analysis)
## - Execution tests (dynamic code analysis)
@@ -44,7 +44,7 @@ workflow:
# GitLab is quite sensitive about rules 'if' order so be careful
## 3. On COMMITS except tags.
## - Linux Clang build
## - Linux build
## - Building quality tests (static code analysis)
## - Execution tests (dynamic code analysis)
## - Source tarball
@@ -81,9 +81,11 @@ workflow:
- 'scheduler_failure'
needs: []
# Default Docker image (keep variables: DEB_VERSION: consistent with devel-docs/os-support.txt)
image: debian:${DEB_VERSION}
image: $CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER}
variables:
DEB_VERSION: "bookworm"
UMFPACK: libumfpack5
RUNNER: "x86_64_v3"
# Common cloning procedure
GIT_DEPTH: "1"
GIT_SUBMODULE_STRATEGY: none
@@ -101,28 +103,30 @@ stages:
- analysis
- distribution
## AppImage CI (Debian) ##
.debian:
## Common GNU/Linux 64-bit CI (Debian) ##
.debian-nonreloc:
extends: .default
rules:
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*Package:AppImage.*/'
interruptible: true
- if: '$GIMP_CI_APPIMAGE != null || "$[[ inputs.distribution_pipeline ]]" =~ /.*GIMP_CI_APPIMAGE.*/'
- <<: *CI_MERGE
- <<: *CI_COMMIT
variables: {}
- if: '$GIMP_CI_MESON_CLANG != null || "$[[ inputs.test_pipeline ]]" =~ /.*GIMP_CI_MESON_CLANG.*/'
variables:
CC: clang
CXX: clang++
CC_LD: lld
CXX_LD: lld
TOOLCHAIN: "clang lld"
VARIANT: -clang
- if: '$GIMP_CI_RASTER_ICONS != null || "$[[ inputs.test_pipeline ]]" =~ /.*GIMP_CI_RASTER_ICONS.*/'
variables:
MESON_OPTIONS: "-Dvector-icons=false"
VARIANT: "-raster"
- <<: *CI_RELEASE
parallel:
matrix:
- RUNNER: [aarch64, x86_64_v3]
tags:
- $RUNNER
image: $CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER}
variables:
CC: "clang"
CXX: "clang++"
CC_LD: lld
CXX_LD: lld
before_script:
- export GIMP_PREFIX="${CI_PROJECT_DIR}/_install-${RUNNER}"
timeout: 20m
timeout: 30m
.debian_environ: &ENVIRON
# See: https://testing.developer.gimp.org/core/setup/build/#preparing-for-building
@@ -138,19 +142,16 @@ stages:
- export GI_TYPELIB_PATH="${GIMP_PREFIX}/${LIB_DIR}/${LIB_SUBDIR}girepository-1.0${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}"
- printf "\e[0Ksection_end:`date +%s`:environ\r\e[0K\n"
deps-debian:
extends: .debian
deps-debian-nonreloc:
extends: .debian-nonreloc
stage: dependencies
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
image: quay.io/buildah/stable
variables:
GIT_STRATEGY: none
PKGCONF_RELOCATABLE_OPTION: '-Dpkgconfig.relocatable=true'
script:
- export container=docker
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- export BUILDAH_FORMAT=docker
- export STORAGE_DRIVER=vfs
- echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
# Install deps
- echo "FROM debian:${DEB_VERSION}" > Dockerfile
- echo "WORKDIR $CI_PROJECT_DIR" >> Dockerfile
@@ -160,16 +161,15 @@ deps-debian:
- echo "RUN apt-get install -qq -y --no-install-recommends ca-certificates" >> Dockerfile
## Build-time only dependencies
- echo "RUN apt-get install -qq -y --no-install-recommends \\" >> Dockerfile
- echo "appstream
- echo "${TOOLCHAIN:-build-essential}
appstream
bison
clang
desktop-file-utils
flex
gi-docgen
git
gobject-introspection
libgtk-3-bin
lld
meson
valac
xsltproc" >> Dockerfile
@@ -182,6 +182,7 @@ deps-debian:
glib-networking
graphviz
graphviz-dev
gvfs
iso-codes
libaa1-dev
libappstream-dev
@@ -195,6 +196,7 @@ deps-debian:
libgtk-3-dev
libgudev-1.0-dev
libheif-dev
$LIBHEIF_PLUGINS
libjson-glib-dev
libjxl-dev
liblcms2-dev
@@ -210,7 +212,7 @@ deps-debian:
librsvg2-dev
libsuitesparse-dev
libtiff-dev
libumfpack5
$UMFPACK
libunwind-dev
libwebp-dev
libwmf-dev
@@ -227,10 +229,12 @@ deps-debian:
- echo "RUN printf \"\e[0Ksection_start:`date +%s`:environ[collapsed=true]\r\e[0KPreparing build environment\n\"" >> Dockerfile2;
- echo "ENV PKG_CONFIG_PATH=\"${GIMP_PREFIX}/lib/$([ "$(uname -m)" = 'aarch64' ] && echo "aarch64-linux-gnu/" || echo "x86_64-linux-gnu/")pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}\"" >> Dockerfile2;
- echo "ENV XDG_DATA_DIRS=\"${GIMP_PREFIX}/share:/usr/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}\"" >> Dockerfile2;
- echo "ENV CC=\"$CC\"" >> Dockerfile2;
- echo "ENV CXX=\"$CXX\"" >> Dockerfile2;
- echo "ENV CC_LD=\"$CC_LD\"" >> Dockerfile2;
- echo "ENV CXX_LD=\"$CXX_LD\"" >> Dockerfile2;
- if [ "$VARIANT" = "-clang" ]; then
echo "ENV CC=\"$CC\"" >> Dockerfile2;
echo "ENV CXX=\"$CXX\"" >> Dockerfile2;
echo "ENV CC_LD=\"$CC_LD\"" >> Dockerfile2;
echo "ENV CXX_LD=\"$CXX_LD\"" >> Dockerfile2;
fi
- echo "ENV CLICOLOR_FORCE=\"1\"" >> Dockerfile2;
- echo "RUN printf \"\e[0Ksection_end:`date +%s`:environ\r\e[0K\n\"" >> Dockerfile2;
# Build some dependencies
@@ -248,8 +252,9 @@ deps-debian:
- echo "RUN ninja -C gegl/_build-${RUNNER}" >> Dockerfile2;
- echo "RUN ninja -C gegl/_build-${RUNNER} install" >> Dockerfile2;
- echo "RUN printf \"\e[0Ksection_end:`date +%s`:gegl_build\r\e[0K\n\"" >> Dockerfile2;
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER} --cache=true --cache-ttl=120h --image-fs-extract-retry 1 --verbosity=warn
- if [ -f 'Dockerfile2' ]; then /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile2 --destination build-debian-${DEB_VERSION}-${RUNNER}-temp --cache=false --no-push --verbosity=warn; fi
#FIXME: '2>&1 | grep -v STEP' since buildah is too verbose. See: https://github.com/containers/buildah/issues/6362
- buildah build --log-level error --volume $CI_PROJECT_DIR:$CI_PROJECT_DIR:Z --file $CI_PROJECT_DIR/Dockerfile --tag $CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER} --layers --cache-from $CI_REGISTRY_IMAGE/cache --cache-to $CI_REGISTRY_IMAGE/cache --cache-ttl=120h 2>&1 | grep -v STEP && buildah push --log-level error $CI_REGISTRY_IMAGE:build-debian-${DEB_VERSION}-${RUNNER} 2>&1 | grep -v STEP
- buildah build --log-level error --volume $CI_PROJECT_DIR:$CI_PROJECT_DIR:Z --file $CI_PROJECT_DIR/Dockerfile2 --no-cache 2>&1 | grep -v STEP
artifacts:
paths:
- _install-${RUNNER}/
@@ -259,11 +264,88 @@ deps-debian:
- gegl/_build-${RUNNER}/config.h
expire_in: 2 hours
gimp-debian-nonreloc:
extends: .debian-nonreloc
needs: ["deps-debian-nonreloc"]
stage: build
variables:
GIT_SUBMODULE_STRATEGY: recursive
script:
- *ENVIRON
# Check building
- printf "\e[0Ksection_start:`date +%s`:gimp_build[collapsed=true]\r\e[0KBuilding GIMP\n"
- meson setup _build-${RUNNER} -Dprefix="${GIMP_PREFIX}"
-Dfile-plug-ins-test=true
$MESON_OPTIONS
- cd _build-${RUNNER}
- ninja
- printf "\e[0Ksection_end:`date +%s`:gimp_build\r\e[0K\n"
# Check execution
- printf "\e[0Ksection_start:`date +%s`:gimp_test[collapsed=true]\r\e[0KTesting GIMP execution\n"
- ninja test
- printf "\e[0Ksection_end:`date +%s`:gimp_test\r\e[0K\n"
# Check source
- printf "\e[0Ksection_start:`date +%s`:gimp_tar[collapsed=true]\r\e[0KChecking GIMP source\n"
- if [ $(git diff |wc -l) -ne 0 ]; then
printf "ERROR. A generated file was updated without the source:\n";
git diff;
exit 1;
fi
- if [ "$VARIANT" != "-clang" ] && [ "$VARIANT" != "-raster" ] && [ "$CI_PIPELINE_SOURCE" != "merge_request_event" ]; then
ninja dist > ninja_dist.log 2>&1 || { cat ninja_dist.log; exit 1; };
fi
- printf "\e[0Ksection_end:`date +%s`:gimp_tar\r\e[0K\n"
# Check install
- printf "\e[0Ksection_start:`date +%s`:gimp_install[collapsed=true]\r\e[0KChecking GIMP installation\n"
- ninja install > ninja_install.log 2>&1 || { cat ninja_install.log; exit 1; };
- printf "\e[0Ksection_end:`date +%s`:gimp_install\r\e[0K\n"
artifacts:
paths:
- _install-${RUNNER}/
- _build-${RUNNER}/meson-logs/meson-log.txt
- _build-${RUNNER}/meson-dist/
- _build-${RUNNER}/config.h
reports:
junit: "_build-${RUNNER}/meson-logs/testlog.junit.xml"
expire_in: 2 days
## AppImage CI (Debian) ##
.debian:
extends: .debian-nonreloc
rules:
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*Package:AppImage.*/'
interruptible: true
- if: '$GIMP_CI_APPIMAGE != null || "$[[ inputs.distribution_pipeline ]]" =~ /.*GIMP_CI_APPIMAGE.*/'
- <<: *CI_RELEASE
parallel:
matrix:
- RUNNER: [aarch64, x86_64_v3]
tags:
- $RUNNER
variables:
#FIXME: remove this variables: key and go back to relying on .default DEB_VERSION on GIMP 3.3/3.4
DEB_VERSION: "trixie"
UMFPACK: libumfpack6
LIBHEIF_PLUGINS: "libheif-plugin-dav1d libheif-plugin-aomenc libheif-plugin-libde265 libheif-plugin-x265 libheif-plugin-j2kdec libheif-plugin-j2kenc"
deps-debian:
extends: .debian
stage: !reference [deps-debian-nonreloc, stage]
image: !reference [deps-debian-nonreloc, image]
variables:
GIT_STRATEGY: none
PKGCONF_RELOCATABLE_OPTION: '-Dpkgconfig.relocatable=true'
script:
- !reference [deps-debian-nonreloc, script]
artifacts: !reference [deps-debian-nonreloc, artifacts]
gimp-debian:
extends: .debian
needs: ["deps-debian"]
stage: build
stage: !reference [gimp-debian-nonreloc, stage]
variables:
#FIXME: remove this variables: key and go back to relying on gimp-debian-nonreloc variables: on GIMP 3.3/3.4
GIT_SUBMODULE_STRATEGY: recursive
script:
- *ENVIRON
@@ -293,85 +375,6 @@ gimp-debian:
expire_in: 2 days
## GNU/Linux 64-bit CIs (Debian) ##
.debian-nonreloc:
extends: .debian
rules:
- <<: *CI_MERGE
- <<: *CI_COMMIT
variables: {}
- if: '$GIMP_CI_MESON_GCC != null || "$[[ inputs.test_pipeline ]]" =~ /.*GIMP_CI_MESON_GCC.*/'
variables:
CC: "cc"
CXX: "c++"
CC_LD: bfd
CXX_LD: bfd
VARIANT: "-gcc"
- if: '$GIMP_CI_RASTER_ICONS != null || "$[[ inputs.test_pipeline ]]" =~ /.*GIMP_CI_RASTER_ICONS.*/'
variables:
MESON_OPTIONS: "-Dvector-icons=false"
VARIANT: "-raster"
- <<: *CI_RELEASE
parallel:
matrix:
- RUNNER: x86_64_v3
tags: []
deps-debian-nonreloc:
extends: .debian-nonreloc
stage: !reference [deps-debian, stage]
image: !reference [deps-debian, image]
variables:
GIT_STRATEGY: none
script:
- !reference [deps-debian, script]
artifacts: !reference [deps-debian, artifacts]
gimp-debian-nonreloc:
extends: .debian-nonreloc
needs: ["deps-debian-nonreloc"]
stage: !reference [gimp-debian, stage]
variables: !reference [gimp-debian, variables]
script:
- *ENVIRON
# Check building
- printf "\e[0Ksection_start:`date +%s`:gimp_build[collapsed=true]\r\e[0KBuilding GIMP\n"
- meson setup _build-${RUNNER} -Dprefix="${GIMP_PREFIX}"
-Dfile-plug-ins-test=true
$MESON_OPTIONS
- cd _build-${RUNNER}
- ninja
- printf "\e[0Ksection_end:`date +%s`:gimp_build\r\e[0K\n"
# Check execution
- printf "\e[0Ksection_start:`date +%s`:gimp_test[collapsed=true]\r\e[0KTesting GIMP execution\n"
- ninja test
- printf "\e[0Ksection_end:`date +%s`:gimp_test\r\e[0K\n"
# Check source
- printf "\e[0Ksection_start:`date +%s`:gimp_tar[collapsed=true]\r\e[0KChecking GIMP source\n"
- if [ $(git diff |wc -l) -ne 0 ]; then
printf "ERROR. A generated file was updated without the source:\n";
git diff;
exit 1;
fi
- if [ "$VARIANT" != "-gcc" ] && [ "$VARIANT" != "-raster" ] && [ "$CI_PIPELINE_SOURCE" != "merge_request_event" ]; then
ninja dist > ninja_dist.log 2>&1 || { cat ninja_dist.log; exit 1; };
fi
- printf "\e[0Ksection_end:`date +%s`:gimp_tar\r\e[0K\n"
# Check install
- printf "\e[0Ksection_start:`date +%s`:gimp_install[collapsed=true]\r\e[0KChecking GIMP installation\n"
- ninja install > ninja_install.log 2>&1 || { cat ninja_install.log; exit 1; };
- printf "\e[0Ksection_end:`date +%s`:gimp_install\r\e[0K\n"
artifacts:
paths:
- _install-${RUNNER}/
- _build-${RUNNER}/meson-logs/meson-log.txt
- _build-${RUNNER}/meson-dist/
- _build-${RUNNER}/config.h
reports:
junit: "_build-${RUNNER}/meson-logs/testlog.junit.xml"
expire_in: 2 days
## Flatpak CI (Fedora) ##
.flatpak:
extends: .default
@@ -392,7 +395,7 @@ gimp-debian-nonreloc:
MESON_DIST: 0
before_script:
- export GIMP_PREFIX="${CI_PROJECT_DIR}/_install"
timeout: 90m
timeout: 30m
deps-flatpak:
extends: .flatpak
@@ -401,8 +404,7 @@ deps-flatpak:
- sh build/linux/flatpak/1_build-deps-flatpakbuilder.sh
artifacts:
paths:
- _build-$RUNNER.tar
- flatpak-builder.log
- _build-$RUNNER.tar.zst
- babl-meson-log.tar
- gegl-meson-log.tar
expire_in: 2 hours
@@ -440,15 +442,17 @@ gimp-flatpak:
variables:
SNAPCRAFT_BASE_VERSION: "8_core24"
RUNNER: x86_64_v3
timeout: 20m
timeout: 30m
deps-snap:
extends: .snap
stage: dependencies
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
image: quay.io/buildah/stable
script:
- export BUILDAH_FORMAT=docker
- export STORAGE_DRIVER=vfs
- echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
# Install deps
- echo "FROM ghcr.io/canonical/snapcraft:${SNAPCRAFT_BASE_VERSION}" > Dockerfile
- echo "ENTRYPOINT [\"\"]" >> Dockerfile
- echo "WORKDIR $CI_PROJECT_DIR" >> Dockerfile
@@ -464,8 +468,9 @@ deps-snap:
# Build babl and GEGL
- echo "FROM $CI_REGISTRY_IMAGE:build-snap-${SNAPCRAFT_BASE_VERSION}-${RUNNER}" > Dockerfile2;
- echo "RUN sh build/linux/snap/1_build-deps-snapcraft.sh" >> Dockerfile2;
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:build-snap-${SNAPCRAFT_BASE_VERSION}-${RUNNER} --cache=true --cache-ttl=120h --image-fs-extract-retry 1 --verbosity=warn
- if [ -f 'Dockerfile2' ]; then /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile2 --destination build-snap-${SNAPCRAFT_BASE_VERSION}-${RUNNER}-temp --cache=false --no-push --verbosity=warn; fi
#FIXME: '2>&1 | grep -v STEP' since buildah is too verbose. See: https://github.com/containers/buildah/issues/6362
- buildah build --log-level error --volume $CI_PROJECT_DIR:$CI_PROJECT_DIR:Z --file $CI_PROJECT_DIR/Dockerfile --tag $CI_REGISTRY_IMAGE:build-snap-${SNAPCRAFT_BASE_VERSION}-${RUNNER} --layers --cache-from $CI_REGISTRY_IMAGE/cache --cache-to $CI_REGISTRY_IMAGE/cache --cache-ttl=120h 2>&1 | grep -v STEP && buildah push --log-level error $CI_REGISTRY_IMAGE:build-snap-${SNAPCRAFT_BASE_VERSION}-${RUNNER} 2>&1 | grep -v STEP
- buildah build --log-level error --volume $CI_PROJECT_DIR:$CI_PROJECT_DIR:Z --file $CI_PROJECT_DIR/Dockerfile2 --no-cache 2>&1 | grep -v STEP
artifacts:
paths:
- _install-$RUNNER.tar
@@ -527,10 +532,7 @@ gimp-snap:
STORE_OPTION: '-Dms-store=true'
parallel:
matrix:
- RUNNER: windows-aarch64
MSYSTEM_PREFIX: clangarm64
- RUNNER: win32-ps
MSYSTEM_PREFIX: clang64
- RUNNER: [windows-aarch64, win32-ps]
tags:
- $RUNNER
variables:
@@ -538,9 +540,9 @@ gimp-snap:
#meson.build forces non-relocatable .pc. See: https://github.com/mesonbuild/meson/issues/14346
PKGCONF_RELOCATABLE_OPTION: '-Dpkgconfig.relocatable=true'
before_script:
# FIXME:'gimpenv' have buggy code about Windows paths. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/12284
- $GIMP_PREFIX = "$PWD\_install-$MSYSTEM_PREFIX".Replace('\', '/')
timeout: 40m
- if (-not $env:MSYSTEM_PREFIX) { $env:MSYSTEM_PREFIX = if ((Get-WmiObject Win32_ComputerSystem).SystemType -like 'ARM64*') { 'clangarm64' } else { 'clang64' }}
- $GIMP_PREFIX = "$PWD\_install-$env:MSYSTEM_PREFIX"
timeout: 30m
.win_environ: &WIN_ENVIRON
# See: https://testing.developer.gimp.org/core/setup/build/windows/#prepare-for-building
@@ -560,9 +562,9 @@ deps-win:
- build\windows\1_build-deps-msys2.ps1
artifacts:
paths:
- _install-$MSYSTEM_PREFIX/
- babl/_build-$MSYSTEM_PREFIX/meson-logs/meson-log.txt
- gegl/_build-$MSYSTEM_PREFIX/meson-logs/meson-log.txt
- _install-*/
- babl/_build-*/meson-logs/meson-log.txt
- gegl/_build-*/meson-logs/meson-log.txt
expire_in: 2 hours
gimp-win:
@@ -578,14 +580,14 @@ gimp-win:
- build\windows\2_build-gimp-msys2.ps1
artifacts:
paths:
- gimp-$MSYSTEM_PREFIX/
- _build-$MSYSTEM_PREFIX/meson-logs/meson-log.txt
- _build-$MSYSTEM_PREFIX/done-dll.list
- gimp-*/
- _build-*/meson-logs/meson-log.txt
- _build-*/done-dll.list
# Needed by dist-installer-weekly and dist-store-weekly
- _build-$MSYSTEM_PREFIX/config.h
- _build-$MSYSTEM_PREFIX/plug-ins/file_associations.list
- _build-$MSYSTEM_PREFIX/build/windows/installer/
- _build-$MSYSTEM_PREFIX/build/windows/store/
- _build-*/config.h
- _build-*/plug-ins/file_associations.list
- _build-*/build/windows/installer/
- _build-*/build/windows/store/
expire_in: 2 days
@@ -594,12 +596,10 @@ gimp-win:
extends: .win
parallel:
matrix:
- RUNNER: win32-ps
MSYSTEM_PREFIX: mingw32
- RUNNER: [win32-ps]
variables:
MSYSTEM_PREFIX: mingw32
MINGW_PACKAGE_PREFIX: mingw-w64-i686
CC: cc
CXX: c++
deps-win-eol:
extends: .win-eol
@@ -669,6 +669,8 @@ meson-health:
- <<: *CI_MERGE
- <<: *CI_COMMIT
stage: analysis
variables:
GIT_SUBMODULE_STRATEGY: recursive
script:
- apt-get update -qq
- apt-get install -qq -y --no-install-recommends git shellcheck devscripts
@@ -693,6 +695,19 @@ clang-format:
- fetch_origin.log
expire_in: 2 days
branches-check:
extends: .default
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS == null && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
stage: analysis
variables:
GIT_DEPTH: "0"
script:
- apt-get update -qq
- apt-get install -qq -y --no-install-recommends git
- sh .gitlab/check_dead_branches.sh
allow_failure: true
cppcheck:
extends: .default
rules:
@@ -809,6 +824,7 @@ dist-appimage-weekly:
include:
project: GNOME/citemplates
file: flatpak/flatpak_ci_initiative.yml
ref: 42fbc2526a7680b6a4f284a210e63e3973ea6dae
dist-flatpak-weekly:
extends:

View File

@@ -0,0 +1,42 @@
#!/bin/sh
printf "\e[0Ksection_start:`date +%s`:branch_check[collapsed=false]\r\e[0KChecking for dead branches\n"
git branch -r | grep -v 'origin/HEAD' | grep -v "origin/$CI_DEFAULT_BRANCH" | while IFS= read remote_branch; do
remote_branch=$(printf "%s\n" "$remote_branch" | sed 's/^ *//;s/ *$//')
branch_name=$(printf "%s\n" "$remote_branch" | sed 's|origin/||')
# NOT CHECKING
## Skip old stable branches
if echo "$branch_name" | grep -q "^gimp-[0-9]-" || [ "$branch_name" = "gnome-2-2" ] || [ "$branch_name" = "gnome-2-4" ]; then
printf "\033[33m(SKIP)\033[0m: $branch_name is a snapshot of $CI_DEFAULT_BRANCH but no problem\n"
continue
fi
## Skip recently created branches
if [ "$(git rev-parse "$remote_branch")" = "$(git rev-parse "$CI_COMMIT_SHA")" ]; then
printf "\033[33m(SKIP)\033[0m: $branch_name is identical to $CI_DEFAULT_BRANCH but no problem\n"
continue
fi
# CHECKING
## Check: merge-base
if git merge-base --is-ancestor "$remote_branch" "$CI_COMMIT_SHA"; then
printf "\033[31m(ERROR)\033[0m: $branch_name is fully merged into $CI_DEFAULT_BRANCH (via git merge-base)\n"
touch 'dead_branch'
continue
fi
## Fallback check: cherry
cherry_output=$(git cherry "$CI_COMMIT_SHA" "$remote_branch")
if [ -z "$(printf "%s\n" "$cherry_output" | grep '^+')" ]; then
printf "\033[31m(ERROR)\033[0m: $branch_name is fully merged into $CI_DEFAULT_BRANCH (via git cherry)\n"
touch 'dead_branch'
continue
fi
done
if [ -f "dead_branch" ]; then
printf " Please delete the merged branches\n"
exit 1
else
printf '(INFO): All branches are organized.\n'
fi
printf "\e[0Ksection_end:`date +%s`:branch_check\r\e[0K\n"

View File

@@ -24,7 +24,7 @@ https://gitlab.gnome.org/GNOME/gimp/-/issues/?sort=updated_desc&state=all&label_
- "Be considerate and respectful". This is our main rule.
E.g. avoid negative emotional writing which only generates more upsetting
interactions.
- Stay on topic by writting only one bug per report created.
- Stay on topic by writing only one bug per report created.
- Add full (not cropped) screenshots or other files using the clip button on GitLab. -->
### Reproduction

View File

@@ -12,4 +12,4 @@
Only human created works please!
- You can request the devs to allow installable packages to be
generated from this MR by writting ~Package: in the comments -->
generated from this MR by writing ~Package: in the comments -->

View File

@@ -5,7 +5,18 @@
# CHECK SCRIPTS RUNNED BY MESON (ALL OSes)
printf "\e[0Ksection_start:`date +%s`:nonunix_test[collapsed=false]\r\e[0KChecking for non-Unix compatibility\n"
diff=$(git diff -U0 --no-color "${newest_common_ancestor_sha}" -- '*.build' '*.py' | grep -E '^\+[^+]' | sed 's/^+//')
diff=$(git diff -U0 --no-color --submodule=diff "${newest_common_ancestor_sha}" \
| awk '
/^diff --git a\/.*\.(build|py)/ {
sub(/^diff --git a\//, "", $0)
sub(/ b\/.*$/, "", $0)
file = $0
next
}
/^\+[^+]/ && file != "" {
print file ":" substr($0, 2)
}
')
## List of commonly used utilities on Unix world
## See the context: https://gitlab.gnome.org/GNOME/gimp/-/issues/11385
@@ -168,10 +179,21 @@ printf "\e[0Ksection_end:`date +%s`:nonunix_test\r\e[0K\n"
# 1) contain bash shebang or are called by bash;
# 2) contain bashisms.
printf "\e[0Ksection_start:`date +%s`:unix_test[collapsed=false]\r\e[0KChecking for Unix portability (optional)\n"
diff=$(git diff -U0 --no-color "${newest_common_ancestor_sha}" | grep -E '^\+[^+]' | sed 's/^+//')
diff=$(git diff -U0 --no-color --submodule=diff "${newest_common_ancestor_sha}" \
| awk '
/^diff --git a\// {
sub(/^diff --git a\//, "", $0)
sub(/ b\/.*$/, "", $0)
file = $0
next
}
/^\+[^+]/ && file != "" {
print file ":" substr($0, 2)
}
')
## Check shebang and external call (1)
echo "$diff" | grep -E '^#!\s*/usr/bin/env\s+bash|^#!\s*/(usr/bin|bin)/bash(\s|$)' && found_bashism='extrinsic_bashism'
echo "$diff" | grep -E '#!\s*/usr/bin/env\s+bash|#!\s*/(usr/bin|bin)/bash(\s|$)' && found_bashism='extrinsic_bashism'
echo "$diff" | grep -E "bash\s+.*\.sh" && found_bashism='extrinsic_bashism'
## Check content with shellcheck and checkbashisms (2)

View File

@@ -201,7 +201,7 @@ help in that regard:
* HEIC: e.g. libde265 and libx265 support (for
respectively decoding and encoding of HEVC).
* AVIF: e.g. libaom decoder and encoder (for AV1 encoding and
decoding), prefered over rav1e.
decoding), preferred over rav1e.
* HEJ2: OpenJPEG (for JPEG2000 inside HEIF).
If you don't compile libheif with the correct flags (see libheif
@@ -489,5 +489,5 @@ reconfiguration:
% ninja reconfigure
Verify that the optional features you wanted are now shown as `true`,
otherwise follow similar advices than above to make sure they are
otherwise follow similar advice as above to make sure they are
visible to your setup.

109
NEWS
View File

@@ -6,6 +6,82 @@
This is the development branch of GIMP.
Overview of Changes from GIMP 3.1.4 to GIMP 3.2-RC1
===================================================
Core:
- macOS: "Quit" from the dock's right-click menu will now follow our
standard Quit procedure, by intercepting the
applicationShouldTerminate signal, instead of forcing the
application to close (hence losing unsaved changes).
- "Add Layer Mask" will now have an "Edit mask immediately" checkbox
allowing to decide whether to go into Edit Mask state or not. This
setting is saved across repetitive actions, as all other settings in
this dialog.
Graphical User Interface:
- "Monitor Linked Image" and "Discard Link Information" menu items
added to Layer menu when the selected layer is a link layer.
- The GimpColorHexEntry will now update the chosen color as you type.
- Use a standard, yet extended, AppMenu on macOS.
Plug-Ins:
- file-compressor: add zip decompression support. This allows support
for .hgt.zip files, as well as other formats compressed with zip.
API:
- The following libgimpbase API are now deprecated:
* gimp_pixpipe_params_init
* gimp_pixpipe_params_parse
* gimp_pixpipe_params_build
* gimp_pixpipe_params_free
- New libgimp functions:
* gimp_vector_layer_get_enable_fill
* gimp_vector_layer_get_enable_stroke
* gimp_vector_layer_get_fill_color
* gimp_vector_layer_get_path
* gimp_vector_layer_get_stroke_cap_style
* gimp_vector_layer_get_stroke_color
* gimp_vector_layer_get_stroke_dash_offset
* gimp_vector_layer_get_stroke_dash_pattern
* gimp_vector_layer_get_stroke_join_style
* gimp_vector_layer_get_stroke_miter_limit
* gimp_vector_layer_get_stroke_width
* gimp_vector_layer_get_stroke_width_unit
* gimp_vector_layer_set_enable_fill
* gimp_vector_layer_set_enable_stroke
* gimp_vector_layer_set_fill_color
* gimp_vector_layer_set_stroke_cap_style
* gimp_vector_layer_set_stroke_color
* gimp_vector_layer_set_stroke_dash_offset
* gimp_vector_layer_set_stroke_dash_pattern
* gimp_vector_layer_set_stroke_join_style
* gimp_vector_layer_set_stroke_miter_limit
* gimp_vector_layer_set_stroke_width
* gimp_vector_layer_set_stroke_width_unit
* gimp_item_is_vector_layer
* gimp_item_id_is_link_layer
* gimp_item_is_link_layer
* gimp_link_layer_discard
* gimp_link_layer_get_by_id
* gimp_link_layer_get_file
* gimp_link_layer_get_type
* gimp_link_layer_monitor
* gimp_link_layer_new
* gimp_link_layer_set_file
* gimp_param_link_layer_get_type
* gimp_param_spec_link_layer
* gimp_procedure_add_link_layer_argument
* gimp_procedure_add_link_layer_aux_argument
* gimp_procedure_add_link_layer_return_value
* gimp_link_layer_get_mime_type
- New libgimp class: GimpLinkLayer
Overview of Changes from GIMP 3.1.2 to GIMP 3.1.4
=================================================
@@ -41,6 +117,11 @@ Core:
metadata. This new setting is enabled by default.
- Fix palette import to properly import colors with alpha values from
palettes.
- New layer types:
* vector layers
* link layers
- Fill/Stroke editor are now live-previewing color changes for vector
layer fill/stroke and text layer outlines.
Tools:
@@ -49,6 +130,12 @@ Tools:
mypaint-brushes-1.0.
- Seamless Clone (Playground): made to work again, but is still too
slow to move out of Playground.
- The Paths tool has updated UI to create vector layers.
- Text tool: bold, italic and underline can now be applied with
commonly used shortcuts (Ctrl+b, i and u respectively).
- Vector and Link layers cannot be painted on, and filters cannot be
merged on them. They now need to be explicitly downgraded to raster
layers.
Graphical User Interface:
@@ -97,6 +184,10 @@ Plug-Ins:
implemented and removed in 2004).
- Raw Image data plug-in dialog redesigned to be on a two-column
layout to avoid over-high dialog.
- Print: in sandboxed environments (Flatpak, Snap), the print Settings
are now displayed as a second dialog after the portal print dialog.
This 2-step workflow is a work-around to the inability to tweak the
print dialog when the print portal is in use.
API:
@@ -106,6 +197,19 @@ API:
* gimp_drawable_filter_operation_get_available()
* gimp_drawable_filter_operation_get_details()
* gimp_drawable_filter_operation_get_pspecs()
* gimp_context_get_paint_fade_length()
* gimp_context_get_paint_fade_repeat()
* gimp_context_set_paint_fade_length()
* gimp_context_set_paint_fade_repeat()
* gimp_item_id_is_vector_layer()
* gimp_param_spec_vector_layer()
* gimp_procedure_add_vector_layer_argument()
* gimp_procedure_add_vector_layer_aux_argument()
* gimp_procedure_add_vector_layer_return_value()
* gimp_vector_layer_discard()
* gimp_vector_layer_get_by_id()
* gimp_vector_layer_new()
* gimp_vector_layer_refresh()
- GimpSizeEntry (libgimpwidget) can now parse mathematical expressions
in their reference value spin buttons too.
- GimpColorScales (libgimpwidget) will now set its decimals to 0 when
@@ -119,6 +223,8 @@ API:
"charset=[ascii|InvalidCharsetId]" prefixes.
- New GIMP_METADATA_SAVE_UPDATE value in enum type
GimpMetadataSaveFlags (libgimpbase).
- Modernize setting "Exif.Image.DateTime" metadata by setting the
timezone additionally.
Build:
@@ -126,6 +232,9 @@ Build:
- Add nightly Aarch64 flatpak.
- appstream-glib dependency replaced with libappstream
- Installer uses latest InnoSetup now.
- New configure option -Dwin-debugging allowing to choose DWARF debug
symbols on Windows instead of the native (CodeView) symbols. This
will be useful for people wishing to debug with GDB in particular.
Overview of Changes from GIMP 3.0.4 to GIMP 3.1.2

View File

@@ -104,6 +104,7 @@
/* global variables */
GimpActionFactory *global_action_factory = NULL;
GHashTable *aux_filter_hash_table = NULL;
/* private variables */
@@ -270,6 +271,8 @@ actions_init (Gimp *gimp)
action_groups[i].icon_name,
action_groups[i].setup_func,
action_groups[i].update_func);
aux_filter_hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
void
@@ -280,6 +283,23 @@ actions_exit (Gimp *gimp)
g_return_if_fail (global_action_factory->gimp == gimp);
g_clear_object (&global_action_factory);
g_hash_table_unref (aux_filter_hash_table);
}
/* XXX Temporary code to store the list of filter operations with an
* "aux" input. This won't be necessary anymore once these filters can
* be applied non-destructively too in the future.
*/
void
actions_filter_set_aux (const gchar *action_name)
{
g_hash_table_add (aux_filter_hash_table, (gpointer) g_strdup (action_name));
}
gboolean
actions_filter_get_aux (const gchar *action_name)
{
return g_hash_table_lookup (aux_filter_hash_table, action_name) != NULL;
}
Gimp *

View File

@@ -24,6 +24,9 @@ extern GimpActionFactory *global_action_factory;
void actions_init (Gimp *gimp);
void actions_exit (Gimp *gimp);
void actions_filter_set_aux (const gchar *action_name);
gboolean actions_filter_get_aux (const gchar *action_name);
Gimp * action_data_get_gimp (gpointer data);
GimpContext * action_data_get_context (gpointer data);
GimpImage * action_data_get_image (gpointer data);

View File

@@ -307,13 +307,8 @@ gint n_dialogs_dockable_actions = G_N_ELEMENTS (dialogs_dockable_actions);
static const GimpStringActionEntry dialogs_toplevel_actions[] =
{
{ "dialogs-preferences", GIMP_ICON_PREFERENCES_SYSTEM,
#if defined(PLATFORM_OSX)
NC_("dialogs-action", "_Settings..."),
NC_("dialogs-action", "_Settings..."),
#else
NC_("dialogs-action", "_Preferences"),
NC_("dialogs-action", "_Preferences"),
#endif
{ NULL },
NC_("dialogs-action", "Open the preferences dialog"),
"gimp-preferences-dialog",
@@ -360,8 +355,6 @@ static const GimpStringActionEntry dialogs_toplevel_actions[] =
{ "dialogs-about", GIMP_ICON_HELP_ABOUT,
#if defined(G_OS_WIN32)
NC_("dialogs-action", "About GIMP"),
#elif defined(PLATFORM_OSX)
NC_("dialogs-action", "About"),
#else /* UNIX: use GNOME HIG */
NC_("dialogs-action", "_About"),
#endif

View File

@@ -82,6 +82,12 @@ static const GimpActionEntry file_actions[] =
file_open_as_layers_cmd_callback,
GIMP_HELP_FILE_OPEN_AS_LAYER },
{ "file-open-as-link-layers", GIMP_ICON_LAYER,
NC_("file-action", "Op_en as Link Layer..."), NULL, { "<primary><alt><shift>O", NULL },
NC_("file-action", "Open an image file as Link layer"),
file_open_as_link_layer_cmd_callback,
GIMP_HELP_FILE_OPEN_AS_LINK_LAYER },
{ "file-open-location", GIMP_ICON_WEB,
NC_("file-action", "Open _Location..."), NULL, { NULL },
NC_("file-action", "Open an image file from a specified location"),

View File

@@ -73,7 +73,8 @@ static void file_open_dialog_show (Gimp *gimp,
const gchar *title,
GimpImage *image,
GFile *file,
gboolean open_as_layers);
gboolean open_as_layers,
gboolean open_as_link);
static GtkWidget * file_save_dialog_show (Gimp *gimp,
GimpImage *image,
GtkWidget *parent,
@@ -118,7 +119,7 @@ file_open_cmd_callback (GimpAction *action,
file_open_dialog_show (gimp, widget,
_("Open Image"),
image, NULL, FALSE);
image, NULL, FALSE, FALSE);
}
void
@@ -140,7 +141,29 @@ file_open_as_layers_cmd_callback (GimpAction *action,
file_open_dialog_show (gimp, widget,
_("Open Image as Layers"),
image, NULL, TRUE);
image, NULL, TRUE, FALSE);
}
void
file_open_as_link_layer_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
Gimp *gimp;
GtkWidget *widget;
GimpDisplay *display;
GimpImage *image = NULL;
return_if_no_gimp (gimp, data);
return_if_no_widget (widget, data);
display = action_data_get_display (data);
if (display)
image = gimp_display_get_image (display);
file_open_dialog_show (gimp, widget,
_("Open Image as Link Layer"),
image, NULL, TRUE, TRUE);
}
void
@@ -577,7 +600,7 @@ file_file_open_dialog (Gimp *gimp,
{
file_open_dialog_show (gimp, parent,
_("Open Image"),
NULL, file, FALSE);
NULL, file, FALSE, FALSE);
}
@@ -589,7 +612,8 @@ file_open_dialog_show (Gimp *gimp,
const gchar *title,
GimpImage *image,
GFile *file,
gboolean open_as_layers)
gboolean open_as_layers,
gboolean open_as_link)
{
GtkWidget *dialog;
@@ -621,7 +645,7 @@ file_open_dialog_show (Gimp *gimp,
gtk_window_set_title (GTK_WINDOW (dialog), title);
gimp_open_dialog_set_image (GIMP_OPEN_DIALOG (dialog),
image, open_as_layers);
image, open_as_layers, open_as_link);
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (parent)));
@@ -841,9 +865,9 @@ file_revert_confirm_response (GtkWidget *dialog,
new_image = file_open_image (gimp, gimp_get_user_context (gimp),
GIMP_PROGRESS (display),
file, 0, 0, FALSE, NULL,
file, 0, 0, TRUE, FALSE, NULL,
GIMP_RUN_INTERACTIVE,
&status, NULL, &error);
NULL, &status, NULL, &error);
if (new_image)
{

View File

@@ -24,6 +24,9 @@ void file_open_cmd_callback (GimpAction *action,
void file_open_as_layers_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void file_open_as_link_layer_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void file_open_location_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);

View File

@@ -29,13 +29,18 @@
#include "core/gimp-filter-history.h"
#include "core/gimpimage.h"
#include "core/gimpgrouplayer.h"
#include "core/gimplinklayer.h"
#include "core/gimplayermask.h"
#include "path/gimpvectorlayer.h"
#include "pdb/gimpprocedure.h"
#include "widgets/gimpaction.h"
#include "widgets/gimpactiongroup.h"
#include "widgets/gimphelp-ids.h"
#include "widgets/gimpstringaction.h"
#include "widgets/gimpuimanager.h"
#include "widgets/gimpwidgets-utils.h"
@@ -48,11 +53,12 @@
/* local function prototypes */
static void filters_actions_set_tooltips (GimpActionGroup *group,
const GimpStringActionEntry *entries,
gint n_entries);
static void filters_actions_history_changed (Gimp *gimp,
GimpActionGroup *group);
static void filters_actions_set_tooltips (GimpActionGroup *group,
const GimpStringActionEntry *entries,
gint n_entries);
static void filters_actions_history_changed (Gimp *gimp,
GimpActionGroup *group);
static gboolean filters_is_non_interactive (const gchar *action_name);
/* private variables */
@@ -748,6 +754,7 @@ static const GimpEnumActionEntry filters_repeat_actions[] =
void
filters_actions_setup (GimpActionGroup *group)
{
static gboolean first_setup = TRUE;
GimpProcedureActionEntry *entries;
gint n_entries;
gint i;
@@ -776,6 +783,21 @@ filters_actions_setup (GimpActionGroup *group)
filters_actions_set_tooltips (group, filters_interactive_actions,
G_N_ELEMENTS (filters_interactive_actions));
/* XXX Hardcoded list to prevent expensive node/graph creation of a
* well-known list of operations.
* This whole code will disappear when we'll support filters with aux
* input non-destructively anyway.
*/
if (first_setup)
{
actions_filter_set_aux ("filters-variable-blur");
actions_filter_set_aux ("filters-oilify");
actions_filter_set_aux ("filters-lens-blur");
actions_filter_set_aux ("filters-gaussian-blur-selective");
actions_filter_set_aux ("filters-displace");
actions_filter_set_aux ("filters-bump-map");
}
gegl_actions = g_strv_builder_new ();
op_classes = gimp_gegl_get_op_classes (TRUE);
@@ -802,7 +824,7 @@ filters_actions_setup (GimpActionGroup *group)
* operations end up generating the same action name. Typically we
* don't want a third-party operation called "my-op" to have the same
* action name than "my_op" (which is to say that one will be
* overrided by the other).
* overridden by the other).
*/
g_free (action_name);
action_name = g_strdup_printf ("filters-%s-%d", formatted_op_name, i++);
@@ -861,6 +883,23 @@ filters_actions_setup (GimpActionGroup *group)
g_free (short_label);
}
/* Identify third-party filters based on operations with an
* auxiliary pad in first setup because of slowness on Windows.
* See #14781.
*/
if (first_setup)
{
GeglNode *node = gegl_node_new ();
gegl_node_set (node,
"operation", op_class->name,
NULL);
if (gegl_node_has_pad (node, "aux"))
actions_filter_set_aux (action_name);
g_clear_object (&node);
}
g_strv_builder_add (gegl_actions, action_name);
g_free (label);
@@ -910,6 +949,8 @@ filters_actions_setup (GimpActionGroup *group)
group, 0);
filters_actions_history_changed (group->gimp, group);
first_setup = FALSE;
}
void
@@ -917,11 +958,14 @@ filters_actions_update (GimpActionGroup *group,
gpointer data)
{
GimpImage *image;
GList *actions;
GList *iter;
gboolean writable = FALSE;
gboolean gray = FALSE;
gboolean alpha = FALSE;
gboolean supports_alpha = FALSE;
gboolean is_group = FALSE;
gboolean force_nde = FALSE;
image = action_data_get_image (data);
@@ -949,6 +993,11 @@ filters_actions_update (GimpActionGroup *group,
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
is_group = TRUE;
if (GIMP_IS_GROUP_LAYER (drawable) ||
gimp_item_is_vector_layer (GIMP_ITEM (drawable)) ||
gimp_item_is_link_layer (GIMP_ITEM (drawable)))
force_nde = TRUE;
}
g_list_free (drawables);
@@ -957,134 +1006,82 @@ filters_actions_update (GimpActionGroup *group,
#define SET_SENSITIVE(action,condition) \
gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
SET_SENSITIVE ("filters-alien-map", writable);
SET_SENSITIVE ("filters-antialias", writable && !is_group);
SET_SENSITIVE ("filters-apply-canvas", writable);
SET_SENSITIVE ("filters-apply-lens", writable);
SET_SENSITIVE ("filters-bayer-matrix", writable);
SET_SENSITIVE ("filters-bloom", writable);
SET_SENSITIVE ("filters-brightness-contrast", writable);
SET_SENSITIVE ("filters-bump-map", writable && !is_group);
actions = gimp_action_group_list_actions (group);
for (iter = actions; iter; iter = iter->next)
{
GimpAction *action = iter->data;
const gchar *action_name;
action_name = gimp_action_get_name (action);
if (filters_is_non_interactive (action_name))
{
/* Even I'm not sure they should, right now non-interactive
* actions are always applied destructively. So these filters
* are incompatible with layers where non-destructivity is
* mandatory.
*/
SET_SENSITIVE (action_name, writable && ! force_nde);
}
else if (GIMP_IS_STRING_ACTION (action))
{
const gchar *opname;
opname = GIMP_STRING_ACTION (action)->value;
if (opname == NULL)
/* These are the filters-recent-*, repeat and reshow handled
* below.
*/
continue;
if (g_strcmp0 (opname, "gegl:gegl") == 0)
{
/* GEGL graph filter can only be run destructively, unless
* the GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT environment
* variable is set.
*/
SET_SENSITIVE (gimp_action_get_name (action), writable &&
(g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") != NULL || ! force_nde));
}
else if (gegl_has_operation (opname))
{
gboolean sensitive = writable;
if (sensitive && force_nde)
/* Operations with auxiliary inputs can only be applied
* destructively. Therefore they must be deactivated on
* types of layers where filters can only be applied
* non-destructively.
*/
sensitive = ! actions_filter_get_aux (action_name);
SET_SENSITIVE (gimp_action_get_name (action), sensitive);
}
}
}
g_list_free (actions);
/* Special-cased filters */
SET_SENSITIVE ("filters-c2g", writable && !gray);
SET_SENSITIVE ("filters-cartoon", writable);
SET_SENSITIVE ("filters-channel-mixer", writable);
SET_SENSITIVE ("filters-checkerboard", writable);
SET_SENSITIVE ("filters-color-balance", writable && !gray);
SET_SENSITIVE ("filters-color-enhance", writable && !gray);
SET_SENSITIVE ("filters-color-exchange", writable);
SET_SENSITIVE ("filters-color-enhance", writable && !force_nde && !gray);
SET_SENSITIVE ("filters-colorize", writable && !gray);
SET_SENSITIVE ("filters-dither", writable);
SET_SENSITIVE ("filters-color-rotate", writable);
SET_SENSITIVE ("filters-color-temperature", writable && !gray);
SET_SENSITIVE ("filters-color-to-alpha", writable && supports_alpha);
SET_SENSITIVE ("filters-component-extract", writable);
SET_SENSITIVE ("filters-convolution-matrix", writable);
SET_SENSITIVE ("filters-cubism", writable);
SET_SENSITIVE ("filters-curves", writable);
SET_SENSITIVE ("filters-deinterlace", writable);
SET_SENSITIVE ("filters-desaturate", writable && !gray);
SET_SENSITIVE ("filters-difference-of-gaussians", writable);
SET_SENSITIVE ("filters-diffraction-patterns", writable);
SET_SENSITIVE ("filters-dilate", writable && !is_group);
SET_SENSITIVE ("filters-displace", writable && !is_group);
SET_SENSITIVE ("filters-distance-map", writable);
SET_SENSITIVE ("filters-dropshadow", writable && alpha);
SET_SENSITIVE ("filters-edge", writable && !is_group);
SET_SENSITIVE ("filters-edge-laplace", writable);
SET_SENSITIVE ("filters-edge-neon", writable);
SET_SENSITIVE ("filters-edge-sobel", writable);
SET_SENSITIVE ("filters-emboss", writable);
SET_SENSITIVE ("filters-engrave", writable);
SET_SENSITIVE ("filters-erode", writable);
SET_SENSITIVE ("filters-exposure", writable);
SET_SENSITIVE ("filters-fattal-2002", writable);
SET_SENSITIVE ("filters-focus-blur", writable);
SET_SENSITIVE ("filters-fractal-trace", writable);
SET_SENSITIVE ("filters-gaussian-blur", writable);
SET_SENSITIVE ("filters-gaussian-blur-selective", writable && !is_group);
SET_SENSITIVE ("filters-gegl-graph", writable && !is_group);
SET_SENSITIVE ("filters-grid", writable);
SET_SENSITIVE ("filters-high-pass", writable);
SET_SENSITIVE ("filters-hue-chroma", writable);
SET_SENSITIVE ("filters-hue-saturation", writable && !gray);
SET_SENSITIVE ("filters-illusion", writable);
SET_SENSITIVE ("filters-invert-linear", writable && !is_group);
SET_SENSITIVE ("filters-invert-perceptual", writable && !is_group);
SET_SENSITIVE ("filters-invert-value", writable && !is_group);
SET_SENSITIVE ("filters-image-gradient", writable);
SET_SENSITIVE ("filters-kaleidoscope", writable);
SET_SENSITIVE ("filters-lens-blur", writable && !is_group);
SET_SENSITIVE ("filters-lens-distortion", writable);
SET_SENSITIVE ("filters-lens-flare", writable);
SET_SENSITIVE ("filters-levels", writable);
SET_SENSITIVE ("filters-linear-sinusoid", writable);
SET_SENSITIVE ("filters-little-planet", writable);
SET_SENSITIVE ("filters-long-shadow", writable && alpha);
SET_SENSITIVE ("filters-mantiuk-2006", writable);
SET_SENSITIVE ("filters-maze", writable);
SET_SENSITIVE ("filters-mean-curvature-blur", writable);
SET_SENSITIVE ("filters-median-blur", writable);
SET_SENSITIVE ("filters-mono-mixer", writable && !gray);
SET_SENSITIVE ("filters-mosaic", writable);
SET_SENSITIVE ("filters-motion-blur-circular", writable);
SET_SENSITIVE ("filters-motion-blur-linear", writable);
SET_SENSITIVE ("filters-motion-blur-zoom", writable);
SET_SENSITIVE ("filters-newsprint", writable);
SET_SENSITIVE ("filters-noise-cell", writable);
SET_SENSITIVE ("filters-noise-cie-lch", writable);
SET_SENSITIVE ("filters-noise-hsv", writable && !gray);
SET_SENSITIVE ("filters-noise-hurl", writable);
SET_SENSITIVE ("filters-noise-perlin", writable);
SET_SENSITIVE ("filters-noise-pick", writable);
SET_SENSITIVE ("filters-noise-reduction", writable);
SET_SENSITIVE ("filters-noise-rgb", writable);
SET_SENSITIVE ("filters-noise-simplex", writable);
SET_SENSITIVE ("filters-noise-slur", writable);
SET_SENSITIVE ("filters-noise-solid", writable);
SET_SENSITIVE ("filters-noise-spread", writable);
SET_SENSITIVE ("filters-normal-map", writable);
SET_SENSITIVE ("filters-offset", writable);
SET_SENSITIVE ("filters-oilify", writable && !is_group);
SET_SENSITIVE ("filters-panorama-projection", writable);
SET_SENSITIVE ("filters-photocopy", writable);
SET_SENSITIVE ("filters-pixelize", writable);
SET_SENSITIVE ("filters-plasma", writable);
SET_SENSITIVE ("filters-polar-coordinates", writable);
SET_SENSITIVE ("filters-posterize", writable);
SET_SENSITIVE ("filters-recursive-transform", writable);
SET_SENSITIVE ("filters-red-eye-removal", writable && !gray);
SET_SENSITIVE ("filters-reinhard-2005", writable);
SET_SENSITIVE ("filters-rgb-clip", writable);
SET_SENSITIVE ("filters-ripple", writable);
SET_SENSITIVE ("filters-saturation", writable && !gray);
SET_SENSITIVE ("filters-semi-flatten", writable && alpha);
SET_SENSITIVE ("filters-sepia", writable && !gray);
SET_SENSITIVE ("filters-shadows-highlights", writable);
SET_SENSITIVE ("filters-shift", writable);
SET_SENSITIVE ("filters-sinus", writable);
SET_SENSITIVE ("filters-slic", writable);
SET_SENSITIVE ("filters-snn-mean", writable);
SET_SENSITIVE ("filters-softglow", writable);
SET_SENSITIVE ("filters-spherize", writable);
SET_SENSITIVE ("filters-spiral", writable);
SET_SENSITIVE ("filters-stretch-contrast", writable);
SET_SENSITIVE ("filters-stretch-contrast-hsv", writable);
SET_SENSITIVE ("filters-stress", writable);
SET_SENSITIVE ("filters-supernova", writable);
SET_SENSITIVE ("filters-threshold", writable);
SET_SENSITIVE ("filters-threshold-alpha", writable && alpha);
SET_SENSITIVE ("filters-tile-glass", writable);
SET_SENSITIVE ("filters-tile-paper", writable);
SET_SENSITIVE ("filters-tile-seamless", writable);
SET_SENSITIVE ("filters-unsharp-mask", writable);
SET_SENSITIVE ("filters-value-propagate", writable);
SET_SENSITIVE ("filters-variable-blur", writable && !is_group);
SET_SENSITIVE ("filters-video-degradation", writable);
SET_SENSITIVE ("filters-vignette", writable);
SET_SENSITIVE ("filters-waterpixels", writable);
SET_SENSITIVE ("filters-waves", writable);
SET_SENSITIVE ("filters-whirl-pinch", writable);
SET_SENSITIVE ("filters-wind", writable);
#undef SET_SENSITIVE
@@ -1336,3 +1333,19 @@ filters_actions_history_changed (Gimp *gimp,
NULL);
}
}
static gboolean
filters_is_non_interactive (const gchar *action_name)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (filters_actions); i++)
if (g_strcmp0 (filters_actions[i].name, action_name) == 0)
return TRUE;
for (i = 0; i < G_N_ELEMENTS (filters_settings_actions); i++)
if (g_strcmp0 (filters_settings_actions[i].name, action_name) == 0)
return TRUE;
return FALSE;
}

View File

@@ -30,6 +30,7 @@
#include "core/gimpimage.h"
#include "core/gimplayer.h"
#include "core/gimplayer-floating-selection.h"
#include "core/gimplinklayer.h"
#include "text/gimptextlayer.h"
@@ -181,6 +182,18 @@ static const GimpActionEntry layers_actions[] =
image_flatten_image_cmd_callback,
GIMP_HELP_IMAGE_FLATTEN },
{ "layers-link-discard", GIMP_ICON_TOOL_TEXT,
NC_("layers-action", "_Discard Link Information"), NULL, { NULL },
NC_("layers-action", "Turn this link layer into a normal layer"),
layers_link_discard_cmd_callback,
GIMP_HELP_LAYER_TEXT_DISCARD },
{ "layers-link-monitor", GIMP_ICON_TOOL_TEXT,
NC_("layers-action", "_Monitor Linked Image"), NULL, { NULL },
NC_("layers-action", "Discard any transformation and monitor the linked file again"),
layers_link_monitor_cmd_callback,
GIMP_HELP_LAYER_TEXT_DISCARD },
{ "layers-text-discard", GIMP_ICON_TOOL_TEXT,
NC_("layers-action", "_Discard Text Information"), NULL, { NULL },
NC_("layers-action", "Turn these text layers into normal layers"),
@@ -200,16 +213,16 @@ static const GimpActionEntry layers_actions[] =
GIMP_HELP_LAYER_TEXT_ALONG_PATH },
{ "layers-vector-fill-stroke", NULL,
NC_("layers-action", "Fill / Stroke"), NULL, { NULL },
NC_("layers-action", "Fill / Stroke..."), NULL, { NULL },
NC_("layers-action", "Edit the fill and stroke of this vector layer"),
layers_vector_fill_stroke_cmd_callback,
NULL },
GIMP_HELP_LAYER_VECTOR_FILL_STROKE },
{ "layers-vector-discard", NULL,
NC_("layers-action", "Discard Vector Information"), NULL, { NULL },
NC_("layers-action", "Turn this vector layer into a normal layer"),
layers_vector_discard_cmd_callback,
NULL },
GIMP_HELP_LAYER_VECTOR_DISCARD },
{ "layers-resize", GIMP_ICON_OBJECT_RESIZE,
NC_("layers-action", "Layer B_oundary Size..."), NULL, { NULL },
@@ -778,6 +791,7 @@ layers_actions_update (GimpActionGroup *group,
gboolean can_lock_alpha = FALSE;
gboolean text_layer = FALSE;
gboolean vector_layer = FALSE;
gboolean link_layer = FALSE;
gboolean bs_mutable = FALSE; /* At least 1 selected layers' blend space is mutable. */
gboolean cs_mutable = FALSE; /* At least 1 selected layers' composite space is mutable. */
gboolean cm_mutable = FALSE; /* At least 1 selected layers' composite mode is mutable. */
@@ -1000,6 +1014,8 @@ layers_actions_update (GimpActionGroup *group,
text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer));
vector_layer = gimp_item_is_vector_layer (GIMP_ITEM (layer));
if (GIMP_IS_LINK_LAYER (layer))
link_layer = gimp_link_layer_is_monitored (GIMP_LINK_LAYER (layer));
}
}
@@ -1068,6 +1084,9 @@ layers_actions_update (GimpActionGroup *group,
SET_VISIBLE ("layers-vector-fill-stroke", vector_layer && !ac);
SET_VISIBLE ("layers-vector-discard", vector_layer && !ac);
SET_VISIBLE ("layers-link-discard", link_layer && !ac);
SET_VISIBLE ("layers-link-monitor", GIMP_IS_LINK_LAYER (layer) && ! link_layer && !ac);
SET_SENSITIVE ("layers-resize", n_selected_layers == 1 && all_writable && all_movable && !ac);
SET_SENSITIVE ("layers-resize-to-image", all_writable && all_movable && !ac);
SET_SENSITIVE ("layers-scale", n_selected_layers == 1 && all_writable && all_movable && !ac);

View File

@@ -48,6 +48,8 @@
#include "core/gimplayerpropundo.h"
#include "core/gimplayer-floating-selection.h"
#include "core/gimplayer-new.h"
#include "core/gimplink.h"
#include "core/gimplinklayer.h"
#include "core/gimplist.h"
#include "core/gimppickable.h"
#include "core/gimppickable-auto-shrink.h"
@@ -68,6 +70,7 @@
#include "widgets/gimpaction.h"
#include "widgets/gimpdock.h"
#include "widgets/gimphelp-ids.h"
#include "widgets/gimpopendialog.h"
#include "widgets/gimpprogressdialog.h"
#include "display/gimpdisplay.h"
@@ -105,6 +108,7 @@ static void layers_new_callback (GtkWidget *dialog,
GimpLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
GimpFillType layer_fill_type,
GimpLink *link,
gint layer_width,
gint layer_height,
gint layer_offset_x,
@@ -128,6 +132,7 @@ static void layers_edit_attributes_callback (GtkWidget *dialog,
GimpLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
GimpFillType layer_fill_type,
GimpLink *link,
gint layer_width,
gint layer_height,
gint layer_offset_x,
@@ -145,6 +150,7 @@ static void layers_add_mask_callback (GtkWidget *dialog,
GimpAddMaskType add_mask_type,
GimpChannel *channel,
gboolean invert,
gboolean edit_mask,
gpointer user_data);
static void layers_scale_callback (GtkWidget *dialog,
GimpViewable *viewable,
@@ -1099,6 +1105,42 @@ layers_delete_cmd_callback (GimpAction *action,
gimp_image_flush (image);
}
void
layers_link_discard_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
GimpImage *image;
GList *layers;
GList *iter;
return_if_no_layers (image, layers, data);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_PROPERTIES,
_("Discard Links"));
for (iter = layers; iter; iter = iter->next)
if (GIMP_IS_LINK_LAYER (iter->data))
gimp_link_layer_discard (GIMP_LINK_LAYER (iter->data));
gimp_image_undo_group_end (image);
}
void
layers_link_monitor_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
GimpImage *image;
GList *layers;
GList *iter;
return_if_no_layers (image, layers, data);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_PROPERTIES,
_("Monitor Links"));
for (iter = layers; iter; iter = iter->next)
if (GIMP_IS_LINK_LAYER (iter->data))
gimp_link_layer_monitor (GIMP_LINK_LAYER (iter->data));
gimp_image_undo_group_end (image);
}
void
layers_text_discard_cmd_callback (GimpAction *action,
GVariant *value,
@@ -1527,6 +1569,7 @@ layers_mask_add_cmd_callback (GimpAction *action,
widget,
config->layer_add_mask_type,
config->layer_add_mask_invert,
config->layer_add_mask_edit_mask,
layers_add_mask_callback,
NULL);
@@ -1602,7 +1645,9 @@ layers_mask_add_last_vals_cmd_callback (GimpAction *action,
if (config->layer_add_mask_invert)
gimp_channel_invert (GIMP_CHANNEL (mask), FALSE);
gimp_layer_add_mask (iter->data, mask, TRUE, NULL);
gimp_layer_add_mask (iter->data, mask,
config->layer_add_mask_edit_mask,
TRUE, NULL);
}
gimp_image_undo_group_end (image);
@@ -1719,7 +1764,7 @@ layers_mask_show_cmd_callback (GimpAction *action,
{
/* if switching "show mask" on, and any selected layer's
* mask is already visible, bail out because that's
* exactly the logic we use in the ui for multile
* exactly the logic we use in the ui for multiple
* visible layer masks.
*/
return;
@@ -1770,7 +1815,7 @@ layers_mask_disable_cmd_callback (GimpAction *action,
{
/* if switching "disable mask" on, and any selected
* layer's mask is already disabled, bail out because
* that's exactly the logic we use in the ui for multile
* that's exactly the logic we use in the ui for multiple
* disabled layer masks.
*/
return;
@@ -2317,6 +2362,7 @@ layers_new_callback (GtkWidget *dialog,
GimpLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
GimpFillType layer_fill_type,
GimpLink *link,
gint layer_width,
gint layer_height,
gint layer_offset_x,
@@ -2337,6 +2383,8 @@ layers_new_callback (GtkWidget *dialog,
gint n_layers = g_list_length (layers);
gboolean run_once = (n_layers == 0);
g_return_if_fail (link == NULL);
g_object_set (config,
"layer-new-name", layer_name,
"layer-new-mode", layer_mode,
@@ -2433,6 +2481,7 @@ layers_edit_attributes_callback (GtkWidget *dialog,
GimpLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
GimpFillType unused1,
GimpLink *link,
gint unused2,
gint unused3,
gint layer_offset_x,
@@ -2461,7 +2510,8 @@ layers_edit_attributes_callback (GtkWidget *dialog,
layer_lock_pixels != gimp_item_get_lock_content (item) ||
layer_lock_position != gimp_item_get_lock_position (item) ||
layer_lock_visibility != gimp_item_get_lock_visibility (item) ||
layer_lock_alpha != gimp_layer_get_lock_alpha (layer))
layer_lock_alpha != gimp_layer_get_lock_alpha (layer) ||
link)
{
gimp_image_undo_group_start (image,
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
@@ -2522,6 +2572,9 @@ layers_edit_attributes_callback (GtkWidget *dialog,
if (layer_lock_alpha != gimp_layer_get_lock_alpha (layer))
gimp_layer_set_lock_alpha (layer, layer_lock_alpha, TRUE);
if (GIMP_IS_LINK_LAYER (layer) && link)
gimp_link_layer_set_link (GIMP_LINK_LAYER (layer), link, TRUE);
gimp_image_undo_group_end (image);
gimp_image_flush (image);
}
@@ -2542,6 +2595,7 @@ layers_add_mask_callback (GtkWidget *dialog,
GimpAddMaskType add_mask_type,
GimpChannel *channel,
gboolean invert,
gboolean edit_mask,
gpointer user_data)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layers->data));
@@ -2551,8 +2605,9 @@ layers_add_mask_callback (GtkWidget *dialog,
GError *error = NULL;
g_object_set (config,
"layer-add-mask-type", add_mask_type,
"layer-add-mask-invert", invert,
"layer-add-mask-type", add_mask_type,
"layer-add-mask-invert", invert,
"layer-add-mask-edit-mask", edit_mask,
NULL);
gimp_image_undo_group_start (image,
@@ -2568,7 +2623,7 @@ layers_add_mask_callback (GtkWidget *dialog,
if (config->layer_add_mask_invert)
gimp_channel_invert (GIMP_CHANNEL (mask), FALSE);
if (! gimp_layer_add_mask (iter->data, mask, TRUE, &error))
if (! gimp_layer_add_mask (iter->data, mask, edit_mask, TRUE, &error))
{
gimp_message_literal (image->gimp,
G_OBJECT (dialog), GIMP_MESSAGE_WARNING,
@@ -2670,7 +2725,7 @@ layers_vector_fill_stroke_cmd_callback (GimpAction *action,
action_data_get_context (data),
_("Fill / Stroke"),
"gimp-vector-layer-stroke",
NULL,
GIMP_HELP_LAYER_VECTOR_FILL_STROKE,
widget);
gtk_widget_show (dialog);
}

View File

@@ -77,6 +77,12 @@ void layers_merge_group_cmd_callback (GimpAction *action,
void layers_delete_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void layers_link_discard_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void layers_link_monitor_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void layers_text_discard_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);

View File

@@ -101,6 +101,6 @@ libappactions = static_library('appactions',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Actions"',
dependencies: [
gegl, gdk_pixbuf, gtk3,
gegl, gdk_pixbuf, gtk3, gexiv2,
],
)

View File

@@ -154,7 +154,7 @@ static const GimpActionEntry paths_actions[] =
{ "paths-to-vector-layer", NULL,
NC_("paths-action", "Path to Vector Layer"), NULL, { NULL }, NULL,
path_to_vector_layer_cmd_callback,
NULL },
GIMP_HELP_PATH_TO_VECTOR_LAYER },
};
static const GimpToggleActionEntry paths_toggle_actions[] =

View File

@@ -61,6 +61,21 @@ static const GimpActionEntry text_tool_actions[] =
text_tool_paste_cmd_callback,
GIMP_HELP_TEXT_TOOL_PASTE },
{ "text-tool-toggle-bold", GIMP_ICON_FORMAT_TEXT_BOLD,
NC_("text-tool-action", "_Bold"), NULL, { "<primary>B", NULL }, NULL,
text_tool_toggle_bold_cmd_callback,
NULL },
{ "text-tool-toggle-italic", GIMP_ICON_FORMAT_TEXT_ITALIC,
NC_("text-tool-action", "_Italic"), NULL, { "<primary>I", NULL }, NULL,
text_tool_toggle_italic_cmd_callback,
NULL },
{ "text-tool-toggle-underline", GIMP_ICON_FORMAT_TEXT_UNDERLINE,
NC_("text-tool-action", "_Underline"), NULL, { "<primary>U", NULL }, NULL,
text_tool_toggle_underline_cmd_callback,
NULL },
{ "text-tool-delete", GIMP_ICON_EDIT_DELETE,
NC_("text-tool-action", "_Delete"), NULL, { NULL }, NULL,
text_tool_delete_cmd_callback,
@@ -189,14 +204,17 @@ text_tool_actions_update (GimpActionGroup *group,
#define SET_ACTIVE(action,condition) \
gimp_action_group_set_action_active (group, action, (condition) != 0)
SET_SENSITIVE ("text-tool-cut", text_sel);
SET_SENSITIVE ("text-tool-copy", text_sel);
SET_SENSITIVE ("text-tool-paste", clip);
SET_SENSITIVE ("text-tool-delete", text_sel);
SET_SENSITIVE ("text-tool-clear", text_layer);
SET_SENSITIVE ("text-tool-load", image);
SET_SENSITIVE ("text-tool-text-to-path", text_layer);
SET_SENSITIVE ("text-tool-text-along-path", text_layer && g_list_length (paths) == 1);
SET_SENSITIVE ("text-tool-cut", text_sel);
SET_SENSITIVE ("text-tool-copy", text_sel);
SET_SENSITIVE ("text-tool-paste", clip);
SET_SENSITIVE ("text-tool-toggle-bold", text_sel);
SET_SENSITIVE ("text-tool-toggle-italic", text_sel);
SET_SENSITIVE ("text-tool-toggle-underline", text_sel);
SET_SENSITIVE ("text-tool-delete", text_sel);
SET_SENSITIVE ("text-tool-clear", text_layer);
SET_SENSITIVE ("text-tool-load", image);
SET_SENSITIVE ("text-tool-text-to-path", text_layer);
SET_SENSITIVE ("text-tool-text-along-path", text_layer && g_list_length (paths) == 1);
direction = gimp_text_tool_get_direction (text_tool);
for (i = 0; i < G_N_ELEMENTS (text_tool_direction_actions); i++)

View File

@@ -84,6 +84,36 @@ text_tool_paste_cmd_callback (GimpAction *action,
gimp_text_tool_paste_clipboard (text_tool);
}
void
text_tool_toggle_bold_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
gimp_text_tool_toggle_tag (text_tool, text_tool->buffer->bold_tag);
}
void
text_tool_toggle_italic_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
gimp_text_tool_toggle_tag (text_tool, text_tool->buffer->italic_tag);
}
void
text_tool_toggle_underline_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
gimp_text_tool_toggle_tag (text_tool, text_tool->buffer->underline_tag);
}
void
text_tool_delete_cmd_callback (GimpAction *action,
GVariant *value,

View File

@@ -27,6 +27,16 @@ void text_tool_copy_cmd_callback (GimpAction *action,
void text_tool_paste_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void text_tool_toggle_bold_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void text_tool_toggle_italic_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);
void text_tool_toggle_underline_cmd_callback
(GimpAction *action,
GVariant *value,
gpointer data);
void text_tool_delete_cmd_callback (GimpAction *action,
GVariant *value,
gpointer data);

View File

@@ -81,6 +81,7 @@ enum
PROP_LAYER_ADD_MASK_TYPE,
PROP_LAYER_ADD_MASK_INVERT,
PROP_LAYER_ADD_MASK_EDIT_MASK,
PROP_LAYER_MERGE_TYPE,
PROP_LAYER_MERGE_ACTIVE_GROUP_ONLY,
@@ -389,6 +390,13 @@ gimp_dialog_config_class_init (GimpDialogConfigClass *klass)
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LAYER_ADD_MASK_EDIT_MASK,
"layer-add-mask-edit-mask",
"Default layer mask: edit mask immediately",
LAYER_ADD_MASK_EDIT_MASK,
TRUE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_ENUM (object_class, PROP_LAYER_MERGE_TYPE,
"layer-merge-type",
"Default layer merge type",
@@ -716,6 +724,9 @@ gimp_dialog_config_set_property (GObject *object,
case PROP_LAYER_ADD_MASK_INVERT:
config->layer_add_mask_invert = g_value_get_boolean (value);
break;
case PROP_LAYER_ADD_MASK_EDIT_MASK:
config->layer_add_mask_edit_mask = g_value_get_boolean (value);
break;
case PROP_LAYER_MERGE_TYPE:
config->layer_merge_type = g_value_get_enum (value);
@@ -908,6 +919,9 @@ gimp_dialog_config_get_property (GObject *object,
case PROP_LAYER_ADD_MASK_INVERT:
g_value_set_boolean (value, config->layer_add_mask_invert);
break;
case PROP_LAYER_ADD_MASK_EDIT_MASK:
g_value_set_boolean (value, config->layer_add_mask_edit_mask);
break;
case PROP_LAYER_MERGE_TYPE:
g_value_set_enum (value, config->layer_merge_type);

View File

@@ -78,6 +78,7 @@ struct _GimpDialogConfig
GimpAddMaskType layer_add_mask_type;
gboolean layer_add_mask_invert;
gboolean layer_add_mask_edit_mask;
GimpMergeType layer_merge_type;
gboolean layer_merge_active_group_only;

View File

@@ -659,6 +659,9 @@ _("Sets the default mask for the 'Add Layer Mask' dialog.")
#define LAYER_ADD_MASK_INVERT_BLURB \
_("Sets the default 'invert mask' state for the 'Add Layer Mask' dialog.")
#define LAYER_ADD_MASK_EDIT_MASK \
_("Sets the default 'edit mask' state for the 'Add Layer Mask' dialog.")
#define LAYER_MERGE_TYPE_BLURB \
_("Sets the default merge type for the 'Merge Visible Layers' dialog.")

View File

@@ -44,7 +44,7 @@ libappconfig = static_library('appconfig',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Config"',
dependencies: [
cairo, gegl, gdk_pixbuf, gio, gio_specific, libmypaint,
cairo, gegl, gdk_pixbuf, gexiv2, gio, gio_specific, libmypaint,
],
)

View File

@@ -1257,6 +1257,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_LAYER_MODE, "GIMP_UNDO_LAYER_MODE", "layer-mode" },
{ GIMP_UNDO_LAYER_OPACITY, "GIMP_UNDO_LAYER_OPACITY", "layer-opacity" },
{ GIMP_UNDO_LAYER_LOCK_ALPHA, "GIMP_UNDO_LAYER_LOCK_ALPHA", "layer-lock-alpha" },
{ GIMP_UNDO_LINK_LAYER, "GIMP_UNDO_LINK_LAYER", "link-layer" },
{ GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, "GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE", "group-layer-suspend-resize" },
{ GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, "GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE", "group-layer-resume-resize" },
{ GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, "GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK", "group-layer-suspend-mask" },
@@ -1372,6 +1373,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_LAYER_MODE, NC_("undo-type", "Set layer mode"), NULL },
{ GIMP_UNDO_LAYER_OPACITY, NC_("undo-type", "Set layer opacity"), NULL },
{ GIMP_UNDO_LAYER_LOCK_ALPHA, NC_("undo-type", "Lock/Unlock alpha channel"), NULL },
{ GIMP_UNDO_LINK_LAYER, NC_("undo-type", "Link layer"), NULL },
{ GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, NC_("undo-type", "Suspend group layer resize"), NULL },
{ GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, NC_("undo-type", "Resume group layer resize"), NULL },
{ GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, NC_("undo-type", "Suspend group layer mask"), NULL },

View File

@@ -609,6 +609,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_LAYER_MODE, /*< desc="Set layer mode" >*/
GIMP_UNDO_LAYER_OPACITY, /*< desc="Set layer opacity" >*/
GIMP_UNDO_LAYER_LOCK_ALPHA, /*< desc="Lock/Unlock alpha channel" >*/
GIMP_UNDO_LINK_LAYER, /*< desc="Link layer" >*/
GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, /*< desc="Suspend group layer resize" >*/
GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, /*< desc="Resume group layer resize" >*/
GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, /*< desc="Suspend group layer mask" >*/

View File

@@ -90,6 +90,7 @@ typedef struct _GimpViewable GimpViewable;
typedef struct _GimpFilter GimpFilter;
typedef struct _GimpItem GimpItem;
typedef struct _GimpAuxItem GimpAuxItem;
typedef struct _GimpLink GimpLink;
typedef struct _Gimp Gimp;
typedef struct _GimpImage GimpImage;
@@ -167,6 +168,7 @@ typedef struct _GimpLayerMask GimpLayerMask;
typedef struct _GimpSelection GimpSelection;
typedef struct _GimpLayer GimpLayer;
typedef struct _GimpGroupLayer GimpGroupLayer;
typedef struct _GimpLinkLayer GimpLinkLayer;
/* auxiliary image items */

View File

@@ -353,7 +353,7 @@ gimp_transform_resize_crop (const GimpVector2 *orig_points,
if (r.area == 0)
{
/* saveguard if something went wrong, adjust and give warning */
/* safeguard if something went wrong, adjust and give warning */
gimp_transform_resize_adjust (orig_points, n_points,
x1, y1, x2, y2);
g_printerr ("no rectangle found by algorithm, no cropping done\n");

View File

@@ -224,18 +224,14 @@ gimp_user_install_run (GimpUserInstall *install,
if (install->migrate)
{
gchar *verstring;
/* TODO: these 2 strings should be merged into one, but it was not
* possible to do it at implementation time, in order not to break
* string freeze.
*/
verstring = g_strdup_printf ("%d.%d", install->old_major, install->old_minor);
user_install_log (install,
_("It seems you have used GIMP %s before. "
/* TRANSLATORS: the %d.%d replacement strings
* will be a series version (e.g. 2.10). The %s
* replacement will be a directory.
*/
_("It seems you have used GIMP %d.%d before. "
"GIMP will now migrate your user settings to '%s'."),
verstring, dirname);
g_free (verstring);
install->old_major, install->old_minor, dirname);
}
else
{

View File

@@ -605,7 +605,7 @@ gimp_get_fill_params (GimpContext *context,
* @start_y:
* @end_x:
* @end_y:
* @n_snap_lines: Number evenly disributed lines to snap to.
* @n_snap_lines: Number evenly distributed lines to snap to.
* @offset_angle: The angle by which to offset the lines, in degrees.
* @xres: The horizontal resolution.
* @yres: The vertical resolution.

View File

@@ -271,7 +271,7 @@ gimp_brush_pipe_select_brush (GimpBrush *brush,
break;
case PIPE_SELECT_ANGULAR:
/* Coords angle is already nomalized,
/* Coords angle is already normalized,
* offset by 90 degrees is still needed
* because hoses were made PS compatible*/
ix = (gint) RINT ((1.0 - current_coords->direction + 0.25) * pipe->rank[i]) % pipe->rank[i];
@@ -351,8 +351,10 @@ gimp_brush_pipe_set_params (GimpBrushPipe *pipe,
{
GimpPixPipeParams params;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_init (&params);
gimp_pixpipe_params_parse (paramstring, &params);
G_GNUC_END_IGNORE_DEPRECATIONS
pipe->dimension = params.dim;
pipe->rank = g_new0 (gint, pipe->dimension);
@@ -384,7 +386,9 @@ gimp_brush_pipe_set_params (GimpBrushPipe *pipe,
pipe->index[i] = 0;
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_free (&params);
G_GNUC_END_IGNORE_DEPRECATIONS
pipe->params = g_strdup (paramstring);
}

View File

@@ -766,7 +766,7 @@ gimp_drawable_transform_affine (GimpDrawable *drawable,
{
result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
new_offset_x, new_offset_y,
new_layer);
new_layer, TRUE);
g_object_unref (new_buffer);
}
}
@@ -848,7 +848,7 @@ gimp_drawable_transform_flip (GimpDrawable *drawable,
{
result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
new_offset_x, new_offset_y,
new_layer);
new_layer, TRUE);
g_object_unref (new_buffer);
}
}
@@ -933,7 +933,7 @@ gimp_drawable_transform_rotate (GimpDrawable *drawable,
{
result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
new_offset_x, new_offset_y,
new_layer);
new_layer, TRUE);
g_object_unref (new_buffer);
}
}
@@ -1026,11 +1026,11 @@ gimp_drawable_transform_paste (GimpDrawable *drawable,
GimpColorProfile *buffer_profile,
gint offset_x,
gint offset_y,
gboolean new_layer)
gboolean new_layer,
gboolean push_undo)
{
GimpImage *image;
GimpLayer *layer = NULL;
const gchar *undo_desc = NULL;
GimpImage *image;
GimpLayer *layer = NULL;
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
@@ -1039,14 +1039,19 @@ gimp_drawable_transform_paste (GimpDrawable *drawable,
image = gimp_item_get_image (GIMP_ITEM (drawable));
if (GIMP_IS_LAYER (drawable))
undo_desc = C_("undo-type", "Transform Layer");
else if (GIMP_IS_CHANNEL (drawable))
undo_desc = C_("undo-type", "Transform Channel");
else
return NULL;
if (push_undo)
{
const gchar *undo_desc = NULL;
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE, undo_desc);
if (GIMP_IS_LAYER (drawable))
undo_desc = C_("undo-type", "Transform Layer");
else if (GIMP_IS_CHANNEL (drawable))
undo_desc = C_("undo-type", "Transform Channel");
else
return NULL;
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE, undo_desc);
}
if (new_layer)
{
@@ -1066,13 +1071,14 @@ gimp_drawable_transform_paste (GimpDrawable *drawable,
}
else
{
gimp_drawable_set_buffer_full (drawable, TRUE, NULL,
gimp_drawable_set_buffer_full (drawable, push_undo, NULL,
buffer,
GEGL_RECTANGLE (offset_x, offset_y, 0, 0),
TRUE);
}
gimp_image_undo_group_end (image);
if (push_undo)
gimp_image_undo_group_end (image);
return drawable;
}

View File

@@ -87,4 +87,5 @@ GimpDrawable * gimp_drawable_transform_paste (GimpDrawable
GimpColorProfile *buffer_profile,
gint offset_x,
gint offset_y,
gboolean new_layer);
gboolean new_layer,
gboolean push_undo);

View File

@@ -142,7 +142,8 @@ static void gimp_drawable_transform (GimpItem *item,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
static const guint8 *
gimp_drawable_get_icc_profile (GimpColorManaged *managed,
@@ -583,7 +584,7 @@ gimp_drawable_duplicate (GimpItem *item,
new_filter = gimp_drawable_filter_duplicate (new_drawable,
filter);
if (filter)
if (new_filter)
{
gimp_drawable_filter_apply (new_filter, NULL);
gimp_drawable_filter_commit (new_filter, TRUE, NULL, FALSE);
@@ -742,7 +743,7 @@ gimp_drawable_flip (GimpItem *item,
if (buffer)
{
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
new_off_x, new_off_y, FALSE);
new_off_x, new_off_y, FALSE, TRUE);
g_object_unref (buffer);
}
}
@@ -774,7 +775,7 @@ gimp_drawable_rotate (GimpItem *item,
if (buffer)
{
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
new_off_x, new_off_y, FALSE);
new_off_x, new_off_y, FALSE, TRUE);
g_object_unref (buffer);
}
}
@@ -786,7 +787,8 @@ gimp_drawable_transform (GimpItem *item,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress)
GimpProgress *progress,
gboolean push_undo)
{
GimpDrawable *drawable = GIMP_DRAWABLE (item);
GeglBuffer *buffer;
@@ -809,7 +811,7 @@ gimp_drawable_transform (GimpItem *item,
if (buffer)
{
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
new_off_x, new_off_y, FALSE);
new_off_x, new_off_y, FALSE, push_undo);
g_object_unref (buffer);
}
}

View File

@@ -56,6 +56,8 @@
#include "gimplist.h"
#include "gimpprogress.h"
#include "gimp-intl.h"
enum
{
@@ -954,9 +956,8 @@ gimp_drawable_filter_update (GimpDrawableFilter *filter,
* directly with bad data.
*/
g_set_error (error, GIMP_ERROR, GIMP_FAILED,
/* TODO: localize after string freeze. */
"GEGL operation '%s' has been called with a "
"non-existent argument name '%s' (#%d).",
_("GEGL operation '%s' has been called with a "
"non-existent argument name '%s' (#%d)."),
opname, pspec->name, i);
break;
}
@@ -1019,10 +1020,9 @@ gimp_drawable_filter_update (GimpDrawableFilter *filter,
else if (! G_TYPE_CHECK_VALUE_TYPE (new_value, G_PARAM_SPEC_VALUE_TYPE (pspec)))
{
g_set_error (error, GIMP_ERROR, GIMP_FAILED,
/* TODO: localize after string freeze. */
"GEGL operation '%s' has been called with a "
"wrong value type for argument '%s' (#%d). "
"Expected %s, got %s.",
_("GEGL operation '%s' has been called with a "
"wrong value type for argument '%s' (#%d). "
"Expected %s, got %s."),
opname, pspec->name, i,
g_type_name (pspec->value_type),
g_type_name (G_VALUE_TYPE (new_value)));
@@ -1095,9 +1095,8 @@ gimp_drawable_filter_update (GimpDrawableFilter *filter,
if (! gegl_node_has_pad (node, auxinputnames[i]))
{
g_set_error (error, GIMP_ERROR, GIMP_FAILED,
/* TODO: localize after string freeze. */
"GEGL operation '%s' has been called with an "
"invalid aux input name '%s'.",
_("GEGL operation '%s' has been called with an "
"invalid aux input name '%s'."),
opname, auxinputnames[i]);
break;
}

View File

@@ -108,8 +108,7 @@ gimp_drawable_filter_mask_rename (GimpItem *item,
GError **error)
{
g_set_error (error, GIMP_ERROR, GIMP_FAILED,
/* TODO: localized after string freeze. */
"Cannot rename effect masks.");
_("Cannot rename effect masks."));
return FALSE;
}

View File

@@ -406,17 +406,26 @@ gimp_extension_load (GimpExtension *extension,
metadata = as_metadata_new ();
success = as_metadata_parse_file (metadata, file, AS_FORMAT_KIND_XML, error);
if (success)
{
#if AS_CHECK_VERSION(1, 0, 0)
components = as_metadata_get_components (metadata);
component = as_component_box_index (components, 0);
components = as_metadata_get_components (metadata);
component = as_component_box_index (components, 0);
#else
components = as_metadata_get_components (metadata);
component = g_ptr_array_index (components, 0);
components = as_metadata_get_components (metadata);
component = g_ptr_array_index (components, 0);
#endif
}
g_object_unref (file);
g_free (path);
if (!success)
{
return success;
}
if (success && as_component_get_kind (component) != AS_COMPONENT_KIND_ADDON)
{
/* Properly setting the type will allow extensions to be

View File

@@ -159,7 +159,8 @@ static void gimp_group_layer_transform (GimpLayer *layer,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
static void gimp_group_layer_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
@@ -1016,7 +1017,8 @@ gimp_group_layer_transform (GimpLayer *layer,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress)
GimpProgress *progress,
gboolean push_undo)
{
GimpGroupLayer *group = GIMP_GROUP_LAYER (layer);
GimpGroupLayerPrivate *private = GET_PRIVATE (layer);

View File

@@ -152,7 +152,7 @@ gimp_id_table_insert (GimpIdTable *id_table, gpointer data)
* @data: The data to associate with the id
*
* Insert data in the id table with a specific ID. If data already
* exsts with the given ID, this function fails.
* exists with the given ID, this function fails.
*
* Returns: The used ID if successful, -1 if it was already in use.
**/

View File

@@ -48,6 +48,8 @@
#include "gimplayermaskundo.h"
#include "gimplayerpropundo.h"
#include "gimplayerundo.h"
#include "gimplinklayer.h"
#include "gimplinklayerundo.h"
#include "gimpmaskundo.h"
#include "gimpsamplepoint.h"
#include "gimpsamplepointundo.h"
@@ -878,6 +880,25 @@ gimp_image_undo_push_text_layer_convert (GimpImage *image,
NULL);
}
/**********************/
/* Link Layer Undos */
/**********************/
GimpUndo *
gimp_image_undo_push_link_layer (GimpImage *image,
const gchar *undo_desc,
GimpLinkLayer *layer)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), NULL);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)), NULL);
return gimp_image_undo_push (image, GIMP_TYPE_LINK_LAYER_UNDO,
GIMP_UNDO_LINK_LAYER, undo_desc,
GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", layer,
NULL);
}
/************************/
/* Vector Layer Undos */
@@ -939,6 +960,7 @@ gimp_image_undo_push_layer_mask_add (GimpImage *image,
GIMP_DIRTY_IMAGE_STRUCTURE,
"item", layer,
"layer-mask", mask,
"edit-mask", FALSE,
NULL);
}
@@ -961,6 +983,7 @@ gimp_image_undo_push_layer_mask_remove (GimpImage *image,
GIMP_DIRTY_IMAGE_STRUCTURE,
"item", layer,
"layer-mask", mask,
"edit-mask", gimp_layer_get_edit_mask (layer),
NULL);
}

View File

@@ -214,6 +214,11 @@ GimpUndo * gimp_image_undo_push_text_layer_convert (GimpImage *image,
const gchar *undo_desc,
GimpTextLayer *layer);
/* link layer undos */
GimpUndo * gimp_image_undo_push_link_layer (GimpImage *image,
const gchar *undo_desc,
GimpLinkLayer *layer);
/* vector layer undos */

View File

@@ -71,6 +71,7 @@
#include "gimplayer-floating-selection.h"
#include "gimplayermask.h"
#include "gimplayerstack.h"
#include "gimplinklayer.h"
#include "gimpmarshal.h"
#include "gimppalette.h"
#include "gimpparasitelist.h"
@@ -3011,7 +3012,7 @@ gimp_image_get_xcf_version (GimpImage *image,
/* The blending space variant corresponding to SPACE_RGB_PERCEPTUAL in <3.0
* corresponds to R'G'B'A which is NON_LINEAR in babl. Perceptual in babl is
* R~G~B~A, >= 3.0 the code, comments and usage matches the existing enum value
* as being NON_LINEAR and new layers created use the new interger value for
* as being NON_LINEAR and new layers created use the new integer value for
* PERCEPTUAL.
*/
version = MAX (23, version);
@@ -3024,6 +3025,14 @@ gimp_image_get_xcf_version (GimpImage *image,
"GIMP 3.2"));
version = MAX (24, version);
}
/* Need version 25 for link layers. */
if (GIMP_IS_LINK_LAYER (layer))
{
ADD_REASON (g_strdup_printf (_("Link layers were added in %s"),
"GIMP 3.2"));
version = MAX (25, version);
}
}
g_list_free (items);
@@ -3157,7 +3166,7 @@ gimp_image_get_xcf_version (GimpImage *image,
/* Note: user unit storage was changed in XCF 21, but we can still
* easily save older XCF (we use the unit name for both singular and
* plural forms). Therefore we don't bump the XCF version unecessarily
* plural forms). Therefore we don't bump the XCF version unnecessarily
* and don't add any test.
*/
@@ -3204,6 +3213,7 @@ gimp_image_get_xcf_version (GimpImage *image,
if (version_string) *version_string = "GIMP 3.0";
break;
case 24:
case 25:
if (gimp_version) *gimp_version = 320;
if (version_string) *version_string = "GIMP 3.2";
break;

View File

@@ -548,10 +548,10 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
}
image = file_open_image (private->gimp, context, progress,
private->file, size, size,
private->file, size, size, TRUE,
FALSE, NULL,
GIMP_RUN_NONINTERACTIVE,
&status, &mime_type, error);
NULL, &status, &mime_type, error);
if (image)
gimp_thumbnail_set_info_from_image (private->thumbnail,

View File

@@ -1777,7 +1777,7 @@ gimp_item_transform (GimpItem *item,
g_object_freeze_notify (G_OBJECT (item));
item_class->transform (item, context, matrix, direction, interpolation,
clip_result, progress);
clip_result, progress, TRUE);
g_object_thaw_notify (G_OBJECT (item));

View File

@@ -107,7 +107,8 @@ struct _GimpItemClass
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
GimpTransformResize (* get_clip) (GimpItem *item,
GimpTransformResize clip_result);
gboolean (* fill) (GimpItem *item,

View File

@@ -169,7 +169,8 @@ static void gimp_layer_transform (GimpItem *item,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
static void gimp_layer_to_selection (GimpItem *item,
GimpChannelOps op,
gboolean antialias,
@@ -248,7 +249,8 @@ static void gimp_layer_real_transform (GimpLayer *layer,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
static void gimp_layer_real_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
@@ -989,10 +991,10 @@ gimp_layer_duplicate (GimpItem *item,
mask = gimp_item_duplicate (GIMP_ITEM (layer->mask),
G_TYPE_FROM_INSTANCE (layer->mask));
gimp_layer_add_mask (new_layer, GIMP_LAYER_MASK (mask), FALSE, NULL);
gimp_layer_add_mask (new_layer, GIMP_LAYER_MASK (mask),
layer->edit_mask, FALSE, NULL);
new_layer->apply_mask = layer->apply_mask;
new_layer->edit_mask = layer->edit_mask;
new_layer->show_mask = layer->show_mask;
}
}
@@ -1298,7 +1300,8 @@ gimp_layer_transform (GimpItem *item,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress)
GimpProgress *progress,
gboolean push_undo)
{
GimpLayer *layer = GIMP_LAYER (item);
GimpObjectQueue *queue = NULL;
@@ -1328,7 +1331,7 @@ gimp_layer_transform (GimpItem *item,
GIMP_LAYER_GET_CLASS (layer)->transform (layer, context, matrix, direction,
interpolation_type,
clip_result,
progress);
progress, push_undo);
if (layer->mask)
{
@@ -1743,7 +1746,8 @@ gimp_layer_real_transform (GimpLayer *layer,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress)
GimpProgress *progress,
gboolean push_undo)
{
if (! gimp_matrix3_is_simple (matrix) &&
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
@@ -1753,7 +1757,7 @@ gimp_layer_real_transform (GimpLayer *layer,
context, matrix, direction,
interpolation_type,
clip_result,
progress);
progress, push_undo);
}
static void
@@ -1913,6 +1917,7 @@ gimp_layer_get_mask (GimpLayer *layer)
GimpLayerMask *
gimp_layer_add_mask (GimpLayer *layer,
GimpLayerMask *mask,
gboolean edit_mask,
gboolean push_undo,
GError **error)
{
@@ -1954,7 +1959,7 @@ gimp_layer_add_mask (GimpLayer *layer,
layer->mask = g_object_ref_sink (mask);
layer->apply_mask = TRUE;
layer->edit_mask = TRUE;
layer->edit_mask = edit_mask;
layer->show_mask = FALSE;
gimp_layer_mask_set_layer (mask, layer);

View File

@@ -122,7 +122,8 @@ struct _GimpLayerClass
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
GimpProgress *progress,
gboolean push_undo);
void (* convert_type) (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
@@ -158,6 +159,7 @@ GimpLayerMask * gimp_layer_create_mask (GimpLayer *layer,
GimpChannel *channel);
GimpLayerMask * gimp_layer_add_mask (GimpLayer *layer,
GimpLayerMask *mask,
gboolean edit_mask,
gboolean push_undo,
GError **error);
void gimp_layer_apply_mask (GimpLayer *layer,

View File

@@ -33,7 +33,8 @@
enum
{
PROP_0,
PROP_LAYER_MASK
PROP_LAYER_MASK,
PROP_EDIT_MASK
};
@@ -83,6 +84,11 @@ gimp_layer_mask_undo_class_init (GimpLayerMaskUndoClass *klass)
GIMP_TYPE_LAYER_MASK,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_EDIT_MASK,
g_param_spec_boolean ("edit-mask", NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
@@ -114,6 +120,9 @@ gimp_layer_mask_undo_set_property (GObject *object,
case PROP_LAYER_MASK:
layer_mask_undo->layer_mask = g_value_dup_object (value);
break;
case PROP_EDIT_MASK:
layer_mask_undo->edit_mask = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -134,6 +143,9 @@ gimp_layer_mask_undo_get_property (GObject *object,
case PROP_LAYER_MASK:
g_value_set_object (value, layer_mask_undo->layer_mask);
break;
case PROP_EDIT_MASK:
g_value_set_boolean (value, layer_mask_undo->edit_mask);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -175,13 +187,15 @@ gimp_layer_mask_undo_pop (GimpUndo *undo,
{
/* remove layer mask */
layer_mask_undo->edit_mask = gimp_layer_get_edit_mask (layer);
gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);
}
else
{
/* restore layer mask */
gimp_layer_add_mask (layer, layer_mask_undo->layer_mask, FALSE, NULL);
gimp_layer_add_mask (layer, layer_mask_undo->layer_mask,
layer_mask_undo->edit_mask, FALSE, NULL);
}
}

View File

@@ -36,6 +36,7 @@ struct _GimpLayerMaskUndo
GimpItemUndo parent_instance;
GimpLayerMask *layer_mask;
gboolean edit_mask;
};
struct _GimpLayerMaskUndoClass

748
app/core/gimplink.c Normal file
View File

@@ -0,0 +1,748 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* GimpLink
* Copyright (C) 2019 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libgimpbase/gimpbase.h"
#include "core-types.h"
#include "gimp.h"
#include "gimpimage.h"
#include "gimplink.h"
#include "gimpmarshal.h"
#include "gimppickable.h"
#include "gimpprojection.h"
#include "file/file-open.h"
#include "gimp-intl.h"
enum
{
PROP_0,
PROP_GIMP,
PROP_FILE,
PROP_ABSOLUTE_PATH,
N_PROPS
};
enum
{
CHANGED,
LAST_SIGNAL
};
struct _GimpLinkPrivate
{
Gimp *gimp;
GFile *file;
GFileMonitor *monitor;
gboolean absolute_path;
GeglBuffer *buffer;
gboolean broken;
GError *error;
guint idle_changed_source;
gboolean is_vector;
gint width;
gint height;
gboolean keep_ratio;
GimpImageBaseType base_type;
GimpPrecision precision;
GimpPlugInProcedure *load_proc;
const gchar *mime_type;
};
static void gimp_link_finalize (GObject *object);
static void gimp_link_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_link_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_link_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
GimpLink *link);
static gboolean gimp_link_emit_changed (gpointer data);
static void gimp_link_update_buffer (GimpLink *link,
GimpProgress *progress,
GError **error);
static void gimp_link_start_monitoring (GimpLink *link);
static gchar * gimp_link_get_relative_path (GimpLink *link,
GFile *parent,
gint n_back);
G_DEFINE_TYPE_WITH_PRIVATE (GimpLink, gimp_link, GIMP_TYPE_OBJECT)
#define parent_class gimp_link_parent_class
static guint link_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *link_props[N_PROPS] = { NULL, };
static void
gimp_link_class_init (GimpLinkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
link_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpLinkClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->finalize = gimp_link_finalize;
object_class->get_property = gimp_link_get_property;
object_class->set_property = gimp_link_set_property;
link_props[PROP_GIMP] = g_param_spec_object ("gimp", NULL, NULL,
GIMP_TYPE_GIMP,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
link_props[PROP_FILE] = g_param_spec_object ("file", NULL, NULL,
G_TYPE_FILE,
GIMP_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
link_props[PROP_ABSOLUTE_PATH] = g_param_spec_boolean ("absolute-path", NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, link_props);
}
static void
gimp_link_init (GimpLink *link)
{
link->p = gimp_link_get_instance_private (link);
link->p->gimp = NULL;
link->p->file = NULL;
link->p->monitor = NULL;
link->p->buffer = NULL;
link->p->broken = TRUE;
link->p->error = NULL;
link->p->width = 0;
link->p->height = 0;
link->p->base_type = GIMP_RGB;
link->p->precision = GIMP_PRECISION_U8_PERCEPTUAL;
link->p->load_proc = NULL;
link->p->idle_changed_source = 0;
}
static void
gimp_link_finalize (GObject *object)
{
GimpLink *link = GIMP_LINK (object);
g_clear_object (&link->p->file);
g_clear_object (&link->p->monitor);
g_clear_object (&link->p->buffer);
g_clear_error (&link->p->error);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_link_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpLink *link = GIMP_LINK (object);
switch (property_id)
{
case PROP_GIMP:
g_value_set_object (value, link->p->gimp);
break;
case PROP_FILE:
g_value_set_object (value, link->p->file);
break;
case PROP_ABSOLUTE_PATH:
g_value_set_boolean (value, link->p->absolute_path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_link_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpLink *link = GIMP_LINK (object);
switch (property_id)
{
case PROP_GIMP:
link->p->gimp = g_value_get_object (value);
break;
case PROP_FILE:
gimp_link_set_file (link, g_value_get_object (value), 0, 0, FALSE, NULL, NULL);
break;
case PROP_ABSOLUTE_PATH:
link->p->absolute_path = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_link_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
GimpLink *link)
{
switch (event_type)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
if (link->p->idle_changed_source == 0)
link->p->idle_changed_source = g_idle_add_full (G_PRIORITY_LOW,
gimp_link_emit_changed,
link, NULL);
break;
case G_FILE_MONITOR_EVENT_CREATED:
g_signal_emit (link, link_signals[CHANGED], 0);
break;
case G_FILE_MONITOR_EVENT_DELETED:
link->p->broken = TRUE;
g_clear_error (&link->p->error);
g_set_error_literal (&link->p->error,
G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("The file got deleted"));
break;
default:
/* No need to signal for changes where nothing can be done anyway.
* In particular a file deletion, the link is broken, yet we don't
* want to re-render.
* Don't emit either on G_FILE_MONITOR_EVENT_CHANGED because too
* many such events may be emitted for a single file writing.
*/
break;
}
}
static gboolean
gimp_link_emit_changed (gpointer data)
{
GimpLink *link = GIMP_LINK (data);
gimp_link_update_buffer (link, NULL, NULL);
g_signal_emit (link, link_signals[CHANGED], 0);
link->p->idle_changed_source = 0;
return G_SOURCE_REMOVE;
}
static void
gimp_link_update_buffer (GimpLink *link,
GimpProgress *progress,
GError **error)
{
GeglBuffer *buffer = NULL;
GError *real_error = NULL;
g_return_if_fail (GIMP_IS_LINK (link));
g_return_if_fail (error == NULL || *error == NULL);
link->p->is_vector = FALSE;
g_clear_error (&link->p->error);
if (link->p->file)
{
GimpImage *image;
GimpPDBStatusType status;
link->p->mime_type = NULL;
image = file_open_image (link->p->gimp,
gimp_get_user_context (link->p->gimp),
progress,
link->p->file,
link->p->width, link->p->height,
link->p->keep_ratio,
FALSE, NULL,
/* XXX We might want interactive opening
* for a first opening (when done through
* GUI), but not for every re-render.
*/
GIMP_RUN_NONINTERACTIVE,
&link->p->is_vector,
&status, &link->p->mime_type,
&real_error);
if (image && status == GIMP_PDB_SUCCESS)
{
/* If we don't flush the projection first, the buffer may be empty.
* I do wonder if the flushing and updating of the link could
* not be multi-threaded with gimp_projection_flush() instead,
* then notifying the update through signals. For very heavy
* images, would it be a better UX? XXX
*/
gimp_projection_flush_now (gimp_image_get_projection (image), TRUE);
buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));
g_object_ref (buffer);
link->p->base_type = gimp_image_get_base_type (image);
link->p->precision = gimp_image_get_precision (image);
link->p->width = gimp_image_get_width (image);
link->p->height = gimp_image_get_height (image);
link->p->load_proc = gimp_image_get_load_proc (image);
}
/* Only keep the buffer, free the rest. */
g_clear_object (&image);
}
link->p->broken = (buffer == NULL);
if (link->p->broken)
{
if (real_error)
link->p->error = g_error_copy (real_error);
else
g_set_error_literal (&link->p->error,
G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("No file was set"));
}
if (error)
*error = real_error;
else
g_clear_error (&real_error);
if (buffer)
{
/* Keep the old buffer if the link is broken (outdated image is
* better than none).
*/
g_clear_object (&link->p->buffer);
link->p->buffer = buffer;
}
}
static void
gimp_link_start_monitoring (GimpLink *link)
{
link->p->monitor = g_file_monitor_file (link->p->file,
G_FILE_MONITOR_WATCH_HARD_LINKS,
NULL, NULL);
g_signal_connect (link->p->monitor, "changed",
G_CALLBACK (gimp_link_file_changed),
link);
}
/**
* gimp_link_get_relative_path:
* @link: the image this link is associated with.
* @parent: (transfer full): a #GFile object.
* @n_back: set it to 0 when calling it initially.
*
* This is a variant of g_file_get_relative_path() which will work even
* when the @link file is not a child of @parent. In this case, the
* relative link will use "../" as many times as necessary until a
* common parent folder is found.
*
* In case no parent is found (it may happen for instance on Windows,
* with various file system roots), an absolute path is returned
* instead, ensuring that we never return %NULL.
*
* Note that this function takes ownership of @parent and will take care
* of freeing it. This allows for tail recursion.
*
* Returns: a path from @link relatively to @parent, falling back
* to an absolute path if a relative path cannot be constructed.
**/
static gchar *
gimp_link_get_relative_path (GimpLink *link,
GFile *parent,
gint n_back)
{
gchar *relative_path;
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
g_return_val_if_fail (parent != NULL && n_back >= 0, NULL);
relative_path = g_file_get_relative_path (parent, link->p->file);
if (relative_path == NULL)
{
GFile *grand_parent = g_file_get_parent (parent);
g_object_unref (parent);
if (grand_parent == NULL)
/* This may happen e.g. on Windows where there are several roots
* so it is not always possible to make a relative path.
*/
return g_file_get_path (link->p->file);
else
return gimp_link_get_relative_path (link, grand_parent, n_back + 1);
}
else
{
g_object_unref (parent);
if (n_back > 0)
{
GStrvBuilder *builder;
gchar **array;
gchar *dots;
gchar *relpath;
builder = g_strv_builder_new ();
for (gint i = 0; i < n_back; i++)
g_strv_builder_add (builder, "..");
array = g_strv_builder_end (builder);
dots = g_strjoinv (G_DIR_SEPARATOR_S, array);
relpath = g_build_filename (dots, relative_path, NULL);
g_free (relative_path);
g_free (dots);
g_strfreev (array);
g_strv_builder_unref (builder);
relative_path = relpath;
}
return relative_path;
}
}
/* public functions */
/**
* gimp_link_new:
* @gimp: #Gimp object.
* @file: a #GFile object.
*
* Creates a new link object. By default, all link objects are created
* as being relative to the path of the image they will be associated
* with.
*
* Return value: a new #GimpLink or %NULL in case of a problem
**/
GimpLink *
gimp_link_new (Gimp *gimp,
GFile *file,
gint vector_width,
gint vector_height,
gboolean keep_ratio,
GimpProgress *progress,
GError **error)
{
GimpLink *link;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
link = g_object_new (GIMP_TYPE_LINK,
"gimp", gimp,
"absolute-path", FALSE,
NULL);
gimp_link_set_file (link, file, vector_width, vector_height, keep_ratio, progress, error);
return GIMP_LINK (link);
}
GimpLink *
gimp_link_duplicate (GimpLink *link)
{
GimpLink *new_link;
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
new_link = g_object_new (GIMP_TYPE_LINK,
"gimp", link->p->gimp,
"absolute-path", gimp_link_get_absolute_path (link),
NULL);
/* Copy things manually as we do not need to trigger a load. */
new_link->p->file = link->p->file ? g_object_ref (link->p->file) : NULL;
new_link->p->buffer = link->p->buffer ? gegl_buffer_dup (link->p->buffer) : NULL;
new_link->p->broken = link->p->broken;
new_link->p->error = link->p->error ? g_error_copy (link->p->error) : NULL;
new_link->p->is_vector = link->p->is_vector;
new_link->p->width = link->p->width;
new_link->p->height = link->p->height;
new_link->p->base_type = link->p->base_type;
new_link->p->precision = link->p->precision;
new_link->p->load_proc = link->p->load_proc;
if (new_link->p->file)
{
gchar *basename;
basename = g_file_get_basename (new_link->p->file);
gimp_object_set_name_safe (GIMP_OBJECT (new_link), basename);
g_free (basename);
if (gimp_link_is_monitored (link))
gimp_link_start_monitoring (new_link);
}
return new_link;
}
/*
* gimp_link_get_file:
* @link: the #GimpLink object.
* @xcf_file: optional XCF file from which @path will be relative to.
* @path: optional returned path of the returned file.
*
* If @path is non-%NULL, it will be set to the file system path for the
* returned %GFile, either as an absolute or relative path, depending on
* how @link was set.
* Note that it is possible for @path to be absolute even when it is set
* to be a relative path, in cases where no relative path can be
* constructed from @xcf_file.
*
* Returns: the %GFile which %link is syncing too.
*/
GFile *
gimp_link_get_file (GimpLink *link,
GFile *xcf_file,
gchar **path)
{
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
g_return_val_if_fail ((path == NULL && xcf_file == NULL) ||
(*path == NULL && xcf_file != NULL &&
g_file_has_parent (xcf_file, NULL)), NULL);
if (path != NULL)
{
if (link->p->absolute_path)
*path = g_file_get_path (link->p->file);
else
*path = gimp_link_get_relative_path (link,
g_file_get_parent (xcf_file),
0);
}
return link->p->file;
}
void
gimp_link_set_file (GimpLink *link,
GFile *file,
gint vector_width,
gint vector_height,
gboolean keep_ratio,
GimpProgress *progress,
GError **error)
{
g_return_if_fail (GIMP_IS_LINK (link));
g_return_if_fail (G_IS_FILE (file) || file == NULL);
g_return_if_fail (error == NULL || *error == NULL);
if (file == link->p->file ||
(file && link->p->file && g_file_equal (file, link->p->file)))
{
if (link->p->width != vector_width ||
link->p->height != vector_height ||
link->p->keep_ratio != keep_ratio)
gimp_link_set_size (link, vector_width, vector_height, keep_ratio);
return;
}
link->p->width = vector_width;
link->p->height = vector_height;
link->p->keep_ratio = keep_ratio;
g_clear_object (&link->p->monitor);
g_set_object (&link->p->file, file);
gimp_link_update_buffer (link, progress, error);
if (link->p->file)
{
gchar *basename;
basename = g_file_get_basename (link->p->file);
gimp_object_set_name_safe (GIMP_OBJECT (link), basename);
g_free (basename);
gimp_link_start_monitoring (link);
}
g_object_notify_by_pspec (G_OBJECT (link), link_props[PROP_FILE]);
}
gboolean
gimp_link_get_absolute_path (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
return link->p->absolute_path;
}
void
gimp_link_set_absolute_path (GimpLink *link,
gboolean absolute_path)
{
g_return_if_fail (GIMP_IS_LINK (link));
link->p->absolute_path = absolute_path;
}
const gchar *
gimp_link_get_mime_type (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
return link->p->mime_type;
}
void
gimp_link_freeze (GimpLink *link)
{
g_return_if_fail (GIMP_IS_LINK (link));
g_return_if_fail (link->p->monitor != NULL);
g_clear_object (&link->p->monitor);
}
void
gimp_link_thaw (GimpLink *link)
{
g_return_if_fail (GIMP_IS_LINK (link));
g_return_if_fail (G_IS_FILE (link->p->file) && link->p->monitor == NULL);
gimp_link_update_buffer (link, NULL, NULL);
gimp_link_start_monitoring (link);
}
gboolean
gimp_link_is_monitored (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
return (link->p->monitor != NULL);
}
gboolean
gimp_link_is_broken (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), TRUE);
return link->p->broken;
}
void
gimp_link_set_size (GimpLink *link,
gint width,
gint height,
gboolean keep_ratio)
{
g_return_if_fail (GIMP_IS_LINK (link));
link->p->width = width;
link->p->height = height;
link->p->keep_ratio = keep_ratio;
if (link->p->monitor && link->p->is_vector)
gimp_link_update_buffer (link, NULL, NULL);
}
void
gimp_link_get_size (GimpLink *link,
gint *width,
gint *height)
{
g_return_if_fail (GIMP_IS_LINK (link));
*width = link->p->width;
*height = link->p->height;
}
GimpImageBaseType
gimp_link_get_base_type (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, GIMP_RGB);
return link->p->base_type;
}
GimpPrecision
gimp_link_get_precision (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, GIMP_PRECISION_U8_PERCEPTUAL);
return link->p->precision;
}
GimpPlugInProcedure *
gimp_link_get_load_proc (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, NULL);
return link->p->load_proc;
}
gboolean
gimp_link_is_vector (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
return link->p->is_vector;
}
GeglBuffer *
gimp_link_get_buffer (GimpLink *link)
{
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
return link->p->buffer;
}

98
app/core/gimplink.h Normal file
View File

@@ -0,0 +1,98 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* GimpLink
* Copyright (C) 2019 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gimpitem.h"
#define GIMP_TYPE_LINK (gimp_link_get_type ())
#define GIMP_LINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LINK, GimpLink))
#define GIMP_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LINK, GimpLinkClass))
#define GIMP_IS_LINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LINK))
#define GIMP_IS_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LINK))
#define GIMP_LINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LINK, GimpLinkClass))
typedef struct _GimpLinkClass GimpLinkClass;
typedef struct _GimpLinkPrivate GimpLinkPrivate;
struct _GimpLink
{
GimpObject parent_instance;
GimpLinkPrivate *p;
};
struct _GimpLinkClass
{
GimpObjectClass parent_class;
void (* changed) (GimpLink *link);
};
GType gimp_link_get_type (void) G_GNUC_CONST;
GimpLink * gimp_link_new (Gimp *gimp,
GFile *file,
gint vector_width,
gint vector_height,
gboolean keep_ratio,
GimpProgress *progress,
GError **error);
GimpLink * gimp_link_duplicate (GimpLink *link);
GFile * gimp_link_get_file (GimpLink *link,
GFile *parent,
gchar **path);
void gimp_link_set_file (GimpLink *layer,
GFile *file,
gint vector_width,
gint vector_height,
gboolean keep_ratio,
GimpProgress *progress,
GError **error);
gboolean gimp_link_get_absolute_path (GimpLink *link);
void gimp_link_set_absolute_path (GimpLink *link,
gboolean absolute_path);
const gchar * gimp_link_get_mime_type (GimpLink *link);
void gimp_link_freeze (GimpLink *link);
void gimp_link_thaw (GimpLink *link);
gboolean gimp_link_is_monitored (GimpLink *link);
gboolean gimp_link_is_broken (GimpLink *link);
void gimp_link_set_size (GimpLink *link,
gint width,
gint height,
gboolean keep_ratio);
void gimp_link_get_size (GimpLink *link,
gint *width,
gint *height);
GimpImageBaseType gimp_link_get_base_type (GimpLink *link);
GimpPrecision gimp_link_get_precision (GimpLink *link);
GimpPlugInProcedure * gimp_link_get_load_proc (GimpLink *link);
gboolean gimp_link_is_vector (GimpLink *link);
GeglBuffer * gimp_link_get_buffer (GimpLink *link);

1137
app/core/gimplinklayer.c Normal file

File diff suppressed because it is too large Load Diff

87
app/core/gimplinklayer.h Normal file
View File

@@ -0,0 +1,87 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* GimpLinkLayer
* Copyright (C) 2019 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gimplayer.h"
#define GIMP_TYPE_LINK_LAYER (gimp_link_layer_get_type ())
#define GIMP_LINK_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LINK_LAYER, GimpLinkLayer))
#define GIMP_LINK_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LINK_LAYER, GimpLinkLayerClass))
#define GIMP_IS_LINK_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LINK_LAYER))
#define GIMP_IS_LINK_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LINK_LAYER))
#define GIMP_LINK_LAYER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LINK_LAYER, GimpLinkLayerClass))
typedef struct _GimpLinkLayerClass GimpLinkLayerClass;
typedef struct _GimpLinkLayerPrivate GimpLinkLayerPrivate;
struct _GimpLinkLayer
{
GimpLayer layer;
GimpLinkLayerPrivate *p;
};
struct _GimpLinkLayerClass
{
GimpLayerClass parent_class;
};
GType gimp_link_layer_get_type (void) G_GNUC_CONST;
GimpLayer * gimp_link_layer_new (GimpImage *image,
GimpLink *link);
GimpLink * gimp_link_layer_get_link (GimpLinkLayer *layer);
gboolean gimp_link_layer_set_link (GimpLinkLayer *layer,
GimpLink *link,
gboolean push_undo);
gboolean gimp_link_layer_set_link_with_matrix (GimpLinkLayer *layer,
GimpLink *link,
GimpMatrix3 *matrix,
GimpInterpolationType interpolation_type,
gint offset_x,
gint offset_y,
gboolean push_undo);
void gimp_link_layer_discard (GimpLinkLayer *layer);
void gimp_link_layer_monitor (GimpLinkLayer *layer);
gboolean gimp_link_layer_is_monitored (GimpLinkLayer *layer);
gboolean gimp_link_layer_get_transform (GimpLinkLayer *layer,
GimpMatrix3 *matrix,
gint *offset_x,
gint *offset_y,
GimpInterpolationType *interpolation);
gboolean gimp_link_layer_set_transform (GimpLinkLayer *layer,
GimpMatrix3 *matrix,
GimpInterpolationType interpolation_type,
gboolean push_undo);
gboolean gimp_item_is_link_layer (GimpItem *item);
/* Only to be used for XCF loading/saving. */
guint32 gimp_link_layer_get_xcf_flags (GimpLinkLayer *layer);
void gimp_link_layer_set_xcf_flags (GimpLinkLayer *layer,
guint32 flags);

View File

@@ -0,0 +1,218 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2019 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "core-types.h"
#include "gimpimage.h"
#include "gimplayer.h"
#include "gimplink.h"
#include "gimplinklayer.h"
#include "gimplinklayerundo.h"
enum
{
PROP_0,
PROP_PREV_LINK
};
static void gimp_link_layer_undo_constructed (GObject *object);
static void gimp_link_layer_undo_finalize (GObject *object);
static void gimp_link_layer_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_link_layer_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gint64 gimp_link_layer_undo_get_memsize (GimpObject *object,
gint64 *gui_size);
static void gimp_link_layer_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
G_DEFINE_TYPE (GimpLinkLayerUndo, gimp_link_layer_undo, GIMP_TYPE_ITEM_UNDO)
#define parent_class gimp_link_layer_undo_parent_class
static void
gimp_link_layer_undo_class_init (GimpLinkLayerUndoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
object_class->constructed = gimp_link_layer_undo_constructed;
object_class->finalize = gimp_link_layer_undo_finalize;
object_class->set_property = gimp_link_layer_undo_set_property;
object_class->get_property = gimp_link_layer_undo_get_property;
gimp_object_class->get_memsize = gimp_link_layer_undo_get_memsize;
undo_class->pop = gimp_link_layer_undo_pop;
g_object_class_install_property (object_class, PROP_PREV_LINK,
g_param_spec_object ("prev-link",
NULL, NULL,
GIMP_TYPE_LINK,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
gimp_link_layer_undo_init (GimpLinkLayerUndo *undo)
{
}
static void
gimp_link_layer_undo_constructed (GObject *object)
{
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
GimpLinkLayer *layer;
GimpLink *link;
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_LINK_LAYER (GIMP_ITEM_UNDO (object)->item));
layer = GIMP_LINK_LAYER (GIMP_ITEM_UNDO (undo)->item);
link = gimp_link_layer_get_link (layer);
undo->link = link ? gimp_link_duplicate (link) : NULL;
gimp_link_layer_get_transform (layer,
&undo->matrix,
&undo->offset_x,
&undo->offset_y,
&undo->interpolation);
}
static void
gimp_link_layer_undo_finalize (GObject *object)
{
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
g_clear_object (&undo->link);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_link_layer_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
switch (property_id)
{
case PROP_PREV_LINK:
g_clear_object (&undo->link);
undo->link = g_value_get_object (value) ? gimp_link_duplicate (g_value_get_object (value)) : NULL;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_link_layer_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpLinkLayerUndo *undo = GIMP_LINK_LAYER_UNDO (object);
switch (property_id)
{
case PROP_PREV_LINK:
g_value_set_object (value, undo->link);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gint64
gimp_link_layer_undo_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpItemUndo *item_undo = GIMP_ITEM_UNDO (object);
gint64 memsize = 0;
if (! gimp_item_is_attached (item_undo->item))
memsize += gimp_object_get_memsize (GIMP_OBJECT (item_undo->item),
gui_size);
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static void
gimp_link_layer_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
GimpLinkLayerUndo *layer_undo = GIMP_LINK_LAYER_UNDO (undo);
GimpLinkLayer *layer = GIMP_LINK_LAYER (GIMP_ITEM_UNDO (undo)->item);
GimpLink *link;
GimpMatrix3 matrix;
gint offset_x;
gint offset_y;
GimpInterpolationType interpolation;
GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
link = gimp_link_layer_get_link (layer);
link = link ? g_object_ref (link) : NULL;
gimp_link_layer_get_transform (layer, &matrix, &offset_x, &offset_y, &interpolation);
gimp_link_layer_set_link_with_matrix (layer, layer_undo->link,
&layer_undo->matrix,
layer_undo->interpolation,
layer_undo->offset_x,
layer_undo->offset_y,
FALSE);
layer_undo->matrix = matrix;
layer_undo->interpolation = interpolation;
layer_undo->offset_x = offset_x;
layer_undo->offset_y = offset_y;
g_clear_object (&layer_undo->link);
layer_undo->link = link;
}

View File

@@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2019 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gimpitemundo.h"
#define GIMP_TYPE_LINK_LAYER_UNDO (gimp_link_layer_undo_get_type ())
#define GIMP_LINK_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LINK_LAYER_UNDO, GimpLinkLayerUndo))
#define GIMP_LINK_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LINK_LAYER_UNDO, GimpLinkLayerUndoClass))
#define GIMP_IS_LINK_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LINK_LAYER_UNDO))
#define GIMP_IS_LINK_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LINK_LAYER_UNDO))
#define GIMP_LINK_LAYER_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LINK_LAYER_UNDO, GimpLinkLayerUndoClass))
typedef struct _GimpLinkLayerUndo GimpLinkLayerUndo;
typedef struct _GimpLinkLayerUndoClass GimpLinkLayerUndoClass;
struct _GimpLinkLayerUndo
{
GimpItemUndo parent_instance;
GimpLink *link;
GimpMatrix3 matrix;
gint offset_x;
gint offset_y;
GimpInterpolationType interpolation;
};
struct _GimpLinkLayerUndoClass
{
GimpItemUndoClass parent_class;
};
GType gimp_link_layer_undo_get_type (void) G_GNUC_CONST;

View File

@@ -872,7 +872,7 @@ gimp_palette_load_acb (GimpContext *context,
{
g_free (palette_entry);
g_free (full_palette_name);
g_object_unref (color);
g_clear_object (&color);
g_printerr ("Invalid ACB palette color code");
break;
@@ -880,63 +880,65 @@ gimp_palette_load_acb (GimpContext *context,
if (color_space == 0)
{
gchar rgb[3];
guchar rgb[3];
if (! g_input_stream_read_all (input, rgb, sizeof (rgb),
&bytes_read, NULL, error))
{
g_free (palette_entry);
g_free (full_palette_name);
g_object_unref (color);
g_clear_object (&color);
g_printerr ("Invalid ACB palette colors");
break;
}
gegl_color_set_pixel (color, babl_format ("R'G'B u8"), rgb);
gegl_color_set_pixel (color, babl_format ("R'G'B' u8"), rgb);
color_ok = TRUE;
}
else if (color_space == 2)
{
gchar cmyk[4];
guchar cmyk[4];
gfloat cmyk_f[4];
if (! g_input_stream_read_all (input, cmyk, sizeof (cmyk),
&bytes_read, NULL, error))
{
g_free (palette_entry);
g_free (full_palette_name);
g_object_unref (color);
g_clear_object (&color);
g_printerr ("Invalid ACB palette colors");
break;
}
for (gint j = 0; j < 4; j++)
cmyk[j] = ((255 - cmyk[j]) / 2.55f) + 0.5f;
cmyk_f[j] = (((255 - cmyk[j]) / 2.55f) + 0.5f) / 100.0f;
gegl_color_set_pixel (color, babl_format ("cmyk u8"), cmyk);
gegl_color_set_pixel (color, babl_format ("CMYK float"), cmyk_f);
color_ok = TRUE;
}
else if (color_space == 7)
{
gchar lab[3];
guchar lab[3];
gfloat lab_f[3];
if (! g_input_stream_read_all (input, lab, sizeof (lab),
&bytes_read, NULL, error))
{
g_free (palette_entry);
g_free (full_palette_name);
g_object_unref (color);
g_clear_object (&color);
g_printerr ("Invalid ACB palette colors");
break;
}
lab[0] = (lab[0] / 2.55f) + 0.5f;
lab[1] = lab[1] - 128;
lab[2] = lab[2] - 128;
lab_f[0] = (lab[0] / 2.55f) + 0.5f;
lab_f[1] = ((gfloat) lab[1]) - 128;
lab_f[2] = ((gfloat) lab[2]) - 128;
gegl_color_set_pixel (color, babl_format ("CIE Lab u8"), lab);
gegl_color_set_pixel (color, babl_format ("CIE Lab float"), lab_f);
color_ok = TRUE;
}
@@ -945,7 +947,7 @@ gimp_palette_load_acb (GimpContext *context,
g_free (palette_entry);
g_free (full_palette_name);
g_object_unref (color);
g_clear_object (&color);
if (! color_ok)
{

View File

@@ -496,11 +496,7 @@ gimp_palette_restrict_format (GimpPalette *palette,
if (push_undo_if_image && gimp_data_get_image (GIMP_DATA (palette)))
gimp_image_undo_push_image_colormap (gimp_data_get_image (GIMP_DATA (palette)),
/* TODO: use localized string
* after string freeze.
*/
/*C_("undo-type", "Change Colormap format restriction"));*/
"Change Colormap format restriction");
C_("undo-type", "Change Colormap format restriction"));
palette->format = format;
if (palette->format == NULL)

View File

@@ -36,6 +36,7 @@
#include "gimpimage.h"
#include "gimplayer.h"
#include "gimplayermask.h"
#include "gimplinklayer.h"
#include "gimppalette.h"
#include "gimpparamspecs.h"
#include "gimppattern.h"

View File

@@ -194,6 +194,9 @@ libappcore_sources = [
'gimplayerstack.c',
'gimplayerundo.c',
'gimplineart.c',
'gimplink.c',
'gimplinklayer.c',
'gimplinklayerundo.c',
'gimplist.c',
'gimpmaskundo.c',
'gimpmybrush-load.c',
@@ -274,6 +277,7 @@ libappcore = static_library('appcore',
cairo,
gegl,
gdk_pixbuf,
libarchive,
libmypaint,
gexiv2,
appstream,

View File

@@ -512,17 +512,24 @@ about_dialog_add_update (GimpAboutDialog *dialog,
if (config->check_update_timestamp > 0)
{
gchar *subtext;
gchar *time;
datetime = g_date_time_new_from_unix_local (config->check_update_timestamp);
gchar *subtext;
gchar *time;
#if defined(PLATFORM_OSX)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSDate *current_date = [NSDate date];
NSString *formatted_date;
NSString *formatted_time;
#elif defined(G_OS_WIN32)
SYSTEMTIME st;
int date_len, time_len;
wchar_t *date_buf = NULL;
wchar_t *time_buf = NULL;
#endif
datetime = g_date_time_new_from_unix_local (config->check_update_timestamp);
#if defined(PLATFORM_OSX)
formatter.locale = [NSLocale currentLocale];
formatter.dateStyle = NSDateFormatterShortStyle;
@@ -546,11 +553,6 @@ about_dialog_add_update (GimpAboutDialog *dialog,
[formatter release];
[pool drain];
#elif defined(G_OS_WIN32)
SYSTEMTIME st;
int date_len, time_len;
wchar_t *date_buf = NULL;
wchar_t *time_buf = NULL;
GetLocalTime (&st);
date_len = GetDateFormatEx (LOCALE_NAME_USER_DEFAULT, 0, &st,

View File

@@ -55,11 +55,13 @@ static void file_open_dialog_response (GtkWidget *dialog,
static GimpImage *file_open_dialog_open_image (GtkWidget *dialog,
Gimp *gimp,
GFile *file,
GimpPlugInProcedure *load_proc);
GimpPlugInProcedure *load_proc,
gboolean as_link);
static gboolean file_open_dialog_open_layers (GtkWidget *dialog,
GimpImage *image,
GFile *file,
GimpPlugInProcedure *load_proc);
GimpPlugInProcedure *load_proc,
gboolean as_link);
/* public functions */
@@ -147,13 +149,14 @@ file_open_dialog_response (GtkWidget *dialog,
{
if (! file_dialog->image)
{
gimp_open_dialog_set_image (
open_dialog,
file_open_dialog_open_image (dialog,
gimp,
file,
file_dialog->file_proc),
TRUE);
gimp_open_dialog_set_image (open_dialog,
file_open_dialog_open_image (dialog,
gimp,
file,
file_dialog->file_proc,
open_dialog->open_as_link),
TRUE,
open_dialog->open_as_link);
if (file_dialog->image)
{
@@ -170,7 +173,8 @@ file_open_dialog_response (GtkWidget *dialog,
else if (file_open_dialog_open_layers (dialog,
file_dialog->image,
file,
file_dialog->file_proc))
file_dialog->file_proc,
open_dialog->open_as_link))
{
success = TRUE;
}
@@ -180,7 +184,8 @@ file_open_dialog_response (GtkWidget *dialog,
if (file_open_dialog_open_image (dialog,
gimp,
file,
file_dialog->file_proc))
file_dialog->file_proc,
open_dialog->open_as_link))
{
success = TRUE;
@@ -227,7 +232,8 @@ static GimpImage *
file_open_dialog_open_image (GtkWidget *dialog,
Gimp *gimp,
GFile *file,
GimpPlugInProcedure *load_proc)
GimpPlugInProcedure *load_proc,
gboolean as_link)
{
GimpImage *image;
GimpPDBStatusType status;
@@ -236,16 +242,21 @@ file_open_dialog_open_image (GtkWidget *dialog,
image = file_open_with_proc_and_display (gimp,
gimp_get_user_context (gimp),
GIMP_PROGRESS (dialog),
file, FALSE,
file, FALSE, as_link,
load_proc,
G_OBJECT (gimp_widget_get_monitor (dialog)),
&status, &error);
if (! image && status != GIMP_PDB_SUCCESS && status != GIMP_PDB_CANCEL)
{
gimp_message (gimp, G_OBJECT (dialog), GIMP_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
gimp_file_get_utf8_name (file), error->message);
if (error)
gimp_message (gimp, G_OBJECT (dialog), GIMP_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
gimp_file_get_utf8_name (file), error->message);
else
gimp_message (gimp, G_OBJECT (dialog), GIMP_MESSAGE_ERROR,
_("Opening '%s' failed."),
gimp_file_get_utf8_name (file));
g_clear_error (&error);
}
@@ -256,7 +267,8 @@ static gboolean
file_open_dialog_open_layers (GtkWidget *dialog,
GimpImage *image,
GFile *file,
GimpPlugInProcedure *load_proc)
GimpPlugInProcedure *load_proc,
gboolean as_link)
{
GList *new_layers;
GimpPDBStatusType status;
@@ -265,7 +277,7 @@ file_open_dialog_open_layers (GtkWidget *dialog,
new_layers = file_open_layers (image->gimp,
gimp_get_user_context (image->gimp),
GIMP_PROGRESS (dialog),
image, FALSE,
image, FALSE, as_link,
file, GIMP_RUN_INTERACTIVE, load_proc,
&status, &error);

View File

@@ -204,7 +204,7 @@ file_open_location_response (GtkDialog *dialog,
image = file_open_with_proc_and_display (gimp,
gimp_get_user_context (gimp),
GIMP_PROGRESS (box),
file, FALSE, NULL,
file, FALSE, FALSE, NULL,
G_OBJECT (gimp_widget_get_monitor (entry)),
&status, &error);

View File

@@ -322,6 +322,21 @@ item_options_dialog_get_vbox (GtkWidget *dialog)
return private->left_vbox;
}
GtkWidget *
item_options_dialog_get_right_vbox (GtkWidget *dialog)
{
ItemOptionsDialog *private;
g_return_val_if_fail (GIMP_IS_VIEWABLE_DIALOG (dialog), NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
return private->right_vbox;
}
GtkWidget *
item_options_dialog_get_grid (GtkWidget *dialog,
gint *next_row)

View File

@@ -55,6 +55,7 @@ GtkWidget * item_options_dialog_new (GimpImage *image,
gpointer user_data);
GtkWidget * item_options_dialog_get_vbox (GtkWidget *dialog);
GtkWidget * item_options_dialog_get_right_vbox (GtkWidget *dialog);
GtkWidget * item_options_dialog_get_grid (GtkWidget *dialog,
gint *next_row);
GtkWidget * item_options_dialog_get_name_entry (GtkWidget *dialog);

View File

@@ -50,6 +50,7 @@ struct _LayerAddMaskDialog
GimpAddMaskType add_mask_type;
GimpChannel *channel;
gboolean invert;
gboolean edit_mask;
GimpAddMaskCallback callback;
gpointer user_data;
};
@@ -73,12 +74,14 @@ layer_add_mask_dialog_new (GList *layers,
GtkWidget *parent,
GimpAddMaskType add_mask_type,
gboolean invert,
gboolean edit_mask,
GimpAddMaskCallback callback,
gpointer user_data)
{
LayerAddMaskDialog *private;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *combo;
GtkWidget *button;
@@ -98,6 +101,7 @@ layer_add_mask_dialog_new (GList *layers,
private->layers = layers;
private->add_mask_type = add_mask_type;
private->invert = invert;
private->edit_mask = edit_mask;
private->callback = callback;
private->user_data = user_data;
@@ -180,15 +184,28 @@ layer_add_mask_dialog_new (GList *layers,
gimp_container_view_set_1_selected (GIMP_CONTAINER_VIEW (combo),
GIMP_VIEWABLE (channel));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
button = gtk_check_button_new_with_mnemonic (_("In_vert mask"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), private->invert);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&private->invert);
button = gtk_check_button_new_with_mnemonic (_("_Edit mask immediately"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), private->edit_mask);
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&private->edit_mask);
return dialog;
}
@@ -224,6 +241,7 @@ layer_add_mask_dialog_response (GtkWidget *dialog,
private->add_mask_type,
private->channel,
private->invert,
private->edit_mask,
private->user_data);
}
else

View File

@@ -23,6 +23,7 @@ typedef void (* GimpAddMaskCallback) (GtkWidget *dialog,
GimpAddMaskType add_mask_type,
GimpChannel *channel,
gboolean invert,
gboolean edit_mask,
gpointer user_data);
@@ -31,5 +32,6 @@ GtkWidget * layer_add_mask_dialog_new (GList *layers,
GtkWidget *parent,
GimpAddMaskType add_mask_type,
gboolean invert,
gboolean edit_mask,
GimpAddMaskCallback callback,
gpointer user_data);

View File

@@ -32,12 +32,15 @@
#include "core/gimpdrawable-filters.h"
#include "core/gimpimage.h"
#include "core/gimplayer.h"
#include "core/gimplink.h"
#include "core/gimplinklayer.h"
#include "text/gimptext.h"
#include "text/gimptextlayer.h"
#include "widgets/gimpcontainerlistview.h"
#include "widgets/gimplayermodebox.h"
#include "widgets/gimpopendialog.h"
#include "widgets/gimpviewabledialog.h"
#include "item-options-dialog.h"
@@ -50,6 +53,7 @@ typedef struct _LayerOptionsDialog LayerOptionsDialog;
struct _LayerOptionsDialog
{
Gimp *gimp;
GimpLayer *layer;
GimpLayerMode mode;
GimpLayerColorSpace blend_space;
@@ -68,6 +72,8 @@ struct _LayerOptionsDialog
GtkWidget *composite_mode_combo;
GtkWidget *size_se;
GtkWidget *offset_se;
GimpLink *link;
};
@@ -93,6 +99,9 @@ static void layer_options_dialog_mode_notify (GtkWidget *widget,
static void layer_options_dialog_rename_toggled (GtkWidget *widget,
LayerOptionsDialog *private);
static void layer_options_file_set (GtkFileChooserButton *widget,
LayerOptionsDialog *private);
/* public functions */
@@ -127,6 +136,7 @@ layer_options_dialog_new (GimpImage *image,
GtkWidget *grid;
GtkListStore *space_model;
GtkWidget *combo;
GtkWidget *file_select;
GtkWidget *scale;
GtkWidget *label;
GtkAdjustment *adjustment;
@@ -144,6 +154,7 @@ layer_options_dialog_new (GimpImage *image,
private = g_slice_new0 (LayerOptionsDialog);
private->gimp = image->gimp;
private->layer = layer;
private->mode = layer_mode;
private->blend_space = layer_blend_space;
@@ -156,6 +167,8 @@ layer_options_dialog_new (GimpImage *image,
private->callback = callback;
private->user_data = user_data;
private->link = NULL;
if (layer && gimp_item_is_text_layer (GIMP_ITEM (layer)))
private->rename_text_layers = GIMP_TEXT_LAYER (layer)->auto_rename;
@@ -372,19 +385,6 @@ layer_options_dialog_new (GimpImage *image,
row += 2;
if (! layer)
{
/* The fill type */
combo = gimp_enum_combo_box_new (GIMP_TYPE_FILL_TYPE);
gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++,
_("_Fill with:"), 0.0, 0.5,
combo, 1);
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
private->fill_type,
G_CALLBACK (gimp_int_combo_box_get_active),
&private->fill_type, NULL);
}
if (layer)
{
GtkWidget *left_vbox = item_options_dialog_get_vbox (dialog);
@@ -402,6 +402,57 @@ layer_options_dialog_new (GimpImage *image,
GIMP_VIEW_SIZE_SMALL, 0);
gtk_container_add (GTK_CONTAINER (frame), view);
gtk_widget_show (view);
if (GIMP_IS_LINK_LAYER (layer))
{
GtkWidget *open_dialog;
GimpLink *link;
/* File chooser dialog. */
open_dialog = gimp_open_dialog_new (private->gimp);
gtk_window_set_title (GTK_WINDOW (open_dialog),
_("Select Linked Image"));
/* File chooser button. */
file_select = gtk_file_chooser_button_new_with_dialog (open_dialog);
link = gimp_link_layer_get_link (GIMP_LINK_LAYER (layer));
gtk_file_chooser_set_file (GTK_FILE_CHOOSER (file_select),
gimp_link_get_file (link, NULL, NULL),
NULL);
gtk_widget_show (file_select);
gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++,
_("_Linked image:"), 0.0, 0.5,
file_select, 1);
g_signal_connect (file_select, "file-set",
G_CALLBACK (layer_options_file_set),
private);
private->link = gimp_link_duplicate (link);
/* Absolute path checkbox. */
button = gtk_check_button_new_with_mnemonic (_("S_tore with absolute path"));
gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++,
NULL, 0.0, 0.5,
button, 2);
g_object_bind_property (G_OBJECT (private->link), "absolute-path",
G_OBJECT (button), "active",
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
gtk_widget_set_visible (button, TRUE);
}
}
else
{
/* The fill type */
combo = gimp_enum_combo_box_new (GIMP_TYPE_FILL_TYPE);
gimp_grid_attach_aligned (GTK_GRID (grid), 0, row,
_("_Fill with:"), 0.0, 0.5,
combo, 1);
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
private->fill_type,
G_CALLBACK (gimp_int_combo_box_get_active),
&private->fill_type, NULL);
}
button = item_options_dialog_get_lock_position (dialog);
@@ -502,6 +553,7 @@ layer_options_dialog_callback (GtkWidget *dialog,
private->composite_mode,
private->opacity / 100.0,
private->fill_type,
private->link,
width,
height,
offset_x,
@@ -574,3 +626,45 @@ layer_options_dialog_rename_toggled (GtkWidget *widget,
}
}
}
static void
layer_options_file_set (GtkFileChooserButton *widget,
LayerOptionsDialog *private)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (widget));
if (file)
{
gint width = 0;
gint height = 0;
if (private->layer)
{
width = gimp_item_get_width (GIMP_ITEM (private->layer));
height = gimp_item_get_height (GIMP_ITEM (private->layer));
if (width == 0 || height == 0)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (private->layer));
width = gimp_image_get_width (image);
height = gimp_image_get_height (image);
}
}
gimp_link_set_file (private->link, file, width, height, TRUE, NULL, NULL);
if (gimp_link_is_broken (private->link))
{
gimp_link_set_file (private->link, NULL, width, height, TRUE, NULL, NULL);
g_signal_handlers_block_by_func (widget,
G_CALLBACK (layer_options_file_set),
private);
gtk_file_chooser_unselect_file (GTK_FILE_CHOOSER (widget), file);
g_signal_handlers_unblock_by_func (widget,
G_CALLBACK (layer_options_file_set),
private);
}
}
g_clear_object (&file);
}

View File

@@ -29,6 +29,7 @@ typedef void (* GimpLayerOptionsCallback) (GtkWidget *dialog,
GimpLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
GimpFillType layer_fill_type,
GimpLink *link,
gint layer_width,
gint layer_height,
gint layer_offset_x,

View File

@@ -125,7 +125,7 @@ static void palette_import_image_remove (GimpContainer *container,
GimpImage *image,
ImportDialog *private);
static void palette_import_make_palette (ImportDialog *private);
static void palette_import_file_set_filters (GtkFileChooser *file_chooser);
/* public functions */
@@ -282,13 +282,15 @@ palette_import_dialog_new (GimpContext *context)
/* Palette file name entry */
private->file_chooser = gtk_file_chooser_button_new (_("Select Palette File"),
GTK_FILE_CHOOSER_ACTION_OPEN);
GTK_FILE_CHOOSER_ACTION_OPEN);
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 4,
NULL, 0.0, 0.5, private->file_chooser, 1);
gtk_size_group_add_widget (size_group, private->file_chooser);
g_object_unref (size_group);
/* Set valid palette files filters */
palette_import_file_set_filters (GTK_FILE_CHOOSER (private->file_chooser));
g_object_unref (size_group);
/* The "Import" frame */
@@ -893,3 +895,62 @@ palette_import_make_palette (ImportDialog *private)
! (palette &&
gimp_palette_get_n_colors (palette) > 0));
}
static void
palette_import_file_set_filters (GtkFileChooser *file_chooser)
{
GtkFileFilter *filter;
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All palette files (*.*)"));
gtk_file_filter_add_pattern (filter, "*");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("GIMP Palette (*.gpl)"));
gtk_file_filter_add_pattern (filter, "*.gpl");
gtk_file_filter_add_pattern (filter, "*.GPL");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Adobe Color Table (*.act)"));
gtk_file_filter_add_pattern (filter, "*.act");
gtk_file_filter_add_pattern (filter, "*.ACT");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Adobe Color Swatch (*.aco)"));
gtk_file_filter_add_pattern (filter, "*.aco");
gtk_file_filter_add_pattern (filter, "*.ACO");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Adobe Color Book (*.acb)"));
gtk_file_filter_add_pattern (filter, "*.acb");
gtk_file_filter_add_pattern (filter, "*.ACB");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Adobe Swatch Exchange (*.ase)"));
gtk_file_filter_add_pattern (filter, "*.ase");
gtk_file_filter_add_pattern (filter, "*.ASE");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Cascading Style Sheet (*.css)"));
gtk_file_filter_add_pattern (filter, "*.css");
gtk_file_filter_add_pattern (filter, "*.CSS");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("JASC or RIFF Palette (*.pal)"));
gtk_file_filter_add_pattern (filter, "*.pal");
gtk_file_filter_add_pattern (filter, "*.PAL");
gtk_file_chooser_add_filter (file_chooser, filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("SwatchBooker (*.sbz)"));
gtk_file_filter_add_pattern (filter, "*.sbz");
gtk_file_filter_add_pattern (filter, "*.SBZ");
gtk_file_chooser_add_filter (file_chooser, filter);
}

View File

@@ -2476,6 +2476,9 @@ prefs_dialog_new (Gimp *gimp,
prefs_check_button_add (object, "layer-add-mask-invert",
_("Invert mask"),
GTK_BOX (vbox2));
prefs_check_button_add (object, "layer-add-mask-edit-mask",
_("Edit mask immediately"),
GTK_BOX (vbox2));
/* Merge Layers Dialog */
vbox2 = prefs_frame_new (_("Merge Layers Dialog"),

View File

@@ -539,16 +539,16 @@ welcome_dialog_create_welcome_page (Gimp *gimp,
/* "globe with meridians" emoticone in UTF-8. */
"\xf0\x9f\x8c\x90",
_("GIMP website"), "https://www.gimp.org/");
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "graduation cap" emoticone in UTF-8. */
"\xf0\x9f\x8e\x93",
_("Tutorials"),
"https://www.gimp.org/tutorials/");
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "open book" emoticone in UTF-8. */
"\xf0\x9f\x93\x96",
_("Documentation"),
"https://docs.gimp.org/");
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "graduation cap" emoticone in UTF-8. */
"\xf0\x9f\x8e\x93",
_("Community Tutorials"),
"https://www.gimp.org/tutorials/");
/* XXX: should we add API docs for plug-in developers once it's
* properly set up? */
@@ -1125,10 +1125,19 @@ welcome_dialog_create_release_page (Gimp *gimp,
tmp = g_strdup_printf (GIMP_VERSION);
if (GIMP_MINOR_VERSION % 2 == 0 && ! strstr (tmp, "RC"))
release_link = g_strdup_printf ("https://www.gimp.org/release-notes/gimp-%d.%d.html",
GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);
{
if (GIMP_MICRO_VERSION == 0 && ! strstr (tmp, "RC"))
release_link = g_strdup_printf ("https://www.gimp.org/release-notes/gimp-%d.%d.html",
GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);
else
release_link = g_strdup_printf ("https://www.gimp.org/release/%d.%d.%d/",
GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION,
GIMP_MICRO_VERSION);
}
else
release_link = g_strdup ("https://www.gimp.org/");
{
release_link = g_strdup ("https://www.gimp.org/");
}
g_free (tmp);
widget = gtk_link_button_new_with_label (release_link, _("Learn more"));
@@ -1382,7 +1391,7 @@ welcome_dialog_release_item_activated (GtkListBox *listbox,
{
GList *windows = gimp_get_image_windows (gimp);
/* Losing forcus on the welcome dialog on purpose for the main GUI
/* Losing focus on the welcome dialog on purpose for the main GUI
* to be more readable.
*/
if (windows)

View File

@@ -378,7 +378,7 @@ gimp_canvas_layer_boundary_set_layers (GimpCanvasLayerBoundary *boundary,
}
if (x1 != (gint) x ||
x1 != (gint) y ||
y1 != (gint) y ||
(x2 - x1) != (gint) w ||
(y2 - y1) != (gint) h ||
edit_mask != private->edit_mask)

View File

@@ -571,7 +571,7 @@ gimp_display_shell_drop_uri_list (GtkWidget *widget,
new_layers = file_open_layers (shell->display->gimp, context,
GIMP_PROGRESS (shell->display),
image, FALSE,
image, FALSE, FALSE,
file, GIMP_RUN_INTERACTIVE, NULL,
&status, &error);

View File

@@ -246,7 +246,7 @@ gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell,
* @w:
* @h:
*
* Gets the screen-space boudning box of the image, after it has
* Gets the screen-space bounding box of the image, after it has
* been transformed (i.e., scaled, rotated, and scrolled).
**/
void
@@ -290,7 +290,7 @@ gimp_display_shell_scale_get_image_bounds (GimpDisplayShell *shell,
* @w:
* @h:
*
* Gets the screen-space boudning box of the image, after it has
* Gets the screen-space bounding box of the image, after it has
* been scaled and scrolled, but before it has been rotated.
**/
void
@@ -320,7 +320,7 @@ gimp_display_shell_scale_get_image_unrotated_bounds (GimpDisplayShell *shell,
* @w:
* @h:
*
* Gets the screen-space boudning box of the image content, after it has
* Gets the screen-space bounding box of the image content, after it has
* been transformed (i.e., scaled, rotated, and scrolled).
**/
void
@@ -375,7 +375,7 @@ gimp_display_shell_scale_get_image_bounding_box (GimpDisplayShell *shell,
* @w:
* @h:
*
* Gets the screen-space boudning box of the image content, after it has
* Gets the screen-space bounding box of the image content, after it has
* been scaled and scrolled, but before it has been rotated.
**/
void
@@ -1289,9 +1289,9 @@ gimp_display_shell_scale_image_starts_to_fit (GimpDisplayShell *shell,
&new_scale_width,
&new_scale_height);
*vertically = (current_scale_width > shell->disp_width &&
*horizontally = (current_scale_width > shell->disp_width &&
new_scale_width <= shell->disp_width);
*horizontally = (current_scale_height > shell->disp_height &&
*vertically = (current_scale_height > shell->disp_height &&
new_scale_height <= shell->disp_height);
}

View File

@@ -1052,7 +1052,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
if (gimp_display_shell_key_to_state (kevent->keyval) == GDK_MOD1_MASK)
/* Make sure the picked layer is reset. */
shell->picked_layer = NULL;
g_clear_weak_pointer (&shell->picked_layer);
switch (kevent->keyval)
{
@@ -1151,7 +1151,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
statusbar = gimp_display_shell_get_statusbar (shell);
gimp_statusbar_pop_temp (statusbar);
shell->picked_layer = NULL;
g_clear_weak_pointer (&shell->picked_layer);
shell->mod_action = GIMP_MODIFIER_ACTION_NONE;
}
else if (shell->mod_action != GIMP_MODIFIER_ACTION_NONE &&
@@ -1767,7 +1767,7 @@ gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
_("Layer picked: '%s'"),
gimp_object_get_name (layer));
}
shell->picked_layer = layer;
g_set_weak_pointer (&shell->picked_layer, layer);
}
}
break;

View File

@@ -920,6 +920,7 @@ gimp_display_shell_finalize (GObject *object)
g_clear_object (&shell->no_image_options);
g_clear_pointer (&shell->title, g_free);
g_clear_pointer (&shell->status, g_free);
g_clear_weak_pointer (&shell->picked_layer);
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View File

@@ -464,12 +464,10 @@ gimp_image_window_constructed (GObject *object)
}
}
#ifndef GDK_WINDOWING_QUARTZ
/* Docs says that macOS always returns FALSE but we actually want to create
* our custom macOS menu.
*/
#ifdef GDK_WINDOWING_QUARTZ
menus_quartz_app_menu (private->gimp);
#else
use_app_menu = gtk_application_prefers_app_menu (GTK_APPLICATION (private->gimp->app));
#endif /* !GDK_WINDOWING_QUARTZ */
if (use_app_menu)
{
@@ -482,6 +480,7 @@ gimp_image_window_constructed (GObject *object)
gtk_application_set_app_menu (GTK_APPLICATION (private->gimp->app),
G_MENU_MODEL (app_menu_model));
}
#endif
/* Create the hbox that contains docks and images */
private->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
@@ -706,7 +705,7 @@ gimp_image_window_configure_event (GtkWidget *widget,
if (GTK_WIDGET_CLASS (parent_class)->configure_event)
GTK_WIDGET_CLASS (parent_class)->configure_event (widget, event);
/* If the window size has changed, make sure additoinal logic is run
/* If the window size has changed, make sure additional logic is run
* in the display shell's size-allocate
*/
if (event->width != current_width ||
@@ -2125,7 +2124,7 @@ gimp_image_window_switch_page (GtkNotebook *notebook,
NULL /*new_entry_id*/,
gimp_widget_get_monitor (GTK_WIDGET (window)));
}
else
else if (private->initial_monitor != NULL)
{
/* we are in construction, use the initial monitor; calling
* gimp_widget_get_monitor() would get us the monitor where the

View File

@@ -558,7 +558,7 @@ gimp_tool_polygon_fit_segment (GimpToolPolygon *polygon,
dest_end = &dest_points[n_points - 1];
/* Transate to origin */
/* Translate to origin */
gimp_vector2_sub (&origo_translation_offset,
&vector2_zero,
&dest_points[0]);

View File

@@ -122,6 +122,6 @@ libappdisplay = static_library('appdisplay',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Display"',
dependencies: [
gegl, gtk3, cairo,
gegl, gtk3, cairo, gexiv2
],
)

View File

@@ -215,15 +215,19 @@ file_gih_pipe_to_image (Gimp *gimp,
* described in the header" means) -- mitch
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_init (&params);
gimp_pixpipe_params_parse (pipe->params, &params);
G_GNUC_END_IGNORE_DEPRECATIONS
params.cellwidth = gimp_image_get_width (image);
params.cellheight = gimp_image_get_height (image);
params.cols = 1;
params.rows = 1;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
paramstring = gimp_pixpipe_params_build (&params);
G_GNUC_END_IGNORE_DEPRECATIONS
if (paramstring)
{
parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
@@ -235,7 +239,9 @@ file_gih_pipe_to_image (Gimp *gimp,
g_free (paramstring);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_free (&params);
G_GNUC_END_IGNORE_DEPRECATIONS
}
return image;
@@ -262,8 +268,10 @@ file_gih_image_to_pipe (GimpImage *image,
"spacing", spacing,
NULL);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_init (&params);
gimp_pixpipe_params_parse (paramstring, &params);
G_GNUC_END_IGNORE_DEPRECATIONS
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
@@ -353,7 +361,9 @@ file_gih_image_to_pipe (GimpImage *image,
g_list_free (brushes);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gimp_pixpipe_params_free (&params);
G_GNUC_END_IGNORE_DEPRECATIONS
gimp_brush_pipe_set_params (pipe, paramstring);

View File

@@ -16,6 +16,7 @@ libappfiledata = static_library('appfiledata',
cairo,
gdk_pixbuf,
gegl,
gexiv2,
libarchive,
],
)

View File

@@ -37,6 +37,8 @@
#include "core/gimpimage-undo.h"
#include "core/gimpimagefile.h"
#include "core/gimplayer.h"
#include "core/gimplink.h"
#include "core/gimplinklayer.h"
#include "core/gimpparamspecs.h"
#include "core/gimpprogress.h"
@@ -53,15 +55,32 @@
#include "gimp-intl.h"
static void file_open_sanitize_image (GimpImage *image,
gboolean as_new);
static void file_open_convert_items (GimpImage *dest_image,
const gchar *basename,
GList *items);
static GList * file_open_get_layers (GimpImage *image,
gboolean merge_visible,
gint *n_visible);
static gboolean file_open_file_proc_is_import (GimpPlugInProcedure *file_proc);
static GimpImage * file_open_link_image (Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GFile *file,
gint vector_width,
gint vector_height,
gboolean vector_keep_ratio,
gboolean as_new,
GimpPlugInProcedure *file_proc,
GimpRunMode run_mode,
gboolean *file_proc_handles_vector,
GimpPDBStatusType *status,
const gchar **mime_type,
GError **error);
static void file_open_sanitize_image (GimpImage *image,
gboolean as_new);
static void file_open_convert_items (GimpImage *dest_image,
const gchar *basename,
GList *items);
static GList * file_open_get_layers (GimpImage *image,
gboolean merge_visible,
gint *n_visible);
static gboolean file_open_file_proc_is_import (GimpPlugInProcedure *file_proc);
static gboolean file_open_valid_permissions (GFile *file,
GError **error);
/* public functions */
@@ -73,9 +92,11 @@ file_open_image (Gimp *gimp,
GFile *file,
gint vector_width,
gint vector_height,
gboolean vector_keep_ratio,
gboolean as_new,
GimpPlugInProcedure *file_proc,
GimpRunMode run_mode,
gboolean *file_proc_handles_vector,
GimpPDBStatusType *status,
const gchar **mime_type,
GError **error)
@@ -118,46 +139,8 @@ file_open_image (Gimp *gimp,
}
}
/* FIXME enable these tests for remote files again, needs testing */
if (g_file_is_native (file))
{
GFileInfo *info;
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
G_FILE_QUERY_INFO_NONE,
NULL, error);
if (info != NULL)
{
if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) != G_FILE_TYPE_REGULAR)
{
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Not a regular file"));
g_object_unref (info);
return NULL;
}
if (! g_file_info_get_attribute_boolean (info,
G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
{
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Permission denied"));
g_object_unref (info);
return NULL;
}
g_object_unref (info);
}
else
{
/* File likely does not exists. error will already have a more
* accurate reason.
*/
return NULL;
}
}
if (g_file_is_native (file) && ! file_open_valid_permissions (file, error))
return NULL;
if (! file_proc)
file_proc = gimp_plug_in_manager_file_procedure_find (gimp->plug_in_manager,
@@ -210,6 +193,9 @@ file_open_image (Gimp *gimp,
return NULL;
}
if (file_proc_handles_vector)
*file_proc_handles_vector = file_proc->handles_vector;
if (progress)
g_object_add_weak_pointer (G_OBJECT (progress), (gpointer) &progress);
@@ -223,7 +209,7 @@ file_open_image (Gimp *gimp,
G_TYPE_FILE, file,
G_TYPE_INT, vector_width,
G_TYPE_INT, vector_height,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, vector_keep_ratio,
G_TYPE_BOOLEAN, vector_width && vector_height ? FALSE : TRUE,
G_TYPE_NONE);
}
@@ -262,7 +248,15 @@ file_open_image (Gimp *gimp,
{
if (image)
{
/* Only set the load procedure if it hasn't already been set. */
/* Only set the load procedure if it hasn't already been set.
* The reason is that we want to know the information of the
* inner format, in case loading the file went through
* intermediate container file formats procedures, typically
* the procedures registered by the file-compressor plug-in.
*
* E.g. it could be used for our compressed XCF, but also for
* commonly compressed formats such as .hgt.zip.
*/
if (! gimp_image_get_load_proc (image))
gimp_image_set_load_proc (image, file_proc);
@@ -499,9 +493,8 @@ file_open_with_display (Gimp *gimp,
GError **error)
{
return file_open_with_proc_and_display (gimp, context, progress,
file, as_new, NULL,
monitor,
status, error);
file, as_new, FALSE, NULL,
monitor, status, error);
}
GimpImage *
@@ -510,12 +503,13 @@ file_open_with_proc_and_display (Gimp *gimp,
GimpProgress *progress,
GFile *file,
gboolean as_new,
gboolean as_link,
GimpPlugInProcedure *file_proc,
GObject *monitor,
GimpPDBStatusType *status,
GError **error)
{
GimpImage *image;
GimpImage *image = NULL;
const gchar *mime_type = NULL;
GimpRunMode run_mode = GIMP_RUN_INTERACTIVE;
@@ -529,14 +523,26 @@ file_open_with_proc_and_display (Gimp *gimp,
if (gimp->no_interface)
run_mode = GIMP_RUN_NONINTERACTIVE;
image = file_open_image (gimp, context, progress,
file, 0, 0,
as_new,
file_proc,
run_mode,
status,
&mime_type,
error);
if (as_link)
image = file_open_link_image (gimp, context, progress,
file, 0, 0, TRUE,
as_new,
file_proc,
run_mode,
NULL,
status,
&mime_type,
error);
else
image = file_open_image (gimp, context, progress,
file, 0, 0, TRUE,
as_new,
file_proc,
run_mode,
NULL,
status,
&mime_type,
error);
if (image)
{
@@ -555,15 +561,20 @@ file_open_with_proc_and_display (Gimp *gimp,
gimp_image_get_n_layers (image) == 1)
{
GimpObject *layer = gimp_image_get_layer_iter (image)->data;
gchar *basename;
basename = g_path_get_basename (gimp_file_get_utf8_name (file));
if (! GIMP_IS_LINK_LAYER (layer))
{
gchar *basename;
basename = g_path_get_basename (gimp_file_get_utf8_name (file));
gimp_item_rename (GIMP_ITEM (layer), basename, NULL);
g_free (basename);
}
gimp_item_rename (GIMP_ITEM (layer), basename, NULL);
gimp_image_undo_free (image);
gimp_image_clean_all (image);
g_free (basename);
}
if (gimp_create_display (image->gimp, image, gimp_unit_pixel (), 1.0,
@@ -611,6 +622,7 @@ file_open_layers (Gimp *gimp,
GimpProgress *progress,
GimpImage *dest_image,
gboolean merge_visible,
gboolean as_link,
GFile *file,
GimpRunMode run_mode,
GimpPlugInProcedure *file_proc,
@@ -629,14 +641,26 @@ file_open_layers (Gimp *gimp,
g_return_val_if_fail (status != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
new_image = file_open_image (gimp, context, progress,
file,
gimp_image_get_width (dest_image),
gimp_image_get_height (dest_image),
FALSE,
file_proc,
run_mode,
status, &mime_type, error);
if (as_link)
new_image = file_open_link_image (gimp, context, progress,
file,
gimp_image_get_width (dest_image),
gimp_image_get_height (dest_image),
TRUE,
FALSE,
file_proc,
run_mode,
NULL, status, &mime_type, error);
else
new_image = file_open_image (gimp, context, progress,
file,
gimp_image_get_width (dest_image),
gimp_image_get_height (dest_image),
TRUE,
FALSE,
file_proc,
run_mode,
NULL, status, &mime_type, error);
if (new_image)
{
@@ -743,6 +767,91 @@ file_open_from_command_line (Gimp *gimp,
/* private functions */
static GimpImage *
file_open_link_image (Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GFile *file,
gint vector_width,
gint vector_height,
gboolean vector_keep_ratio,
gboolean as_new,
GimpPlugInProcedure *file_proc,
GimpRunMode run_mode,
gboolean *file_proc_handles_vector,
GimpPDBStatusType *status,
const gchar **mime_type,
GError **error)
{
GimpImage *image = NULL;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (status != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (! file_proc)
file_proc = gimp_plug_in_manager_file_procedure_find (gimp->plug_in_manager,
GIMP_FILE_PROCEDURE_GROUP_OPEN,
file, error);
if (g_file_is_native (file) && ! file_open_valid_permissions (file, error))
return NULL;
if (g_file_is_native (file) && file_proc != NULL)
{
GimpLink *link = gimp_link_new (gimp, file,
vector_width, vector_height, vector_keep_ratio,
progress, error);
if (gimp_link_is_broken (link))
{
*status = GIMP_PDB_EXECUTION_ERROR;
}
else
{
GimpLayer *layer;
gint width;
gint height;
gimp_link_get_size (link, &width, &height);
image = gimp_image_new (gimp, width, height,
gimp_link_get_base_type (link),
gimp_link_get_precision (link));
layer = gimp_link_layer_new (image, link);
gimp_image_add_layer (image, layer, NULL, 0, FALSE);
if (! gimp_image_get_load_proc (image))
gimp_image_set_load_proc (image, gimp_link_get_load_proc (link));
file_proc = gimp_image_get_load_proc (image);
if (mime_type)
*mime_type = g_slist_nth_data (file_proc->mime_types_list, 0);
if (file_proc_handles_vector)
*file_proc_handles_vector = file_proc->handles_vector;
*status = GIMP_PDB_SUCCESS;
}
g_clear_object (&link);
}
else if (! g_file_is_native (file))
{
gchar *uri = g_file_get_uri (file);
if (error && ! *error)
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Only platform-native file paths are supported: '%s' cannot be opened as link."),
uri);
g_free (uri);
}
return image;
}
static void
file_open_sanitize_image (GimpImage *image,
gboolean as_new)
@@ -840,7 +949,65 @@ file_open_get_layers (GimpImage *image,
static gboolean
file_open_file_proc_is_import (GimpPlugInProcedure *file_proc)
{
return !(file_proc &&
file_proc->mime_types &&
strcmp (file_proc->mime_types, "image/x-xcf") == 0);
const gchar *proc_name;
g_return_val_if_fail (file_proc != NULL, TRUE);
proc_name = gimp_object_get_name (file_proc);
/* Even when loading through an intermediate container format plug-in
* (e.g. file-compressor), the stored procedure shall be the inner
* format.
*/
return (g_strcmp0 (proc_name, "gimp-xcf-load") != 0);
}
static gboolean
file_open_valid_permissions (GFile *file,
GError **error)
{
/* FIXME enable these tests for remote files again, needs testing */
if (g_file_is_native (file))
{
GFileInfo *info;
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
G_FILE_QUERY_INFO_NONE,
NULL, error);
if (info != NULL)
{
if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) != G_FILE_TYPE_REGULAR)
{
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Not a regular file"));
g_object_unref (info);
return FALSE;
}
if (! g_file_info_get_attribute_boolean (info,
G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
{
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Permission denied"));
g_object_unref (info);
return FALSE;
}
g_object_unref (info);
}
else
{
/* File likely does not exists. error will already have a more
* accurate reason.
*/
return FALSE;
}
return TRUE;
}
return FALSE;
}

View File

@@ -26,9 +26,11 @@ GimpImage * file_open_image (Gimp *gimp,
GFile *file,
gint vector_width,
gint vector_height,
gboolean vector_keep_ratio,
gboolean as_new,
GimpPlugInProcedure *file_proc,
GimpRunMode run_mode,
gboolean *file_proc_handles_vector,
GimpPDBStatusType *status,
const gchar **mime_type,
GError **error);
@@ -58,6 +60,7 @@ GimpImage * file_open_with_proc_and_display (Gimp *gimp,
GimpProgress *progress,
GFile *file,
gboolean as_new,
gboolean as_link,
GimpPlugInProcedure *file_proc,
GObject *monitor,
GimpPDBStatusType *status,
@@ -68,6 +71,7 @@ GList * file_open_layers (Gimp *gimp,
GimpProgress *progress,
GimpImage *dest_image,
gboolean merge_visible,
gboolean as_link,
GFile *file,
GimpRunMode run_mode,
GimpPlugInProcedure *file_proc,

View File

@@ -11,6 +11,6 @@ libappfile = static_library('appfile',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-File"',
dependencies: [
gegl, gdk_pixbuf,
gegl, gdk_pixbuf, gexiv2
],
)

View File

@@ -56,5 +56,6 @@ libappgegl = static_library('appgegl',
cairo,
gegl,
gdk_pixbuf,
gexiv2
],
)

View File

@@ -343,12 +343,9 @@ gimp_check_updates_process (const gchar *source,
parser = json_parser_new ();
if (! json_parser_load_from_data (parser, file_contents, file_length, &error))
{
gchar *uri = g_file_get_uri (G_FILE (source));
g_printerr ("%s: parsing of %s failed: %s\n", G_STRFUNC,
uri, error->message);
source, error->message);
g_free (uri);
g_free (file_contents);
g_clear_object (&parser);
g_clear_error (&error);
@@ -417,8 +414,30 @@ gimp_check_updates_callback (GObject *source,
{
gchar *uri = g_file_get_uri (G_FILE (source));
#ifndef GIMP_CONSOLE_COMPILATION
if (error->domain == G_IO_ERROR &&
error->code == G_IO_ERROR_NOT_SUPPORTED)
{
#ifndef G_OS_WIN32
g_message ("%s: loading of %s failed: %s\n\n%s",
G_STRFUNC, uri, error->message,
_("Perhaps you are missing GIO backends and need "
"to install GVFS?"));
#else
g_message ("%s: loading of %s failed: %s\n\n%s",
G_STRFUNC, uri, error->message,
_("Perhaps you are missing GIO backends."));
#endif /* G_OS_WIN32 */
}
else
{
g_printerr ("%s: loading of %s failed: %s\n", G_STRFUNC,
uri, error->message);
}
#else
g_printerr ("%s: loading of %s failed: %s\n", G_STRFUNC,
uri, error->message);
#endif /* GIMP_CONSOLE_COMPILATION */
g_free (uri);
g_clear_error (&error);

View File

@@ -41,6 +41,10 @@
#include "file/file-open.h"
#include "menus/menus.h"
#include "widgets/gimpuimanager.h"
#include "gimpdbusservice.h"
#include "gui-unique.h"
#include "themes.h"
@@ -56,14 +60,19 @@ static HWND proxy_window = NULL;
#elif defined (GDK_WINDOWING_QUARTZ)
static void gui_unique_quartz_init (Gimp *gimp);
static void gui_unique_quartz_exit (void);
static void gui_unique_quartz_init (Gimp *gimp);
static void gui_unique_quartz_exit (void);
static gboolean gui_unique_quartz_trigger_quit (gpointer data);
@interface GimpAppleEventHandler : NSObject {}
- (void) handleEvent:(NSAppleEventDescriptor *) inEvent
andReplyWith:(NSAppleEventDescriptor *) replyEvent;
@end
@interface GimpAppDelegate : NSObject <NSApplicationDelegate>
@end
static Gimp *unique_gimp = NULL;
static GimpAppleEventHandler *event_handler = NULL;
static void (^themeChangeHandler) (NSNotification *) = NULL;
@@ -339,6 +348,15 @@ gui_unique_quartz_idle_open (GFile *file)
}
@end
@implementation GimpAppDelegate
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *) sender
{
g_idle_add ((GSourceFunc) gui_unique_quartz_trigger_quit, unique_gimp);
return NSTerminateCancel;
}
@end
static void
gui_unique_quartz_init (Gimp *gimp)
{
@@ -375,6 +393,13 @@ gui_unique_quartz_init (Gimp *gimp)
andSelector: @selector (handleEvent: andReplyWith:)
forEventClass: kCoreEventClass
andEventID: kAEOpenDocuments];
/* When quitting the application using "Quit" from the dock's right-click menu,
* GIMP does not follow our standard quit procedure. Instead, macOS forces the
* application to close, which may result in losing unsaved changes.
* This delegate intercepts the applicationShouldTerminate call and uses our
* existing quit code, preventing macOS from handling the shutdown directly. */
[NSApp setDelegate:[[GimpAppDelegate alloc] init]];
}
static void
@@ -399,6 +424,17 @@ gui_unique_quartz_exit (void)
event_handler = NULL;
}
static gboolean
gui_unique_quartz_trigger_quit (gpointer data)
{
Gimp *gimp = (Gimp *)data;
GimpUIManager *ui_manager = menus_get_image_manager_singleton (gimp);
gimp_ui_manager_activate_action (ui_manager, "file", "file-quit");
return FALSE;
}
#else
static void

View File

@@ -220,7 +220,7 @@ icon_themes_current_prefer_symbolic (Gimp *gimp)
* override the "prefer-symbolic-icons" property, not only to avoid
* discrepancies, but even more to avoid weird cases where we end up using
* icons from the system icon theme while the chosen theme has the right icon
* (yet simply not in the prefered style). See Issue #9410.
* (yet simply not in the preferred style). See Issue #9410.
*/
if (gtk_icon_theme_has_icon (icon_theme, GIMP_ICON_WILBER) &&
! gtk_icon_theme_has_icon (icon_theme, GIMP_ICON_WILBER "-symbolic"))

View File

@@ -31,7 +31,7 @@ libappgui = static_library('appgui',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-GUI"',
dependencies: [
cairo, gegl, gdk_pixbuf, gio_specific, gtk3
cairo, gegl, gdk_pixbuf, gexiv2, gio_specific, gtk3
],
install: false,
)

View File

@@ -805,7 +805,7 @@ language_get_system_lang_id (void)
#elif defined PLATFORM_OSX
NSString *langs;
/* In macOS, the user sets a list of prefered languages and the
/* In macOS, the user sets a list of preferred languages and the
* software respects this preference order. I.e. that just storing the
* top-prefered lang would not be enough. What if GIMP didn't have
* translations for it, then it would fallback to the second lang. If

View File

@@ -1,4 +1,4 @@
/* GIMP - The GNU Image Manipulation Program
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
@@ -475,7 +475,7 @@ gimp_early_configuration (void)
if (user_gimprc)
user_gimprc_file = g_file_new_for_commandline_arg (user_gimprc);
/* GimpEarlyRc is reponsible for reading "gimprc" files for the
/* GimpEarlyRc is responsible for reading "gimprc" files for the
* sole purpose of getting some configuration data that is needed
* in the early initialization phase
*/
@@ -761,10 +761,10 @@ main (int argc,
/* The GIMP option group is just an empty option group, created for
* the sole purpose of running a post-parse hook before any other of
* dependant libraries are run. This makes it possible to apply
* dependent libraries are run. This makes it possible to apply
* options from configuration data obtained from "gimprc" files,
* before other libraries have a chance to run some of their
* intialization code.
* initialization code.
*/
gimp_group = g_option_group_new ("gimp", "", "", NULL, NULL);
g_option_group_set_parse_hooks (gimp_group, NULL,

View File

@@ -20,6 +20,10 @@
#include <gegl.h>
#include <gtk/gtk.h>
#ifdef PLATFORM_OSX
#include <AppKit/AppKit.h>
#endif
#include "libgimpbase/gimpbase.h"
#include "menus-types.h"
@@ -52,7 +56,11 @@
/* private variables */
static gboolean menurc_deleted = FALSE;
static gboolean menurc_deleted = FALSE;
#ifdef PLATFORM_OSX
static Gimp *unique_gimp = NULL;
#endif
/* public functions */
@@ -542,3 +550,115 @@ menus_get_image_manager_singleton (Gimp *gimp)
return image_ui_manager;
}
#ifdef PLATFORM_OSX
@interface GimpappMenuHandler : NSObject
@end
@implementation GimpappMenuHandler
+ (void) gimpShowAbout:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "dialogs", "dialogs-about");
}
+ (void) gimpShowWelcomeDialog:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "dialogs", "dialogs-welcome");
}
+ (void) gimpShowPreferences:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "dialogs", "dialogs-preferences");
}
+ (void) gimpShowInputDevices:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "dialogs", "dialogs-input-devices");
}
+ (void) gimpShowKeyboardShortcuts:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "dialogs", "dialogs-keyboard-shortcuts");
}
+ (void) gimpQuit:(id) sender
{
GimpUIManager *ui_manager = menus_get_image_manager_singleton (unique_gimp);
gimp_ui_manager_activate_action (ui_manager, "file", "file-quit");
}
@end
void
menus_quartz_app_menu (Gimp *gimp)
{
NSMenu *main_menu;
NSMenuItem *app_menu_item;
NSMenu *app_menu;
NSInteger last_index;
NSMenuItem *item;
g_return_if_fail (GIMP_IS_GIMP (gimp));
unique_gimp = gimp;
main_menu = [NSApp mainMenu];
app_menu_item = [main_menu itemAtIndex:0];
app_menu = [app_menu_item submenu];
/* On macOS, some standard menu items (e.g. "Hide", "Hide Others", "Show All", "Quit")
* are automatically provided by the system rather than created by our application.
* For the items we need to customize, we override their default behavior with our own
* implementations. In addition, we extend the menu with extra entries specific to
* our applications functionality. */
[app_menu setTitle:@"GIMP"];
/* About */
item = [app_menu itemAtIndex:0];
[item setTarget:[GimpappMenuHandler class]];
[item setAction:@selector (gimpShowAbout:)];
/* Welcome Dialog */
item = [[NSMenuItem alloc] initWithTitle:@"Welcome Dialog"
action:@selector (gimpShowWelcomeDialog:)
keyEquivalent:@""];
[item setTarget:[GimpappMenuHandler class]];
[app_menu insertItem:item atIndex:1];
/* Settings */
item = [app_menu itemAtIndex:3];
[item setTarget:[GimpappMenuHandler class]];
[item setAction:@selector (gimpShowPreferences:)];
/* Input Devices */
item = [[NSMenuItem alloc] initWithTitle:@"Input Devices"
action:@selector (gimpShowInputDevices:)
keyEquivalent:@""];
[item setTarget:[GimpappMenuHandler class]];
[app_menu insertItem:item atIndex:4];
/* Keyboard Shortcuts */
item = [[NSMenuItem alloc] initWithTitle:@"Keyboard Shortcuts"
action:@selector (gimpShowKeyboardShortcuts:)
keyEquivalent:@""];
[item setTarget:[GimpappMenuHandler class]];
[app_menu insertItem:item atIndex:5];
/* Quit */
last_index = [app_menu numberOfItems] - 1;
item = [app_menu itemAtIndex:last_index];
[item setTarget:[GimpappMenuHandler class]];
[item setAction:@selector (gimpQuit:)];
}
#endif

View File

@@ -31,3 +31,7 @@ void menus_remove (Gimp *gimp);
GimpMenuFactory * menus_get_global_menu_factory (Gimp *gimp);
GimpUIManager * menus_get_image_manager_singleton (Gimp *gimp);
#ifdef PLATFORM_OSX
void menus_quartz_app_menu (Gimp *gimp);
#endif

View File

@@ -16,6 +16,6 @@ libappmenus = static_library('appmenus',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Menus"',
dependencies: [
gegl, gtk3
gegl, gtk3, gexiv2
],
)

View File

@@ -25,6 +25,6 @@ libapplayermodeslegacy = static_library('applayermodeslegacy',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Layer-Modes-Legacy"',
dependencies: [
cairo, gegl, gdk_pixbuf,
cairo, gegl, gdk_pixbuf, gexiv2
],
)

View File

@@ -50,5 +50,6 @@ libapplayermodes = static_library('applayermodes',
cairo,
gegl,
gdk_pixbuf,
gexiv2
],
)

View File

@@ -66,7 +66,7 @@ libappoperations = static_library('appoperations',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Operations"',
dependencies: [
cairo, gegl, gdk_pixbuf,
cairo, gegl, gdk_pixbuf, gexiv2
],
)

View File

@@ -63,6 +63,6 @@ libapppaint = static_library('apppaint',
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Gimp-Paint"',
dependencies: [
cairo, gegl, gdk_pixbuf, libmypaint,
cairo, gegl, gdk_pixbuf, gexiv2, libmypaint,
],
)

Some files were not shown because too many files have changed in this diff Show More