by changing it to always deal with the center of the viewport instead of
its upper-left corner.
Fix gimp_display_shell_scroll_center_image_coordinate() to use the
proper transform functions like in the last commit.
gimp_display_shell_scale_to(): calculate the point that should not
move with GimpDisplayShell's untransform/transform functions before
and after scaling, then scroll to the right point. Just using the
scale functions doesn't work any longer when a rotation is
active. Other functions are affected too, but this most important
issue can be fixed by fixing just this function.
Since commit 867b1f7e the window did always pop if it was set to
visible once, even if closed and "Use info window" disabled.
Fix this by adapting the show logic to the fact that we now keep the
widget alive across images/displays.
...in initially active tab
gimp_tool_gui_update_shell(): implement the "overlay" case and hide the
gui on the previous shell, then show it on the new one.
to not return a reference that has to be dropped. Also allow NULL to
be returned if the managed cannot have a profile. If it can have one,
get_color_profile() still always returns a profile (either the
assigned one, or a generated built-in one).
gimp_image_constructed(): connect to "notify" on GimpColorConfig
and call gimp_color_managed_profile_changed() on the image.
Remove the "notify" handler on GimpColorConfig from
gimpdisplayshell-handlers.c because it already connects to the
image's "profile-changed" signal.
Additionally, implement GimpColorManaged::profile_changed() in
GimpImage and invalidate the image and all layer previews. One step
closer to color managing image and layer previews.
...when a color profile is active
This commit doesn't fix anything, but it prepares the code to do the
right thing:
It passes the actual raw image pixels through the entire color picking
mechanism to the widgets which display colors, particularly
GimpColorFrame.
This is needed for GimpColorFrame's "Pixel" mode (as opposed to its
RGB, HSV etc. modes) which is supposed to show the raw pixel values
from the image.
Before this commit, it was recreating the raw pixel values from the
GimpRGB value it knows, which will become impossible when we correctly
pick color managed GimpRGB values soon.
it used to be a typedef to gpointer and actually was a cmsHPROFILE.
Change its API to be more "standard", remove the public close()
function. The object caches both the cmsHPROFILE and the data/length
ICC blob, so conversions between the two become obsolete (simply call
get_lcms_profile() or get_icc_profile()).
Adapt everything to the new API, but port it in a naive way for now,
the code doesn't take advantage of the new possibilities yet (like
refcounting).
...but they aren't clipped
gimp_display_shell_profile_can_convert_to_u8(): allow the shortcut of
converting directly to 8-bit for display only for GIMP_COMPONENT_TYPE_U8.
This might be an lcms bug, the code can be enabled again for U16 and
U32 if it's indeed an lcms bug and it gets fixed.
but they aren't clipped
Add gimp_display_shell_profile_can_convert_to_u8() which returns
whether the lcms transform can safely write directly into an u8 buffer
without destroying out-of-gammut pixel values, which we assume is the
case for all integer formats. If the function returns FALSE, always
convert via the R'G'B'A float filter_buffer.
Also connect to the image's "precision-changed" signal and update the
profile transform when it's emitted.
- disable auto-adding of the lcms display filter module
- change profile convert dest formats to be always R'G'B'A, a display
profile transform outputs something that can be displayed directly,
so no additional gamma transform must happen when the pixels are
copied to a cairo-ARGB32 buffer
- add a medium forest of if() branches to gimpdisplayshell-filter.c
which cover all combinations of profile and display filter
transforms
- all of this is still very broken when changing an image to linear,
because the configured RGB profile from prefs will do horrible
nonsense (things work fine though with a per-image profile that is
for linear data)
Move some functions from libgimpwidgets/gimpwidgets.[ch]
and from app/widgets/gimpwidgets-utils.[ch]. Newly add
gimp_widget_get_color_profile() which is extracted from
modules/display-filter-lcms.c.
...bring focus back to GIMP image window
When showing docks in multi-window-mode, try to set the keyboard focus
back to the active display because it might have been stolen by a dock.
- change start() and set_text() to use "format" and "..." instead of
"message", allowing to format progress messages in place
- s/cancelable/cancellable/
- move "cancellable" to be the second argument of start()
Set the active display's viewport as priority rectangle on the image.
Update the rectangle in the default implementations of
GimpDisplayShell::scaled(), ::scrolled() and ::rotated(), which isn't
entirely correct yet but much better than before, and the only "bad"
thing that can happen with a bogus priority rectangle is that the
image is updated as out-of-viewport as before, just differently.
This may or may not remove some logic that avoids drawing tiny update
regions, and may or may not improve things or make them worse. Will
add code that actually tile-aligns update areas later.
...(crop, rectangle, etc) in large image zoomed-to-fit
Introduce a hash of the last 16 used icons in GimpStatusbar, it was
loading icons at a very high frequency. Found by Massimo.
Always round grid spacings and offsets to integer precision when
using them for snapping and grid drawing. While we might *want* to
have subpixel precision grids, all the UI is pretending it to be
on pixel boundaries. Make that pretense an fact.
In gimp_image_window_new(), place the window on the right
monitor manually if we are not in single-window-mode.
In gimp_image_window_switch_page(), make sure we don't use an
unrealized new window's monitor for updating the session info, because
the monitor of an unrealized window is always where the pointer is.
Change gimp_get_display_name() to also return the screen, and its
implementation in the GUI to return the initial monitor during
startup. Retrieve that information in app.c using a weird callback
construct and pass the monitor to file_open_from_command_line().
Half-related, add screen and monitor parameters to GimpDisplayShell
and use these initial values for calculating the canvas's initial
extents.
The image windows still don't position themselves correctly though
because we have no mechanism for that whatsoever just yet, but we now
at least pass the needed monitor information to the right objects.
Add a "monitor" parameter and return something reasonable, instead
of a useless resolution average of all the screen's monitors. Also
require a screen to be passed now.
There is now a preference option that determines whether windows
should be opened on the same monitor as before. It should be disabled
when the machine gets monitors plugged/unplugged dynamically ("laptop")
and enabled when there is a static multi-monitor setup ("wokstation").
This is merely the current simplistic policy on top of the newly added
underlying infrastructure:
- pass integer monitor numbers around in all places where we already
pass around a GdkScreen. Pass the "current" monitor to these changed
APIs, where "current" is either the monitor where the action-triggering
widget is, or if that is unavailable the monitor where the mouse is.
- add gimp_widget_get_monitor() in order to easily get to the monitor,
just like gtk_widget_get_screen().
- add screen and monitor parameters in some places that were missed
before.
- in sessionrc, save all window positions relative to the window's
monitor, and save the monitor separately, if it's not the screen's
primary monitor.
- when restoring window positions, use the stored monitor when the new
prefs options says so (use the screen's primary monitor if there is
no stored monitor), otherwise use current monitor that is now passed
around.
Enhance the existing but unused display scaling (hidpi/retina) support
to work independently in x and y direction, and adjust the scaling
factors accordingly when dot-for-dot is off and xres != yres.
Increase GIMP_DISPLAY_RENDER_MAX_SCALE from 2.0 to 4.0 and adjust the
rendering chunk size dynamically so we never render chunks that do
not fit into the GimpDisplayXfer buffers.
Disable extended input events when the cursor moves to a child of
the canvas widget. Otherwise GTK will try and fail to deliver an
extended event to the child widget, and end up sending it to the
canvas instead.
Calculate GimpCanvasPassepartout's extents using a cairo_region_xor()
of the crop rectangle and the image extents, instead of a
cairo_region_subtract(). This fixes the artifacts and has the nice
side effect that the passepartout now colors both the parts of the
image that will be removed *and* the parts of the image that will be
newly added.
- don't include <gdk-pixbuf/gdk-pixbuf.h> in headers in app/
- instead, include it in many .c files instead of <glib-object.h>,
finally acknowledging the fact that app/ depends on gdk-pixbuf almost
globally
- fix up includes as if libgimpbase depended in GIO, which it soon will
Along with this change, the snap preferences have been moved from
GimpDisplayConfig to GimpDisplayOptions, where it makes much more sense.
One of the consequences is that there is no need to duplicate these
values in GimpDisplayShell anymore to differenciate defaults and
current settings.
The main change is that even with only 1 image in single window mode,
there is now a tab.
Also whatever the number of images when you hide docks with Tab, no tabs
are shown.
Shells can now travel from one window to another. Canvas position code
should therefore not keep track of the image window for a specific shell
but must use whatever is the current window for this shell (even though
it may be a different one before and after the size-allocate).
This also partly fixes some positioning issue during mode switch.
This removes the obsolete check which makes the tool fail from
gimp_display_shell_set_mask(). Also change the foreground select tool
and the display mask from using GimpChannel to GeglBuffer, because
that's what it needs, simply buffers. Most changed files simply newly
include <gegl.h> because a GeglBuffer appeared in two headers.
Letting just tab presses bubble up when an overlay canvas child didn't
handle a key event isn't enough. Instead, let all key presses and
releases bubble up if the canvas itself doesn't have the focus.
Read: don't make assumptions.
Tab key events are not handled by the widget itself, they are supposed
to bubble up until they hit the generic keyboard navigation code
that knows about the focus chain, therefore:
gimp_display_shell_canvas_tool_events(): if an overlay widget is
focussed, don't handle Tab events and toggle dock visibility. Instead,
simply bail out with FALSE so the event reaches te keyboard navigation
code.
Also treat GDK_KEY_KP_Tab like GDK_KEY_Tab all over the place.
Also make some of GimpToolGui's memory management proper, there was
no leak but it needs to be proper in order to add runtime switching
between dialog and overlay.
Use "right-docks-width" and always a positive value instead of
"right-docks-position" (as opponsed to "left-docks-width", that
distinction is a GtkPaned implementation detail and does not belong
into a config file). Parse all old values too. Also fix a glitch in
the deserialization code which might fix bug #700147.
In multi-window mode, closing an image window is only meant to close
the current image (unless this is the last empty window).
In single window mode though, you are meaning to close the whole program.
Thanks to Niels Martignène for the original patch.
Don't try to switch to the move tool if the move tool is already active.
Also never bail out early from gimp_display_shell_space_pressed() so we
don't end up in an inconsistent state.
Added complete API for zoom/unzoom (scale and scroll) and
rotate/unrotate, with the same set of functions as the existing
transform/untransform. Moved some special case functions to the
namespaces they belong.
- stroke around the drawn area to work around the impossibility of
tiling antialiased stuff.
- don't use the display xfer stuff because if we overdraw we must
not have anything in the source pattern outside the drawn region
- reorder enum GimpCursorType to be in angular order
- add gimp_cursor_rotate(cursor_type, angle)
- rotate the shell's cursors automatically in the setter
First version of display rotation, inspired by gimp-painter.
The rotation always happens around the image's center.
The only "UI" for rotating is currently shift+middle-drag and
shift+space-drag. Control constrains the angle to 15 degrees
and is currently the only way to go back to "no rotation".
by not manually intersecting and subtracting regions at all. Simply
clip the cairo_t to the area we want to render, it will automatically
intersect with the clip region from the expose event, and check if the
clip is empty before actually drawing anything.
and get the shell from gimp_canvas_item_get_shell() if needed. Remove
some cairo_translate() that didn't have any effect and were leftovers
from a very early canvas item code.
the changes are simply copied from the gtk3-port branch, reducing the
number of diffs, and enabling hacking on drawing stuff in master while
keeping the branch easily rebasable.
and don't use them for (un)transforming integer coordinates. Everything
seems to work fine, but this sort of change has caused off-by-one errors
before, please review.
We cannot simply randomy move the focus from e.g. a text entry back to
the canvas. Instead introduce global handling of "Escape" and a
"primary_focus_widget" that is always set the the image window's
active canvas. When Escape is pressed, move the focus to that primary
focus widget, or beep if it is already there. Text widgets still get
the key events before that logic and can consume the Escape.
Simplify the loops without any significant loss in performance, separating
the positive and negative X directions to treat each correctly. Fixes this
bug.
Create all display filters with "color-config" and "color-managed"
parameters set, not only the automatically added color management
display filter. This way we don't only support removing and adding the
filter again, but also support potential other color management
modules.
Save the "right-docks-position" as negative value in pixels from the
right window border. Change the image window restoring code to
interpret negative values like that, but keep the meaning of positive
values for compatibility with existing sessionrc files.
Recent Cairo uses SHM transports when available, and exposes the ability
for its users to manage images shared between it and the display.
This allows us to eliminate copies, and if the architecture supports it
even to upload directly into GPU addressable memory without any copies
(all in normal system memory so we suffer no performance penalty when
applying the filters). The caveat is that we need to be aware of the
synchronize requirements, the cairo_surface_flush and
cairo_surface_mark_dirty, around access to the transport image. To
reduce the frequency of these barriers, we can subdivide the transport
image into small chunks as to satisfy individual updates and delay the
synchronisation barrier until we are forced to reuse earlier pixels.
Note this bumps the required Cairo version to 1.12, and please be aware
that the XSHM transport requires bug fixes from cairo.git (will be
1.12.12)
v2: After further reflections with Mitch, we realized we can share the
transport surface between all canvases by attaching it to the common
screen.
v3: Fix a couple of typos in insert_node() introduced when switching
variables names.
v4: Encapsulating within an image surface rather than a subsurface was
hiding the backing SHM segment from cairo, causing it to allocate
further SHM resources to stream the upload. We should be able to use a
sub-surface here, but it is more convenient to wrap the pixels in an
image surface for rendering the filters (and conveniently masking the
callee flushes from invalidating our parent transport surface).
Cc: Michael Natterer <mitch@gimp.org>
so it is just a bit more important than projection construction. Makes
initial image display show up in the right place much quicker, but
still after layouting the shell's widgets.
When reverting, we load a new image into the old image's existing
displays, and replace all references to the old image by the new image
in all GimpContext instances. We used to first update the displays and
then the contexts, which would shortly produce an inconsistent state
where the contexts were out of sync. When updating the displays with
the new image, we sometimes call menu update functions which would
then use that old image from the context when they should use the new
one, and thus triggered callbacks as if the user had activated a menu
(like image -> precision). To fix this, update the contexts before the
displays. It is also more logical to first update model objects and
then view objects.
Sync GimpDisplayShell's properties with the default values when it's
emptied and turns into the empty display, so the default values used
when filling it with an image are displayed while it's empty.
When updating the tool cursor on BUTTON_PRESS, pass a state *without*
the newly pressed button's mask to gimp_display_shell_update_cursor(),
or it will simply never call the cursor update function. Tool cursors
don't normally change when a mouse button is down.
Reset the tool on image changes again, but not if only the active
drawable changes, so keep bug #678890 closed:
Introduce new dirty flag GIMP_DIRTY_ACTIVE_DRAWABLE and set it on all
tools' dirty_mask except for rect select. Check the new flag when
reseting the active tool because of a drawable change.
Another attempt to fix paste/drop positions for good.
Paste/drop target is either the selected area of a drawable, the
drawable itself, or the image:
- if the paste is larger than the target, center on the target
- if there is a viewport, and the viewport intersects with the
target, center on the intersection
- otherwise, center on the target
Finally, if we did viewport-centered pasting, make sure the paste is
as completely within image bounds as possible.
Fix this and other issues more globally by moving the logic that
formats the image's display name into the GimpImage object, and return
the properly formatted name, e.g. "Foo.xcf", or "[Foo] (imported)"
from gimp_image_get_display_name().
Also add gimp_image_get_display_path() which returns the full path
instead. Use the two functions for formatting the image title, and
apply various other fixes that make sure the UI always uses the same
string to identify the image.
Call gimp_object_name_changed() whenever the save/export status
changes, so the image's cached display name and path get cleared.
I'm not sure if it'd be better to compress only sequence
of contiguous motion events, thinking to the case of anticipating
a motion event before a modifier key press/release.
And along with it a lot of stuff like the drawable preview cache, the
gegl tile manager backend, temporary gimp_gegl_buffer_foo() stuff, and
the remaining bits of performance.
The projection is in an evil semi-ported state which makes it work
ok-ish for stuff like layer moving, but absolutely unbearable for
painting, there is also an off-by-one rendering glitch at some zoom
levels.
commit 9ce8d4fae2. Fix the return_val
logic added in that commit, and make sure we always swallow arroy key
events, because we don't want focus keynav away from the canvas.
because it would require really evil hacks to honor these properties
in the gegl projection if they were on the mask, and because they
actually belong to the layer.
Regardless of the elaborate discussion in bug #599267, as soon as the
grid starts covering the image completely (when the is no more spacing
between grid lines), it is entirely useless, so skip drawing it.
Instead, either destroy the child instead of removing it, or remove
*and* destroy it in cases where the remove() api on the "parent"
doesn't match GTK+'s parent/child relation (like with all our dock
widgets). We can't rely on remove() to implicitly detstroy, because
there might be arbitrary other code holding references, such as
accessibility modules and whatnot. Most likely fixes unclear crashes
in accessibility code and other crashes we blamed GTK+ for.
these are the same nearly always, but during
an image-scale, the image size is updated early
and expose redraw following dialog destruction
uses the projection before the scale.
Basically this patch partly restores the code
before commit 8b8e67ffe2
Because it's generally the right thing to do, and server grabs broke
badly with input devices / client side windows.
gimpdisplayshell-grab.c: change logic to only server-grab if an event
is passed to the pointer grab/ungrab functions, but always use
gtk_grab_add/remove() which is sufficient in most cases.
gimpdisplayshell-tool-events.c: have the grab functions grab the
server only for space-bar scrolling and do all tool interaction,
including ruler clicks, with gtk_grab_add/remove(). Refactor things
a bit to also use the grab API for button-2 scrolling.
gimpdeviceinfo-coords.c: transform the event's coords to the canvas'
coordinate system, they might come from a ruler now.
This fixes the following bugs:
Bug 645315 - gimp_display_shell_pointer_grab: gdk_pointer_grab failed...
Bug 644351 - Gimp misses some strokes especially when drawing fast
Bug 645747 - Gimp is now unusable on xfce4
Add a canvas item group for previews, and a small preview infrastructure
to GimpDrawTool, and put the transform preview into the preview group,
which is below all guides, grid and layer boundaries.
instead of checking for event->button == 3, so context menus
work correctly on the Mac. Didn't change the image menu yet
because thet requires some more refactoring.
Refactor GimpImageWindow session management. As far as session
management goes, there are four states and four transitions that are
interesting.
The states are:
State Window mode Images opened
------------------------------------------
s1 swm 0
s2 swm >0
s3 mwm 0
s4 mwm >0
The transitions are:
Transition Description
-------------------------------------------
t1 Enter single-window mode (swm)
t2 Enter multi-window mwm (mwm)
t3 Open an image
t4 Close an image
When thinking of it like this, it is pretty easy to see when to call
gimp_image_window_session_clear() and when to call
gimp_image_window_session_apply(). So kill
gimp_image_window_set_entry_id() and handle all transitions in
gimp_image_window_session_update().
which removes a lot of code from the transform tool, and reduces the
number of canvas items used for the transform grid from possibly
gazillions to one.
Add GimpWindowingStrategy with create_dockable_dialog() and use it in
dialogs_create_dockable_cmd_callback(). There are two implementations:
GimpSingleWindowStrategy and GimpMultiWindowStrategy. Depending on the
window mode, we want new dockables to appear in different places when
created. In single-window mode, they should appear inside the single
image window. In multi-window mode, a new dock window is created.
In gimp_display_shell_drop_uri_list(), shell->display is dereferenced in
some places without checking that it's still there. It can be set to
NULL if the user quits the application while a drag and drop action is
being processed and the main loop is iterated during execution of this
function. (Bug #652280)
Since gimp_display_shell_appearance_update() depends on docks being
present, call it in gimp_image_window_add_dock(). Otherwise the resize
handle will be present when starting in single-window mode.
Call gimp_image_window_session_update() at the end of
gimp_image_window_constructed() so that if GIMP is closed right after
being started, the image window session info has the widget
initialized (and also so that the correct size is setup initially).
in both multi- and single-window mode. This is useful especially in
multi-window mode because in single-window we can already cycle
through all tabs with Ctrl+PageUp/Down.
Removes a lot of code from the rectangle tool and fixes off-by-one
drawing problems because in image coordinates, lines can't be aligned
correctly with rectangles.
instead of always passing FALSE when changing to a different
layer. For some reason we were displaying the right state anyway,
which can only mean that we do things redundantly here and call this
function twice.
- start_stroke()/finih_stroke() -> begin_stroke()/end_stroke()
- process_event_queue() -> process_stroke()
- GimpMotionBuffer::motion() -> GimpMotionBuffer::stroke()
- add GimpMotionBuffer::hover() and process_hover()
- remove push_event_history() and pop_event_queue() from API
The thing works like this:
- Motion events are continuously fed into the buffer using motion_event()
- begin_stroke()/end_stroke() correspond to BUTTON_PRESS/BUTTON_RELEASE,
the period between them is a "stroke"
- If motion_event() returns TRUE, we request "stroke" signals by calling
process_stroke() and "hover" signals by calling process_hover()
where finish_stroke() is the former flush_event_queue() and
start_stroke() is used in BUTTON_PRESS instead of poking into the
motion buffer's internals. Also, call finish_stroke() also when the
tool is not active, so the event buffer is flushed (the "motion"
callback will ignore the events if the tool is not active).
and emit the buffer's "motion" signal when a motion is supposed
to happen. In GimpDisplayShell, connect to GimpMotionBuffer::motion()
and call the tool.
That's most likely a very old artifact that was needed not even when
we used to do XOR, and these days it's even wrong because it makes
the tools think that something about the display has changed, like
zoom or scroll.
The flashing function checks for a non-empty queue by itself. Also
remove the timeout source explicitly in flush_event_queue() because it
might be called directly, and its FALSE return value has no effect on
the timeout source in that case.
This commit only adds the class and removes the members from
GimpDisplayShell, so everything looks more ugly than before, but
I wanted the member moving separate from any refactorings.
Use gdk_window_create_similar_surface instead of gdk_cairo_create in
selection_render_mask, as the latter is not entirely correct to use
outside the expose handler and may have some unwanted clipping state.
The width/height returned by gimp_canvas_rectangle_transform() were
off-by-one if the rectangle's width/height were exactly 0.0 and its
x/y exact integers, causing too much drawing and/or too little
invalidation.
instead of turning it off unconditionally in gimp_canvas_init(), so we
have full control over buffering when we are rendering images, but let
GTK+ handle a flicker-free wilber itself.
in order to be safe against whatever windowing system / event manager
depending event order. Also properly update the tool's state after a
button reelease, and after a space release.
and completely separate configure and sanity checks for gdk-pixbuf
from GTK+, because it's now distributed as a separate package. Remove
all sorts of conditional compiling based on GDK_CHECK_VERSION() and
CAIRO_VERSION.