2011-02-23 12:21:06 +08:00
|
|
|
/* 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
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <gegl.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
|
2011-09-19 06:45:36 +08:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "display-types.h"
|
|
|
|
#include "tools/tools-types.h"
|
|
|
|
|
|
|
|
#include "config/gimpdisplayconfig.h"
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
2017-01-23 07:00:03 +08:00
|
|
|
#include "core/gimp-filter-history.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "core/gimpimage.h"
|
2017-01-23 07:00:03 +08:00
|
|
|
#include "core/gimpitem.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
#include "widgets/gimpcontrollers.h"
|
|
|
|
#include "widgets/gimpcontrollerkeyboard.h"
|
2011-04-07 05:12:32 +08:00
|
|
|
#include "widgets/gimpcontrollermouse.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "widgets/gimpcontrollerwheel.h"
|
|
|
|
#include "widgets/gimpdeviceinfo.h"
|
|
|
|
#include "widgets/gimpdeviceinfo-coords.h"
|
2011-02-28 21:37:00 +08:00
|
|
|
#include "widgets/gimpdevicemanager.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "widgets/gimpdevices.h"
|
|
|
|
#include "widgets/gimpdialogfactory.h"
|
|
|
|
#include "widgets/gimpuimanager.h"
|
2011-02-24 23:54:39 +08:00
|
|
|
#include "widgets/gimpwidgets-utils.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2016-04-03 22:27:41 +08:00
|
|
|
#include "tools/gimpguidetool.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "tools/gimpmovetool.h"
|
2016-04-03 22:27:41 +08:00
|
|
|
#include "tools/gimpsamplepointtool.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "tools/gimptoolcontrol.h"
|
|
|
|
#include "tools/tool_manager.h"
|
|
|
|
|
2016-10-15 04:08:02 +08:00
|
|
|
#include "gimpcanvas.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "gimpdisplay.h"
|
|
|
|
#include "gimpdisplayshell.h"
|
|
|
|
#include "gimpdisplayshell-autoscroll.h"
|
|
|
|
#include "gimpdisplayshell-cursor.h"
|
|
|
|
#include "gimpdisplayshell-grab.h"
|
|
|
|
#include "gimpdisplayshell-layer-select.h"
|
2013-04-19 22:22:19 +08:00
|
|
|
#include "gimpdisplayshell-rotate.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
#include "gimpdisplayshell-scale.h"
|
|
|
|
#include "gimpdisplayshell-scroll.h"
|
|
|
|
#include "gimpdisplayshell-tool-events.h"
|
|
|
|
#include "gimpdisplayshell-transform.h"
|
|
|
|
#include "gimpimagewindow.h"
|
2011-04-18 00:53:42 +08:00
|
|
|
#include "gimpmotionbuffer.h"
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
#include "gimp-log.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
|
2018-01-04 19:02:53 +08:00
|
|
|
static gboolean gimp_display_shell_canvas_tool_events_internal (GtkWidget *canvas,
|
|
|
|
GdkEvent *event,
|
|
|
|
GimpDisplayShell *shell,
|
|
|
|
GdkEvent **next_event);
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
static GdkModifierType
|
2018-01-04 19:02:53 +08:00
|
|
|
gimp_display_shell_key_to_state (gint key);
|
2011-10-06 02:04:42 +08:00
|
|
|
static GdkModifierType
|
2018-01-04 19:02:53 +08:00
|
|
|
gimp_display_shell_button_to_state (gint button);
|
|
|
|
|
|
|
|
static void gimp_display_shell_proximity_in (GimpDisplayShell *shell);
|
|
|
|
static void gimp_display_shell_proximity_out (GimpDisplayShell *shell);
|
|
|
|
|
|
|
|
static void gimp_display_shell_check_device_cursor (GimpDisplayShell *shell);
|
|
|
|
|
|
|
|
static void gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event,
|
|
|
|
GdkModifierType state,
|
|
|
|
gint x,
|
|
|
|
gint y);
|
|
|
|
static void gimp_display_shell_stop_scrolling (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event);
|
|
|
|
static void gimp_display_shell_handle_scrolling (GimpDisplayShell *shell,
|
|
|
|
GdkModifierType state,
|
|
|
|
gint x,
|
|
|
|
gint y);
|
|
|
|
|
|
|
|
static void gimp_display_shell_space_pressed (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event);
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
static void gimp_display_shell_released (GimpDisplayShell *shell,
|
2018-01-04 19:02:53 +08:00
|
|
|
const GdkEvent *event,
|
|
|
|
const GimpCoords *image_coords);
|
|
|
|
|
|
|
|
static gboolean gimp_display_shell_tab_pressed (GimpDisplayShell *shell,
|
|
|
|
const GdkEventKey *event);
|
|
|
|
|
|
|
|
static void gimp_display_shell_update_focus (GimpDisplayShell *shell,
|
|
|
|
gboolean focus_in,
|
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state);
|
|
|
|
static void gimp_display_shell_update_cursor (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *display_coords,
|
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
gboolean update_software_cursor);
|
|
|
|
|
|
|
|
static gboolean gimp_display_shell_initialize_tool (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state);
|
|
|
|
|
|
|
|
static void gimp_display_shell_get_event_coords (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event,
|
|
|
|
GimpCoords *display_coords,
|
|
|
|
GdkModifierType *state,
|
|
|
|
guint32 *time);
|
|
|
|
static void gimp_display_shell_untransform_event_coords (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *display_coords,
|
|
|
|
GimpCoords *image_coords,
|
|
|
|
gboolean *update_software_cursor);
|
|
|
|
|
|
|
|
static GdkEvent * gimp_display_shell_compress_motion (GdkEvent *initial_event,
|
|
|
|
GdkEvent **next_event);
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_display_shell_events (GtkWidget *widget,
|
|
|
|
GdkEvent *event,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
Gimp *gimp;
|
|
|
|
gboolean set_display = FALSE;
|
|
|
|
|
|
|
|
/* are we in destruction? */
|
|
|
|
if (! shell->display || ! gimp_display_get_shell (shell->display))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
gimp = gimp_display_get_gimp (shell->display);
|
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case GDK_KEY_PRESS:
|
|
|
|
case GDK_KEY_RELEASE:
|
|
|
|
{
|
|
|
|
GdkEventKey *kevent = (GdkEventKey *) event;
|
|
|
|
|
|
|
|
if (gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
/* do not process most key events while BUTTON1 is down. We do this
|
2011-02-23 12:21:06 +08:00
|
|
|
* so tools keep the modifier state they were in when BUTTON1 was
|
|
|
|
* pressed and to prevent accelerators from being invoked.
|
|
|
|
*/
|
|
|
|
if (kevent->state & GDK_BUTTON1_MASK)
|
|
|
|
{
|
|
|
|
if (kevent->keyval == GDK_KEY_Shift_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Shift_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Alt_L ||
|
2011-10-06 01:44:24 +08:00
|
|
|
kevent->keyval == GDK_KEY_Alt_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Meta_L ||
|
2018-03-16 09:31:43 +08:00
|
|
|
kevent->keyval == GDK_KEY_Meta_R ||
|
|
|
|
kevent->keyval == GDK_KEY_space ||
|
|
|
|
kevent->keyval == GDK_KEY_KP_Space)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (kevent->keyval)
|
|
|
|
{
|
|
|
|
case GDK_KEY_Left: case GDK_KEY_Right:
|
|
|
|
case GDK_KEY_Up: case GDK_KEY_Down:
|
|
|
|
case GDK_KEY_space:
|
|
|
|
case GDK_KEY_KP_Space:
|
|
|
|
case GDK_KEY_Tab:
|
2013-06-08 21:27:14 +08:00
|
|
|
case GDK_KEY_KP_Tab:
|
2011-02-23 12:21:06 +08:00
|
|
|
case GDK_KEY_ISO_Left_Tab:
|
|
|
|
case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
|
|
|
|
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R:
|
|
|
|
case GDK_KEY_Control_L: case GDK_KEY_Control_R:
|
2011-10-06 01:44:24 +08:00
|
|
|
case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
|
2011-02-23 12:21:06 +08:00
|
|
|
case GDK_KEY_Return:
|
|
|
|
case GDK_KEY_KP_Enter:
|
|
|
|
case GDK_KEY_ISO_Enter:
|
|
|
|
case GDK_KEY_BackSpace:
|
|
|
|
case GDK_KEY_Escape:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if (shell->space_release_pending ||
|
|
|
|
shell->button1_release_pending ||
|
|
|
|
shell->scrolling)
|
2011-02-23 12:21:06 +08:00
|
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_display = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
|
|
case GDK_SCROLL:
|
|
|
|
set_display = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_FOCUS_CHANGE:
|
|
|
|
{
|
|
|
|
GdkEventFocus *fevent = (GdkEventFocus *) event;
|
|
|
|
|
|
|
|
if (fevent->in && shell->display->config->activate_on_focus)
|
|
|
|
set_display = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setting the context's display automatically sets the image, too */
|
|
|
|
if (set_display)
|
|
|
|
gimp_context_set_display (gimp_get_user_context (gimp), shell->display);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_display_shell_canvas_no_image_events (GtkWidget *canvas,
|
|
|
|
GdkEvent *event,
|
|
|
|
GimpDisplayShell *shell)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (event->type)
|
|
|
|
{
|
2012-12-01 21:26:36 +08:00
|
|
|
case GDK_2BUTTON_PRESS:
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
if (bevent->button == 1)
|
|
|
|
{
|
|
|
|
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
|
|
|
GimpUIManager *manager = gimp_image_window_get_ui_manager (window);
|
|
|
|
|
|
|
|
gimp_ui_manager_activate_action (manager, "file", "file-open");
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_BUTTON_PRESS:
|
2011-12-16 05:35:44 +08:00
|
|
|
if (gdk_event_triggers_context_menu (event))
|
|
|
|
{
|
|
|
|
gimp_ui_manager_ui_popup (shell->popup_manager,
|
|
|
|
"/dummy-menubar/image-popup",
|
|
|
|
GTK_WIDGET (shell),
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_PRESS:
|
|
|
|
{
|
|
|
|
GdkEventKey *kevent = (GdkEventKey *) event;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-06-08 21:27:14 +08:00
|
|
|
if (kevent->keyval == GDK_KEY_Tab ||
|
|
|
|
kevent->keyval == GDK_KEY_KP_Tab ||
|
2011-02-23 13:22:24 +08:00
|
|
|
kevent->keyval == GDK_KEY_ISO_Left_Tab)
|
|
|
|
{
|
2011-05-31 15:24:14 +08:00
|
|
|
return gimp_display_shell_tab_pressed (shell, kevent);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
return FALSE;
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
gboolean
|
|
|
|
gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
|
|
|
|
GdkEvent *event,
|
|
|
|
GimpDisplayShell *shell)
|
2018-01-04 19:02:53 +08:00
|
|
|
{
|
|
|
|
GdkEvent *next_event = NULL;
|
|
|
|
gboolean return_val;
|
|
|
|
|
|
|
|
g_return_val_if_fail (gtk_widget_get_realized (canvas), FALSE);
|
|
|
|
|
|
|
|
return_val = gimp_display_shell_canvas_tool_events_internal (canvas,
|
|
|
|
event, shell,
|
|
|
|
&next_event);
|
|
|
|
|
|
|
|
if (next_event)
|
|
|
|
{
|
|
|
|
gtk_main_do_event (next_event);
|
|
|
|
|
|
|
|
gdk_event_free (next_event);
|
|
|
|
}
|
|
|
|
|
|
|
|
return return_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_shell_canvas_grab_notify (GtkWidget *canvas,
|
|
|
|
gboolean was_grabbed,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
GimpDisplay *display;
|
|
|
|
GimpImage *image;
|
|
|
|
Gimp *gimp;
|
|
|
|
|
|
|
|
/* are we in destruction? */
|
|
|
|
if (! shell->display || ! gimp_display_get_shell (shell->display))
|
|
|
|
return;
|
|
|
|
|
|
|
|
display = shell->display;
|
|
|
|
gimp = gimp_display_get_gimp (display);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
|
|
|
|
if (! image)
|
|
|
|
return;
|
|
|
|
|
|
|
|
GIMP_LOG (TOOL_EVENTS, "grab_notify (display %p): was_grabbed = %s",
|
|
|
|
display, was_grabbed ? "TRUE" : "FALSE");
|
|
|
|
|
|
|
|
if (! was_grabbed)
|
|
|
|
{
|
|
|
|
if (! gimp_image_is_empty (image))
|
|
|
|
{
|
|
|
|
GimpTool *active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (active_tool && active_tool->focus_display == display)
|
|
|
|
{
|
|
|
|
tool_manager_modifier_state_active (gimp, 0, display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_shell_buffer_stroke (GimpMotionBuffer *buffer,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = shell->display;
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (display);
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control))
|
|
|
|
{
|
|
|
|
tool_manager_motion_active (gimp,
|
|
|
|
coords, time, state,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_shell_buffer_hover (GimpMotionBuffer *buffer,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
gboolean proximity,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = shell->display;
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (display);
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (active_tool &&
|
|
|
|
! gimp_tool_control_is_active (active_tool->control))
|
|
|
|
{
|
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
coords, state, proximity,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_display_shell_ruler_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event,
|
|
|
|
GimpDisplayShell *shell,
|
|
|
|
GimpOrientationType orientation)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = shell->display;
|
|
|
|
|
|
|
|
if (display->gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (! gimp_display_get_image (display))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (event->type == GDK_BUTTON_PRESS && event->button == 1)
|
|
|
|
{
|
|
|
|
GimpTool *active_tool = tool_manager_get_active (display->gimp);
|
|
|
|
|
|
|
|
if (active_tool)
|
|
|
|
{
|
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
NULL, event->state);
|
|
|
|
|
|
|
|
if (gimp_display_shell_pointer_grab (shell, NULL, 0))
|
|
|
|
{
|
|
|
|
if (gimp_display_shell_keyboard_grab (shell,
|
|
|
|
(GdkEvent *) event))
|
|
|
|
{
|
|
|
|
if (event->state & gimp_get_toggle_behavior_mask ())
|
|
|
|
{
|
|
|
|
gimp_sample_point_tool_start_new (active_tool, display);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_guide_tool_start_new (active_tool, display,
|
|
|
|
orientation);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_pointer_ungrab (shell, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_display_shell_hruler_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
return gimp_display_shell_ruler_button_press (widget, event, shell,
|
|
|
|
GIMP_ORIENTATION_HORIZONTAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_display_shell_vruler_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event,
|
|
|
|
GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
return gimp_display_shell_ruler_button_press (widget, event, shell,
|
|
|
|
GIMP_ORIENTATION_VERTICAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_display_shell_canvas_tool_events_internal (GtkWidget *canvas,
|
|
|
|
GdkEvent *event,
|
|
|
|
GimpDisplayShell *shell,
|
|
|
|
GdkEvent **next_event)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
GimpDisplay *display;
|
|
|
|
GimpImage *image;
|
|
|
|
Gimp *gimp;
|
|
|
|
GimpCoords display_coords;
|
|
|
|
GimpCoords image_coords;
|
|
|
|
GdkModifierType state;
|
|
|
|
guint32 time;
|
|
|
|
gboolean device_changed = FALSE;
|
|
|
|
gboolean return_val = FALSE;
|
|
|
|
gboolean update_sw_cursor = FALSE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-01-04 19:02:53 +08:00
|
|
|
*next_event = NULL;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
/* are we in destruction? */
|
|
|
|
if (! shell->display || ! gimp_display_get_shell (shell->display))
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
/* set the active display before doing any other canvas event processing */
|
|
|
|
if (gimp_display_shell_events (canvas, event, shell))
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2016-10-15 04:08:02 +08:00
|
|
|
/* events on overlays have a different window, but these windows'
|
|
|
|
* user_data can still be the canvas, we need to check manually if
|
|
|
|
* the event's window and the canvas' window are different.
|
2011-02-23 13:22:24 +08:00
|
|
|
*/
|
2016-10-15 04:08:02 +08:00
|
|
|
if (event->any.window != gtk_widget_get_window (canvas))
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
2016-10-15 04:08:02 +08:00
|
|
|
GtkWidget *event_widget;
|
|
|
|
|
|
|
|
gdk_window_get_user_data (event->any.window, (gpointer) &event_widget);
|
|
|
|
|
|
|
|
/* if the event came from a different window than the canvas',
|
|
|
|
* check if it came from a canvas child and bail out.
|
|
|
|
*/
|
|
|
|
if (gtk_widget_get_ancestor (event_widget, GIMP_TYPE_CANVAS))
|
|
|
|
return FALSE;
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
display = shell->display;
|
|
|
|
gimp = gimp_display_get_gimp (display);
|
|
|
|
image = gimp_display_get_image (display);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (! image)
|
|
|
|
return gimp_display_shell_canvas_no_image_events (canvas, event, shell);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-27 18:08:36 +08:00
|
|
|
GIMP_LOG (TOOL_EVENTS, "event (display %p): %s",
|
|
|
|
display, gimp_print_event (event));
|
|
|
|
|
2016-09-23 00:18:40 +08:00
|
|
|
/* See bug 771444 */
|
|
|
|
if (shell->pointer_grabbed &&
|
|
|
|
event->type == GDK_MOTION_NOTIFY)
|
|
|
|
{
|
|
|
|
GimpDeviceManager *manager = gimp_devices_get_manager (gimp);
|
|
|
|
GimpDeviceInfo *info;
|
|
|
|
|
|
|
|
info = gimp_device_manager_get_current_device (manager);
|
|
|
|
|
|
|
|
if (info->device != event->motion.device)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
/* Find out what device the event occurred upon */
|
2013-12-15 04:56:20 +08:00
|
|
|
if (! gimp->busy &&
|
|
|
|
! shell->inferior_ignore_mode &&
|
|
|
|
gimp_devices_check_change (gimp, event))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
gimp_display_shell_check_device_cursor (shell);
|
|
|
|
device_changed = TRUE;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
gimp_display_shell_get_event_coords (shell, event,
|
|
|
|
&display_coords,
|
|
|
|
&state, &time);
|
|
|
|
gimp_display_shell_untransform_event_coords (shell,
|
|
|
|
&display_coords, &image_coords,
|
|
|
|
&update_sw_cursor);
|
|
|
|
|
|
|
|
/* If the device (and maybe the tool) has changed, update the new
|
|
|
|
* tool's state
|
|
|
|
*/
|
|
|
|
if (device_changed && gtk_widget_has_focus (canvas))
|
|
|
|
{
|
2011-04-04 01:01:13 +08:00
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
&image_coords, state);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case GDK_ENTER_NOTIFY:
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
GdkEventCrossing *cevent = (GdkEventCrossing *) event;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-01-04 19:07:44 +08:00
|
|
|
if (shell->inferior_ignore_mode &&
|
|
|
|
cevent->subwindow == NULL &&
|
|
|
|
cevent->mode == GDK_CROSSING_NORMAL)
|
2013-12-15 04:56:20 +08:00
|
|
|
{
|
|
|
|
shell->inferior_ignore_mode = FALSE;
|
|
|
|
gtk_widget_set_extension_events (shell->canvas,
|
|
|
|
GDK_EXTENSION_EVENTS_ALL);
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (cevent->mode != GDK_CROSSING_NORMAL)
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
/* ignore enter notify while we have a grab */
|
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
return TRUE;
|
|
|
|
|
2011-02-27 19:16:51 +08:00
|
|
|
gimp_display_shell_proximity_in (shell);
|
2011-02-23 13:22:24 +08:00
|
|
|
update_sw_cursor = TRUE;
|
|
|
|
|
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_LEAVE_NOTIFY:
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
GdkEventCrossing *cevent = (GdkEventCrossing *) event;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-01-04 19:07:44 +08:00
|
|
|
if (! shell->inferior_ignore_mode &&
|
|
|
|
cevent->subwindow == NULL &&
|
|
|
|
cevent->mode == GDK_CROSSING_NORMAL &&
|
|
|
|
cevent->detail == GDK_NOTIFY_INFERIOR)
|
2013-12-15 04:56:20 +08:00
|
|
|
{
|
|
|
|
shell->inferior_ignore_mode = TRUE;
|
|
|
|
gtk_widget_set_extension_events (shell->canvas,
|
|
|
|
GDK_EXTENSION_EVENTS_NONE);
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (cevent->mode != GDK_CROSSING_NORMAL)
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
/* ignore leave notify while we have a grab */
|
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
return TRUE;
|
|
|
|
|
2011-02-27 19:08:09 +08:00
|
|
|
gimp_display_shell_proximity_out (shell);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_PROXIMITY_IN:
|
2011-02-27 19:16:51 +08:00
|
|
|
gimp_display_shell_proximity_in (shell);
|
2011-02-27 19:08:09 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_PROXIMITY_OUT:
|
2011-02-27 19:08:09 +08:00
|
|
|
gimp_display_shell_proximity_out (shell);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
2011-02-23 12:21:06 +08:00
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_FOCUS_CHANGE:
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
GdkEventFocus *fevent = (GdkEventFocus *) event;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (fevent->in)
|
|
|
|
{
|
|
|
|
if (G_UNLIKELY (! gtk_widget_has_focus (canvas)))
|
|
|
|
g_warning ("%s: FOCUS_IN but canvas has no focus", G_STRFUNC);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
/* ignore focus changes while we have a grab */
|
2011-04-07 03:35:29 +08:00
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* press modifier keys when the canvas gets the focus */
|
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
&image_coords, state);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-27 18:08:36 +08:00
|
|
|
if (G_UNLIKELY (gtk_widget_has_focus (canvas)))
|
2011-02-23 12:21:06 +08:00
|
|
|
g_warning ("%s: FOCUS_OUT but canvas has focus", G_STRFUNC);
|
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
/* ignore focus changes while we have a grab */
|
2011-04-07 03:35:29 +08:00
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
return TRUE;
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
/* release modifier keys when the canvas loses the focus */
|
2011-04-04 01:01:13 +08:00
|
|
|
gimp_display_shell_update_focus (shell, FALSE,
|
|
|
|
&image_coords, 0);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
|
|
{
|
2012-11-07 05:46:47 +08:00
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
GdkModifierType button_state;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:53:11 +08:00
|
|
|
/* ignore new mouse events */
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if (gimp->busy || shell->scrolling ||
|
|
|
|
shell->pointer_grabbed ||
|
|
|
|
shell->button1_release_pending)
|
2011-12-10 03:53:11 +08:00
|
|
|
return TRUE;
|
|
|
|
|
2012-11-07 05:46:47 +08:00
|
|
|
button_state = gimp_display_shell_button_to_state (bevent->button);
|
|
|
|
|
|
|
|
state |= button_state;
|
2011-12-10 05:26:22 +08:00
|
|
|
|
2011-12-10 03:53:11 +08:00
|
|
|
/* ignore new buttons while another button is down */
|
2011-12-10 05:34:44 +08:00
|
|
|
if (((state & (GDK_BUTTON1_MASK)) && (state & (GDK_BUTTON2_MASK |
|
|
|
|
GDK_BUTTON3_MASK))) ||
|
|
|
|
((state & (GDK_BUTTON2_MASK)) && (state & (GDK_BUTTON1_MASK |
|
|
|
|
GDK_BUTTON3_MASK))) ||
|
|
|
|
((state & (GDK_BUTTON3_MASK)) && (state & (GDK_BUTTON1_MASK |
|
|
|
|
GDK_BUTTON2_MASK))))
|
2011-12-10 03:53:11 +08:00
|
|
|
return TRUE;
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
/* focus the widget if it isn't; if the toplevel window
|
|
|
|
* already has focus, this will generate a FOCUS_IN on the
|
|
|
|
* canvas immediately, therefore we do this before logging
|
|
|
|
* the BUTTON_PRESS.
|
|
|
|
*/
|
|
|
|
if (! gtk_widget_has_focus (canvas))
|
|
|
|
gtk_widget_grab_focus (canvas);
|
|
|
|
|
|
|
|
/* if the toplevel window didn't have focus, the above
|
|
|
|
* gtk_widget_grab_focus() didn't set the canvas' HAS_FOCUS
|
2011-04-04 00:42:50 +08:00
|
|
|
* flags, and didn't trigger a FOCUS_IN, but the tool needs
|
|
|
|
* to be set up correctly regardless, so simply do the
|
|
|
|
* same things here, it's safe to do them redundantly.
|
2011-02-23 12:21:06 +08:00
|
|
|
*/
|
2011-04-04 01:01:13 +08:00
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
&image_coords, state);
|
2011-04-04 00:42:50 +08:00
|
|
|
gimp_display_shell_update_cursor (shell, &display_coords,
|
2012-11-07 05:46:47 +08:00
|
|
|
&image_coords, state & ~button_state,
|
|
|
|
FALSE);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-10-06 02:04:42 +08:00
|
|
|
if (gdk_event_triggers_context_menu (event))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-10-06 02:04:42 +08:00
|
|
|
GimpUIManager *ui_manager;
|
|
|
|
const gchar *ui_path;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-10-06 02:04:42 +08:00
|
|
|
ui_manager = tool_manager_get_popup_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
display,
|
|
|
|
&ui_path);
|
|
|
|
|
|
|
|
if (ui_manager)
|
|
|
|
{
|
|
|
|
gimp_ui_manager_ui_popup (ui_manager,
|
|
|
|
ui_path,
|
|
|
|
GTK_WIDGET (shell),
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_ui_manager_ui_popup (shell->popup_manager,
|
|
|
|
"/dummy-menubar/image-popup",
|
|
|
|
GTK_WIDGET (shell),
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bevent->button == 1)
|
|
|
|
{
|
2011-12-10 03:20:02 +08:00
|
|
|
if (! gimp_display_shell_pointer_grab (shell, NULL, 0))
|
2011-02-23 12:21:06 +08:00
|
|
|
return TRUE;
|
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
if (! shell->space_release_pending)
|
2011-02-23 12:21:06 +08:00
|
|
|
if (! gimp_display_shell_keyboard_grab (shell, event))
|
|
|
|
{
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_pointer_ungrab (shell, NULL);
|
2011-02-23 12:21:06 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-04-04 00:27:03 +08:00
|
|
|
if (gimp_display_shell_initialize_tool (shell,
|
|
|
|
&image_coords, state))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-18 06:29:32 +08:00
|
|
|
GimpCoords last_motion;
|
|
|
|
|
2015-12-29 05:04:13 +08:00
|
|
|
/* Use the last evaluated velocity&direction instead of the
|
2011-04-04 00:27:03 +08:00
|
|
|
* button_press event's ones because the click is
|
|
|
|
* usually at the same spot as the last motion event
|
2015-12-29 05:04:13 +08:00
|
|
|
* which would give us bogus derivate dynamics.
|
2011-02-23 12:21:06 +08:00
|
|
|
*/
|
2011-04-18 17:08:24 +08:00
|
|
|
gimp_motion_buffer_begin_stroke (shell->motion_buffer, time,
|
2011-04-18 06:29:32 +08:00
|
|
|
&last_motion);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2015-12-29 05:04:13 +08:00
|
|
|
image_coords.velocity = last_motion.velocity;
|
|
|
|
image_coords.direction = last_motion.direction;
|
|
|
|
|
2011-04-04 00:27:03 +08:00
|
|
|
tool_manager_button_press_active (gimp,
|
|
|
|
&image_coords,
|
|
|
|
time, state,
|
|
|
|
GIMP_BUTTON_PRESS_NORMAL,
|
|
|
|
display);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
2011-10-06 02:04:42 +08:00
|
|
|
}
|
|
|
|
else if (bevent->button == 2)
|
|
|
|
{
|
2013-04-19 22:22:19 +08:00
|
|
|
gimp_display_shell_start_scrolling (shell, NULL, state,
|
2011-12-10 03:20:02 +08:00
|
|
|
bevent->x, bevent->y);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return_val = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_2BUTTON_PRESS:
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
if (gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (bevent->button == 1 &&
|
|
|
|
active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control) &&
|
|
|
|
gimp_tool_control_get_wants_double_click (active_tool->control))
|
|
|
|
{
|
|
|
|
tool_manager_button_press_active (gimp,
|
|
|
|
&image_coords,
|
|
|
|
time, state,
|
|
|
|
GIMP_BUTTON_PRESS_DOUBLE,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
|
2011-03-31 16:21:55 +08:00
|
|
|
/* don't update the cursor again on double click */
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_3BUTTON_PRESS:
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
if (gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (bevent->button == 1 &&
|
|
|
|
active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control) &&
|
|
|
|
gimp_tool_control_get_wants_triple_click (active_tool->control))
|
|
|
|
{
|
|
|
|
tool_manager_button_press_active (gimp,
|
|
|
|
&image_coords,
|
|
|
|
time, state,
|
|
|
|
GIMP_BUTTON_PRESS_TRIPLE,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
|
2011-03-31 16:21:55 +08:00
|
|
|
/* don't update the cursor again on triple click */
|
|
|
|
return TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
gimp_display_shell_autoscroll_stop (shell);
|
|
|
|
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if (bevent->button == 1 && shell->button1_release_pending)
|
|
|
|
{
|
|
|
|
gimp_display_shell_released (shell, event, NULL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
if (gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
2016-04-15 07:17:00 +08:00
|
|
|
state &= ~gimp_display_shell_button_to_state (bevent->button);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-10-06 02:04:42 +08:00
|
|
|
if (bevent->button == 1)
|
|
|
|
{
|
2011-12-10 03:53:11 +08:00
|
|
|
if (! shell->pointer_grabbed || shell->scrolling)
|
2011-04-07 04:30:44 +08:00
|
|
|
return TRUE;
|
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
if (! shell->space_release_pending)
|
2011-02-23 12:21:06 +08:00
|
|
|
gimp_display_shell_keyboard_ungrab (shell, event);
|
|
|
|
|
|
|
|
if (active_tool &&
|
|
|
|
(! gimp_image_is_empty (image) ||
|
|
|
|
gimp_tool_control_get_handle_empty_image (active_tool->control)))
|
|
|
|
{
|
2011-04-18 17:08:24 +08:00
|
|
|
gimp_motion_buffer_end_stroke (shell->motion_buffer);
|
2011-04-18 06:29:32 +08:00
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
if (gimp_tool_control_is_active (active_tool->control))
|
|
|
|
{
|
|
|
|
tool_manager_button_release_active (gimp,
|
|
|
|
&image_coords,
|
|
|
|
time, state,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the tool's modifier state because it didn't get
|
|
|
|
* key events while BUTTON1 was down
|
|
|
|
*/
|
2011-04-07 03:35:29 +08:00
|
|
|
if (gtk_widget_has_focus (canvas))
|
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
&image_coords, state);
|
|
|
|
else
|
|
|
|
gimp_display_shell_update_focus (shell, FALSE,
|
|
|
|
&image_coords, 0);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_pointer_ungrab (shell, NULL);
|
2011-10-06 02:04:42 +08:00
|
|
|
}
|
|
|
|
else if (bevent->button == 2)
|
|
|
|
{
|
2011-04-07 04:30:44 +08:00
|
|
|
if (shell->scrolling)
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_stop_scrolling (shell, NULL);
|
2011-10-06 02:04:42 +08:00
|
|
|
}
|
|
|
|
else if (bevent->button == 3)
|
|
|
|
{
|
|
|
|
/* nop */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
2015-04-18 14:40:31 +08:00
|
|
|
GimpController *mouse = gimp_controllers_get_mouse (gimp);
|
2011-04-07 05:12:32 +08:00
|
|
|
|
2011-10-06 02:04:42 +08:00
|
|
|
if (!(shell->scrolling || shell->pointer_grabbed) &&
|
|
|
|
mouse && gimp_controller_mouse_button (GIMP_CONTROLLER_MOUSE (mouse),
|
|
|
|
bevent))
|
2015-04-18 14:40:31 +08:00
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return_val = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_SCROLL:
|
|
|
|
{
|
2015-04-18 14:40:31 +08:00
|
|
|
GdkEventScroll *sevent = (GdkEventScroll *) event;
|
|
|
|
GimpController *wheel = gimp_controllers_get_wheel (gimp);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-04-07 04:50:20 +08:00
|
|
|
if (! wheel ||
|
|
|
|
! gimp_controller_wheel_scroll (GIMP_CONTROLLER_WHEEL (wheel),
|
|
|
|
sevent))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-07 04:50:20 +08:00
|
|
|
GdkScrollDirection direction = sevent->direction;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-10-07 05:59:49 +08:00
|
|
|
if (state & gimp_get_toggle_behavior_mask ())
|
2011-04-07 04:50:20 +08:00
|
|
|
{
|
|
|
|
switch (direction)
|
|
|
|
{
|
|
|
|
case GDK_SCROLL_UP:
|
|
|
|
gimp_display_shell_scale (shell,
|
|
|
|
GIMP_ZOOM_IN,
|
|
|
|
0.0,
|
|
|
|
GIMP_ZOOM_FOCUS_BEST_GUESS);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
|
|
gimp_display_shell_scale (shell,
|
|
|
|
GIMP_ZOOM_OUT,
|
|
|
|
0.0,
|
|
|
|
GIMP_ZOOM_FOCUS_BEST_GUESS);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
2011-04-07 04:50:20 +08:00
|
|
|
else
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-07 04:50:20 +08:00
|
|
|
GtkAdjustment *adj = NULL;
|
|
|
|
gdouble value;
|
|
|
|
|
|
|
|
if (state & GDK_SHIFT_MASK)
|
|
|
|
switch (direction)
|
|
|
|
{
|
|
|
|
case GDK_SCROLL_UP: direction = GDK_SCROLL_LEFT; break;
|
|
|
|
case GDK_SCROLL_DOWN: direction = GDK_SCROLL_RIGHT; break;
|
|
|
|
case GDK_SCROLL_LEFT: direction = GDK_SCROLL_UP; break;
|
|
|
|
case GDK_SCROLL_RIGHT: direction = GDK_SCROLL_DOWN; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (direction)
|
|
|
|
{
|
|
|
|
case GDK_SCROLL_LEFT:
|
|
|
|
case GDK_SCROLL_RIGHT:
|
|
|
|
adj = shell->hsbdata;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_SCROLL_UP:
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
|
|
adj = shell->vsbdata;
|
|
|
|
break;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-04-07 04:50:20 +08:00
|
|
|
value = (gtk_adjustment_get_value (adj) +
|
|
|
|
((direction == GDK_SCROLL_UP ||
|
|
|
|
direction == GDK_SCROLL_LEFT) ?
|
|
|
|
-gtk_adjustment_get_page_increment (adj) / 2 :
|
|
|
|
gtk_adjustment_get_page_increment (adj) / 2));
|
|
|
|
value = CLAMP (value,
|
|
|
|
gtk_adjustment_get_lower (adj),
|
|
|
|
gtk_adjustment_get_upper (adj) -
|
|
|
|
gtk_adjustment_get_page_size (adj));
|
|
|
|
|
|
|
|
gtk_adjustment_set_value (adj, value);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_display_shell_untransform_event_coords (shell,
|
|
|
|
&display_coords,
|
|
|
|
&image_coords,
|
|
|
|
&update_sw_cursor);
|
|
|
|
|
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
|
|
|
|
|
|
|
return_val = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_MOTION_NOTIFY:
|
|
|
|
{
|
|
|
|
GdkEventMotion *mevent = (GdkEventMotion *) event;
|
|
|
|
GdkEvent *compressed_motion = NULL;
|
2011-04-18 01:59:31 +08:00
|
|
|
GimpMotionMode motion_mode = GIMP_MOTION_MODE_EXACT;
|
2011-02-23 12:21:06 +08:00
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
if (gimp->busy)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
2011-04-18 01:59:31 +08:00
|
|
|
if (active_tool)
|
|
|
|
motion_mode = gimp_tool_control_get_motion_mode (active_tool->control);
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
if (shell->scrolling ||
|
2011-04-18 01:59:31 +08:00
|
|
|
motion_mode == GIMP_MOTION_MODE_COMPRESS)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2018-01-04 19:02:53 +08:00
|
|
|
compressed_motion = gimp_display_shell_compress_motion (event,
|
|
|
|
next_event);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
if (compressed_motion && ! shell->scrolling)
|
|
|
|
{
|
|
|
|
gimp_display_shell_get_event_coords (shell,
|
|
|
|
compressed_motion,
|
|
|
|
&display_coords,
|
|
|
|
&state, &time);
|
|
|
|
gimp_display_shell_untransform_event_coords (shell,
|
|
|
|
&display_coords,
|
|
|
|
&image_coords,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-27 19:08:09 +08:00
|
|
|
/* call proximity_in() here because the pointer might already
|
|
|
|
* be in proximity when the canvas starts to receive events,
|
|
|
|
* like when a new image has been created into an empty
|
|
|
|
* display
|
|
|
|
*/
|
2011-02-27 19:16:51 +08:00
|
|
|
gimp_display_shell_proximity_in (shell);
|
|
|
|
update_sw_cursor = TRUE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
if (shell->scrolling)
|
|
|
|
{
|
2017-05-12 03:31:41 +08:00
|
|
|
GdkEventMotion *me = (compressed_motion ?
|
|
|
|
(GdkEventMotion *) compressed_motion :
|
|
|
|
mevent);
|
2013-04-20 14:37:15 +08:00
|
|
|
|
2017-05-12 03:31:41 +08:00
|
|
|
gimp_display_shell_handle_scrolling (shell, state, me->x, me->y);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
else if (state & GDK_BUTTON1_MASK)
|
|
|
|
{
|
|
|
|
if (active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control) &&
|
|
|
|
(! gimp_image_is_empty (image) ||
|
|
|
|
gimp_tool_control_get_handle_empty_image (active_tool->control)))
|
|
|
|
{
|
|
|
|
GdkTimeCoord **history_events;
|
|
|
|
gint n_history_events;
|
2011-04-18 19:13:51 +08:00
|
|
|
guint32 last_motion_time;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
/* if the first mouse button is down, check for automatic
|
|
|
|
* scrolling...
|
|
|
|
*/
|
|
|
|
if ((mevent->x < 0 ||
|
|
|
|
mevent->y < 0 ||
|
|
|
|
mevent->x > shell->disp_width ||
|
|
|
|
mevent->y > shell->disp_height) &&
|
|
|
|
! gimp_tool_control_get_scroll_lock (active_tool->control))
|
|
|
|
{
|
|
|
|
gimp_display_shell_autoscroll_start (shell, state, mevent);
|
|
|
|
}
|
|
|
|
|
2011-04-18 19:13:51 +08:00
|
|
|
/* gdk_device_get_history() has several quirks. First
|
|
|
|
* is that events with borderline timestamps at both
|
|
|
|
* ends are included. Because of that we need to add 1
|
|
|
|
* to lower border. The second is due to poor X event
|
2011-02-23 12:21:06 +08:00
|
|
|
* resolution. We need to do -1 to ensure that the
|
|
|
|
* amount of events between timestamps is final or
|
2013-01-27 23:52:38 +08:00
|
|
|
* risk losing some.
|
2011-02-23 12:21:06 +08:00
|
|
|
*/
|
2011-04-18 19:13:51 +08:00
|
|
|
last_motion_time =
|
|
|
|
gimp_motion_buffer_get_last_motion_time (shell->motion_buffer);
|
|
|
|
|
2011-04-18 01:59:31 +08:00
|
|
|
if (motion_mode == GIMP_MOTION_MODE_EXACT &&
|
2011-02-23 12:21:06 +08:00
|
|
|
shell->display->config->use_event_history &&
|
|
|
|
gdk_device_get_history (mevent->device, mevent->window,
|
2011-04-18 19:13:51 +08:00
|
|
|
last_motion_time + 1,
|
2011-02-23 12:21:06 +08:00
|
|
|
mevent->time - 1,
|
|
|
|
&history_events,
|
|
|
|
&n_history_events))
|
|
|
|
{
|
|
|
|
GimpDeviceInfo *device;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
device = gimp_device_info_get_by_device (mevent->device);
|
|
|
|
|
|
|
|
for (i = 0; i < n_history_events; i++)
|
|
|
|
{
|
|
|
|
gimp_device_info_get_time_coords (device,
|
|
|
|
history_events[i],
|
|
|
|
&display_coords);
|
|
|
|
|
|
|
|
gimp_display_shell_untransform_event_coords (shell,
|
|
|
|
&display_coords,
|
|
|
|
&image_coords,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Early removal of useless events saves CPU time.
|
|
|
|
*/
|
2011-04-18 07:09:57 +08:00
|
|
|
if (gimp_motion_buffer_motion_event (shell->motion_buffer,
|
|
|
|
&image_coords,
|
|
|
|
history_events[i]->time,
|
|
|
|
TRUE))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-18 17:31:38 +08:00
|
|
|
gimp_motion_buffer_request_stroke (shell->motion_buffer,
|
2011-04-18 17:08:24 +08:00
|
|
|
state,
|
|
|
|
history_events[i]->time);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gdk_device_free_history (history_events, n_history_events);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-18 01:59:31 +08:00
|
|
|
gboolean event_fill = (motion_mode == GIMP_MOTION_MODE_EXACT);
|
|
|
|
|
2011-02-23 12:21:06 +08:00
|
|
|
/* Early removal of useless events saves CPU time.
|
|
|
|
*/
|
2011-04-18 07:09:57 +08:00
|
|
|
if (gimp_motion_buffer_motion_event (shell->motion_buffer,
|
|
|
|
&image_coords,
|
|
|
|
time,
|
|
|
|
event_fill))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-18 17:31:38 +08:00
|
|
|
gimp_motion_buffer_request_stroke (shell->motion_buffer,
|
2011-04-18 17:08:24 +08:00
|
|
|
state,
|
|
|
|
time);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! (state &
|
|
|
|
(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)))
|
|
|
|
{
|
|
|
|
/* Early removal of useless events saves CPU time.
|
2011-04-18 01:59:31 +08:00
|
|
|
* Pass event_fill = FALSE since we are only hovering.
|
2011-02-23 12:21:06 +08:00
|
|
|
*/
|
2011-04-18 07:09:57 +08:00
|
|
|
if (gimp_motion_buffer_motion_event (shell->motion_buffer,
|
|
|
|
&image_coords,
|
|
|
|
time,
|
|
|
|
FALSE))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-04-18 17:31:38 +08:00
|
|
|
gimp_motion_buffer_request_hover (shell->motion_buffer,
|
2011-04-18 17:08:24 +08:00
|
|
|
state,
|
|
|
|
shell->proximity);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-24 19:23:11 +08:00
|
|
|
if (compressed_motion)
|
|
|
|
gdk_event_free (compressed_motion);
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
return_val = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_KEY_PRESS:
|
|
|
|
{
|
|
|
|
GdkEventKey *kevent = (GdkEventKey *) event;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (state & GDK_BUTTON1_MASK)
|
|
|
|
{
|
2018-03-16 09:31:43 +08:00
|
|
|
if (kevent->keyval == GDK_KEY_Alt_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Alt_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Shift_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Shift_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Meta_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Meta_R)
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
2018-03-16 09:31:43 +08:00
|
|
|
GdkModifierType key;
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
key = gimp_display_shell_key_to_state (kevent->keyval);
|
|
|
|
state |= key;
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
if (active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control) &&
|
|
|
|
! gimp_image_is_empty (image))
|
|
|
|
{
|
|
|
|
tool_manager_active_modifier_state_active (gimp, state,
|
|
|
|
display);
|
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-02-15 08:00:13 +08:00
|
|
|
gboolean arrow_key = FALSE;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_focus_display_active (gimp, display);
|
|
|
|
|
|
|
|
if (gimp_tool_control_get_wants_all_key_events (active_tool->control))
|
|
|
|
{
|
|
|
|
if (tool_manager_key_press_active (gimp, kevent, display))
|
|
|
|
{
|
|
|
|
/* FIXME: need to do some of the stuff below, like
|
|
|
|
* calling oper_update()
|
|
|
|
*/
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 23:27:05 +08:00
|
|
|
if (! gtk_widget_has_focus (shell->canvas))
|
|
|
|
{
|
|
|
|
/* The event was in an overlay widget and not handled
|
|
|
|
* there, make sure the overlay widgets are keyboard
|
|
|
|
* navigatable by letting the generic widget handlers
|
|
|
|
* deal with the event.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (kevent->keyval)
|
|
|
|
{
|
2012-06-08 06:21:07 +08:00
|
|
|
case GDK_KEY_Left:
|
|
|
|
case GDK_KEY_Right:
|
|
|
|
case GDK_KEY_Up:
|
|
|
|
case GDK_KEY_Down:
|
|
|
|
arrow_key = TRUE;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_Return:
|
|
|
|
case GDK_KEY_KP_Enter:
|
|
|
|
case GDK_KEY_ISO_Enter:
|
|
|
|
case GDK_KEY_BackSpace:
|
|
|
|
case GDK_KEY_Escape:
|
2012-06-08 06:21:07 +08:00
|
|
|
if (! gimp_image_is_empty (image))
|
|
|
|
return_val = tool_manager_key_press_active (gimp,
|
|
|
|
kevent,
|
|
|
|
display);
|
|
|
|
|
|
|
|
if (! return_val)
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
GimpController *keyboard = gimp_controllers_get_keyboard (gimp);
|
|
|
|
|
|
|
|
if (keyboard)
|
2012-05-28 01:55:42 +08:00
|
|
|
return_val =
|
|
|
|
gimp_controller_keyboard_key_press (GIMP_CONTROLLER_KEYBOARD (keyboard),
|
|
|
|
kevent);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
2012-06-08 06:21:07 +08:00
|
|
|
|
|
|
|
/* always swallow arrow keys, we don't want focus keynav */
|
|
|
|
if (! return_val)
|
|
|
|
return_val = arrow_key;
|
2011-02-23 13:22:24 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_KEY_space:
|
|
|
|
case GDK_KEY_KP_Space:
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if (shell->button1_release_pending)
|
|
|
|
shell->space_release_pending = TRUE;
|
|
|
|
else
|
|
|
|
gimp_display_shell_space_pressed (shell, event);
|
2011-02-23 13:22:24 +08:00
|
|
|
return_val = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_KEY_Tab:
|
2013-06-08 21:27:14 +08:00
|
|
|
case GDK_KEY_KP_Tab:
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_ISO_Left_Tab:
|
2013-06-08 23:27:05 +08:00
|
|
|
gimp_display_shell_tab_pressed (shell, kevent);
|
|
|
|
return_val = TRUE;
|
2011-02-23 13:22:24 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Update the state based on modifiers being pressed */
|
|
|
|
case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
|
|
|
|
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R:
|
|
|
|
case GDK_KEY_Control_L: case GDK_KEY_Control_R:
|
2011-10-06 01:44:24 +08:00
|
|
|
case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
GdkModifierType key;
|
|
|
|
|
|
|
|
key = gimp_display_shell_key_to_state (kevent->keyval);
|
|
|
|
state |= key;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (! gimp_image_is_empty (image))
|
|
|
|
tool_manager_modifier_state_active (gimp, state, display);
|
|
|
|
}
|
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_RELEASE:
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
|
|
|
GdkEventKey *kevent = (GdkEventKey *) event;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
if ((state & GDK_BUTTON1_MASK) &&
|
|
|
|
(! shell->space_release_pending ||
|
|
|
|
(kevent->keyval != GDK_KEY_space &&
|
|
|
|
kevent->keyval != GDK_KEY_KP_Space)))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2018-03-16 09:31:43 +08:00
|
|
|
if (kevent->keyval == GDK_KEY_Alt_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Alt_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Shift_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Shift_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Control_R ||
|
|
|
|
kevent->keyval == GDK_KEY_Meta_L ||
|
|
|
|
kevent->keyval == GDK_KEY_Meta_R)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2018-03-16 09:31:43 +08:00
|
|
|
GdkModifierType key;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
key = gimp_display_shell_key_to_state (kevent->keyval);
|
|
|
|
state &= ~key;
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
if (active_tool &&
|
|
|
|
gimp_tool_control_is_active (active_tool->control) &&
|
|
|
|
! gimp_image_is_empty (image))
|
|
|
|
{
|
|
|
|
tool_manager_active_modifier_state_active (gimp, state,
|
|
|
|
display);
|
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tool_manager_focus_display_active (gimp, display);
|
|
|
|
|
|
|
|
if (gimp_tool_control_get_wants_all_key_events (active_tool->control))
|
|
|
|
{
|
|
|
|
if (tool_manager_key_release_active (gimp, kevent, display))
|
|
|
|
{
|
|
|
|
/* FIXME: need to do some of the stuff below, like
|
|
|
|
* calling oper_update()
|
|
|
|
*/
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 23:27:05 +08:00
|
|
|
if (! gtk_widget_has_focus (shell->canvas))
|
|
|
|
{
|
|
|
|
/* The event was in an overlay widget and not handled
|
|
|
|
* there, make sure the overlay widgets are keyboard
|
|
|
|
* navigatable by letting the generic widget handlers
|
|
|
|
* deal with the event.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (kevent->keyval)
|
|
|
|
{
|
|
|
|
case GDK_KEY_space:
|
|
|
|
case GDK_KEY_KP_Space:
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if ((state & GDK_BUTTON1_MASK))
|
|
|
|
{
|
|
|
|
shell->button1_release_pending = TRUE;
|
|
|
|
shell->space_release_pending = FALSE;
|
|
|
|
/* We need to ungrab the pointer in order to catch
|
|
|
|
* button release events.
|
|
|
|
*/
|
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
gimp_display_shell_pointer_ungrab (shell, event);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_released (shell, event, NULL);
|
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
return_val = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Update the state based on modifiers being pressed */
|
|
|
|
case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
|
|
|
|
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R:
|
|
|
|
case GDK_KEY_Control_L: case GDK_KEY_Control_R:
|
2011-10-06 01:44:24 +08:00
|
|
|
case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
GdkModifierType key;
|
|
|
|
|
|
|
|
key = gimp_display_shell_key_to_state (kevent->keyval);
|
|
|
|
state &= ~key;
|
|
|
|
|
|
|
|
/* For all modifier keys: call the tools
|
|
|
|
* modifier_state *and* oper_update method so tools
|
|
|
|
* can choose if they are interested in the press
|
|
|
|
* itself or only in the resulting state
|
|
|
|
*/
|
|
|
|
if (! gimp_image_is_empty (image))
|
|
|
|
tool_manager_modifier_state_active (gimp, state, display);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
&image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we reached this point in gimp_busy mode, return now */
|
|
|
|
if (gimp->busy)
|
|
|
|
return return_val;
|
|
|
|
|
|
|
|
/* cursor update */
|
|
|
|
gimp_display_shell_update_cursor (shell, &display_coords, &image_coords,
|
|
|
|
state, update_sw_cursor);
|
|
|
|
|
|
|
|
return return_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkModifierType
|
|
|
|
gimp_display_shell_key_to_state (gint key)
|
|
|
|
{
|
2011-10-06 01:44:24 +08:00
|
|
|
/* FIXME: need some proper GDK API to figure this */
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case GDK_KEY_Alt_L:
|
|
|
|
case GDK_KEY_Alt_R:
|
|
|
|
return GDK_MOD1_MASK;
|
2016-04-15 07:17:00 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_Shift_L:
|
|
|
|
case GDK_KEY_Shift_R:
|
|
|
|
return GDK_SHIFT_MASK;
|
2016-04-15 07:17:00 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GDK_KEY_Control_L:
|
|
|
|
case GDK_KEY_Control_R:
|
|
|
|
return GDK_CONTROL_MASK;
|
2016-04-15 07:17:00 +08:00
|
|
|
|
2011-10-06 01:44:24 +08:00
|
|
|
#ifdef GDK_WINDOWING_QUARTZ
|
|
|
|
case GDK_KEY_Meta_L:
|
|
|
|
case GDK_KEY_Meta_R:
|
|
|
|
return GDK_MOD2_MASK;
|
|
|
|
#endif
|
2016-04-15 07:17:00 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-06 02:04:42 +08:00
|
|
|
static GdkModifierType
|
|
|
|
gimp_display_shell_button_to_state (gint button)
|
|
|
|
{
|
|
|
|
if (button == 1)
|
|
|
|
return GDK_BUTTON1_MASK;
|
|
|
|
else if (button == 2)
|
|
|
|
return GDK_BUTTON2_MASK;
|
|
|
|
else if (button == 3)
|
|
|
|
return GDK_BUTTON3_MASK;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-27 19:08:09 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_proximity_in (GimpDisplayShell *shell)
|
|
|
|
{
|
2011-02-27 19:16:51 +08:00
|
|
|
if (! shell->proximity)
|
|
|
|
{
|
|
|
|
shell->proximity = TRUE;
|
2011-02-27 19:08:09 +08:00
|
|
|
|
2011-02-27 19:16:51 +08:00
|
|
|
gimp_display_shell_check_device_cursor (shell);
|
|
|
|
}
|
2011-02-27 19:08:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_display_shell_proximity_out (GimpDisplayShell *shell)
|
|
|
|
{
|
2011-02-27 19:16:51 +08:00
|
|
|
if (shell->proximity)
|
|
|
|
{
|
|
|
|
shell->proximity = FALSE;
|
2011-02-27 19:08:09 +08:00
|
|
|
|
2011-02-27 19:16:51 +08:00
|
|
|
gimp_display_shell_clear_software_cursor (shell);
|
|
|
|
}
|
2011-02-27 19:08:09 +08:00
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_check_device_cursor (GimpDisplayShell *shell)
|
|
|
|
{
|
2011-02-28 21:37:00 +08:00
|
|
|
GimpDeviceManager *manager;
|
|
|
|
GimpDeviceInfo *current_device;
|
|
|
|
|
|
|
|
manager = gimp_devices_get_manager (shell->display->gimp);
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2011-02-28 21:37:00 +08:00
|
|
|
current_device = gimp_device_manager_get_current_device (manager);
|
2011-02-23 13:22:24 +08:00
|
|
|
|
|
|
|
shell->draw_cursor = ! gimp_device_info_has_cursor (current_device);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
|
2011-12-10 03:20:02 +08:00
|
|
|
const GdkEvent *event,
|
2013-04-19 22:22:19 +08:00
|
|
|
GdkModifierType state,
|
2011-02-23 13:22:24 +08:00
|
|
|
gint x,
|
|
|
|
gint y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (! shell->scrolling);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_pointer_grab (shell, event, GDK_POINTER_MOTION_MASK);
|
|
|
|
|
2013-04-19 22:22:19 +08:00
|
|
|
shell->scrolling = TRUE;
|
|
|
|
shell->scroll_last_x = x;
|
|
|
|
shell->scroll_last_y = y;
|
2016-11-16 21:41:30 +08:00
|
|
|
shell->rotating = (state & gimp_get_extend_selection_mask ()) ? TRUE : FALSE;
|
2013-04-19 22:22:19 +08:00
|
|
|
shell->rotate_drag_angle = shell->rotate_angle;
|
2016-11-16 21:41:30 +08:00
|
|
|
shell->scaling = (state & gimp_get_toggle_behavior_mask ()) ? TRUE : FALSE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-19 22:22:19 +08:00
|
|
|
if (shell->rotating)
|
2015-01-10 06:47:57 +08:00
|
|
|
gimp_display_shell_set_override_cursor (shell,
|
|
|
|
(GimpCursorType) GDK_EXCHANGE);
|
2017-05-12 03:31:41 +08:00
|
|
|
else if (shell->scaling)
|
2016-11-16 21:41:30 +08:00
|
|
|
gimp_display_shell_set_override_cursor (shell,
|
|
|
|
(GimpCursorType) GIMP_CURSOR_ZOOM);
|
2013-04-19 22:22:19 +08:00
|
|
|
else
|
2015-01-10 06:47:57 +08:00
|
|
|
gimp_display_shell_set_override_cursor (shell,
|
|
|
|
(GimpCursorType) GDK_FLEUR);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_stop_scrolling (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event)
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (shell->scrolling);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_unset_override_cursor (shell);
|
|
|
|
|
2013-04-19 22:22:19 +08:00
|
|
|
shell->scrolling = FALSE;
|
|
|
|
shell->scroll_last_x = 0;
|
|
|
|
shell->scroll_last_y = 0;
|
|
|
|
shell->rotating = FALSE;
|
|
|
|
shell->rotate_drag_angle = 0.0;
|
2016-11-16 21:41:30 +08:00
|
|
|
shell->scaling = FALSE;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
/* We may have ungrabbed the pointer when space was released while
|
|
|
|
* mouse was down, to be able to catch a GDK_BUTTON_RELEASE event.
|
|
|
|
*/
|
|
|
|
if (shell->pointer_grabbed)
|
|
|
|
gimp_display_shell_pointer_ungrab (shell, event);
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2017-05-12 03:31:41 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_handle_scrolling (GimpDisplayShell *shell,
|
|
|
|
GdkModifierType state,
|
|
|
|
gint x,
|
|
|
|
gint y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (shell->scrolling);
|
|
|
|
|
|
|
|
if (shell->rotating)
|
|
|
|
{
|
|
|
|
gboolean constrain = (state & GDK_CONTROL_MASK) ? TRUE : FALSE;
|
|
|
|
|
|
|
|
gimp_display_shell_rotate_drag (shell,
|
|
|
|
shell->scroll_last_x,
|
|
|
|
shell->scroll_last_y,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
constrain);
|
|
|
|
}
|
|
|
|
else if (shell->scaling)
|
|
|
|
{
|
|
|
|
gimp_display_shell_scale_drag (shell,
|
|
|
|
shell->scroll_last_x - x,
|
|
|
|
shell->scroll_last_y - y);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_scroll (shell,
|
|
|
|
shell->scroll_last_x - x,
|
|
|
|
shell->scroll_last_y - y);
|
|
|
|
}
|
|
|
|
|
|
|
|
shell->scroll_last_x = x;
|
|
|
|
shell->scroll_last_y = y;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_space_pressed (GimpDisplayShell *shell,
|
2011-06-01 05:17:29 +08:00
|
|
|
const GdkEvent *event)
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (shell->display);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-03-17 02:32:10 +08:00
|
|
|
if (shell->space_release_pending || shell->scrolling)
|
2011-02-23 13:22:24 +08:00
|
|
|
return;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (! gimp_display_shell_keyboard_grab (shell, event))
|
|
|
|
return;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (shell->display->config->space_bar_action)
|
|
|
|
{
|
|
|
|
case GIMP_SPACE_BAR_ACTION_NONE:
|
2013-04-28 21:28:18 +08:00
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GIMP_SPACE_BAR_ACTION_PAN:
|
|
|
|
{
|
2011-02-28 21:37:00 +08:00
|
|
|
GimpDeviceManager *manager;
|
|
|
|
GimpDeviceInfo *current_device;
|
|
|
|
GimpCoords coords;
|
2013-04-19 22:22:19 +08:00
|
|
|
GdkModifierType state = 0;
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2011-02-28 21:37:00 +08:00
|
|
|
manager = gimp_devices_get_manager (gimp);
|
|
|
|
current_device = gimp_device_manager_get_current_device (manager);
|
|
|
|
|
|
|
|
gimp_device_info_get_device_coords (current_device,
|
2011-02-23 13:22:24 +08:00
|
|
|
gtk_widget_get_window (shell->canvas),
|
|
|
|
&coords);
|
2013-04-19 22:22:19 +08:00
|
|
|
gdk_event_get_state (event, &state);
|
2011-02-23 13:22:24 +08:00
|
|
|
|
2013-04-19 22:22:19 +08:00
|
|
|
gimp_display_shell_start_scrolling (shell, event, state,
|
2011-12-10 03:20:02 +08:00
|
|
|
coords.x, coords.y);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GIMP_SPACE_BAR_ACTION_MOVE:
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2013-04-28 21:28:18 +08:00
|
|
|
GimpTool *active_tool = tool_manager_get_active (gimp);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
if (active_tool || ! GIMP_IS_MOVE_TOOL (active_tool))
|
|
|
|
{
|
|
|
|
GdkModifierType state;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
shell->space_shaded_tool =
|
|
|
|
gimp_object_get_name (active_tool->tool_info);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
gimp_context_set_tool (gimp_get_user_context (gimp),
|
|
|
|
gimp_get_tool_info (gimp, "gimp-move-tool"));
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
gdk_event_get_state (event, &state);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
NULL, state);
|
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2018-03-16 09:31:43 +08:00
|
|
|
shell->space_release_pending = TRUE;
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
gimp_display_shell_released (GimpDisplayShell *shell,
|
|
|
|
const GdkEvent *event,
|
|
|
|
const GimpCoords *image_coords)
|
2011-02-23 13:22:24 +08:00
|
|
|
{
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (shell->display);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
if (! shell->space_release_pending &&
|
|
|
|
! shell->button1_release_pending)
|
2011-02-23 13:22:24 +08:00
|
|
|
return;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
switch (shell->display->config->space_bar_action)
|
|
|
|
{
|
|
|
|
case GIMP_SPACE_BAR_ACTION_NONE:
|
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GIMP_SPACE_BAR_ACTION_PAN:
|
2011-12-10 03:20:02 +08:00
|
|
|
gimp_display_shell_stop_scrolling (shell, event);
|
2011-02-23 13:22:24 +08:00
|
|
|
break;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
case GIMP_SPACE_BAR_ACTION_MOVE:
|
2013-04-28 21:28:18 +08:00
|
|
|
if (shell->space_shaded_tool)
|
|
|
|
{
|
|
|
|
gimp_context_set_tool (gimp_get_user_context (gimp),
|
|
|
|
gimp_get_tool_info (gimp,
|
|
|
|
shell->space_shaded_tool));
|
|
|
|
shell->space_shaded_tool = NULL;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
if (gtk_widget_has_focus (shell->canvas))
|
|
|
|
{
|
|
|
|
GdkModifierType state;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
gdk_event_get_state (event, &state);
|
2011-04-07 03:35:29 +08:00
|
|
|
|
2013-04-28 21:28:18 +08:00
|
|
|
gimp_display_shell_update_focus (shell, TRUE,
|
|
|
|
image_coords, state);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_update_focus (shell, FALSE,
|
|
|
|
image_coords, 0);
|
|
|
|
}
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
gimp_display_shell_keyboard_ungrab (shell, event);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
Bug 724692 - Canvas rotation stuck with specific order of actions.
Commit b279c2d217 was breaking a specific use case, which I oversaw:
when space bar activates the move tool, you may want to release the
space bar while mouse button is pressed, and expect to still be able to
move the layer/selection/guide, but releasing space was stopping the
move immediately. The move tool must only be deactivated when both space
and button 1 are released, and the move itself must continue as long as
button 1 is pressed (when started while space was pressed).
As a nice side effect of this commit, panning and canvas rotation are
also improved since now they can be continued while releasing space
(respectively shift-space) if mouse button 1 was pressed, and up until
the mouse button is released. Pressing space again, then releasing the
mouse, back and forth, also work as expected (i.e. move tool stay
activated though the move stops; and panning or rotation continue).
Of course now we don't get anymore panning/rotation stuck while neither
space nor mouse buttons are pressed (which was the original bug). At
least one of these need to stay pressed for panning/rotation/move to
stay activated. And initial activation is obviously always through
(shift-)space only.
2018-04-14 21:36:08 +08:00
|
|
|
shell->space_release_pending = FALSE;
|
|
|
|
shell->button1_release_pending = FALSE;
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
2011-05-31 15:24:14 +08:00
|
|
|
static gboolean
|
2011-06-01 05:17:29 +08:00
|
|
|
gimp_display_shell_tab_pressed (GimpDisplayShell *shell,
|
|
|
|
const GdkEventKey *kevent)
|
2011-05-31 15:24:14 +08:00
|
|
|
{
|
|
|
|
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
|
|
|
GimpUIManager *manager = gimp_image_window_get_ui_manager (window);
|
|
|
|
GimpImage *image = gimp_display_get_image (shell->display);
|
|
|
|
|
|
|
|
if (kevent->state & GDK_CONTROL_MASK)
|
|
|
|
{
|
|
|
|
if (image && ! gimp_image_is_empty (image))
|
|
|
|
{
|
2013-06-08 21:27:14 +08:00
|
|
|
if (kevent->keyval == GDK_KEY_Tab ||
|
|
|
|
kevent->keyval == GDK_KEY_KP_Tab)
|
2011-05-31 15:24:14 +08:00
|
|
|
gimp_display_shell_layer_select_init (shell,
|
|
|
|
1, kevent->time);
|
|
|
|
else
|
|
|
|
gimp_display_shell_layer_select_init (shell,
|
|
|
|
-1, kevent->time);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (kevent->state & GDK_MOD1_MASK)
|
|
|
|
{
|
|
|
|
if (image)
|
|
|
|
{
|
2013-06-08 21:27:14 +08:00
|
|
|
if (kevent->keyval == GDK_KEY_Tab ||
|
|
|
|
kevent->keyval == GDK_KEY_KP_Tab)
|
2011-05-31 15:24:14 +08:00
|
|
|
gimp_ui_manager_activate_action (manager, "windows",
|
|
|
|
"windows-show-display-next");
|
|
|
|
else
|
|
|
|
gimp_ui_manager_activate_action (manager, "windows",
|
|
|
|
"windows-show-display-previous");
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_ui_manager_activate_action (manager, "windows",
|
|
|
|
"windows-hide-docks");
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_update_focus (GimpDisplayShell *shell,
|
2011-04-04 01:01:13 +08:00
|
|
|
gboolean focus_in,
|
2011-02-23 13:22:24 +08:00
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
Gimp *gimp = gimp_display_get_gimp (shell->display);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-04-04 01:01:13 +08:00
|
|
|
if (focus_in)
|
|
|
|
{
|
|
|
|
tool_manager_focus_display_active (gimp, shell->display);
|
|
|
|
tool_manager_modifier_state_active (gimp, state, shell->display);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tool_manager_focus_display_active (gimp, NULL);
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (image_coords)
|
|
|
|
tool_manager_oper_update_active (gimp,
|
|
|
|
image_coords, state,
|
|
|
|
shell->proximity,
|
|
|
|
shell->display);
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_update_cursor (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *display_coords,
|
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
gboolean update_software_cursor)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = shell->display;
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (display);
|
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
|
|
|
GimpTool *active_tool;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (! shell->display->config->cursor_updating)
|
|
|
|
return;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
active_tool = tool_manager_get_active (gimp);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (active_tool)
|
|
|
|
{
|
|
|
|
if ((! gimp_image_is_empty (image) ||
|
|
|
|
gimp_tool_control_get_handle_empty_image (active_tool->control)) &&
|
|
|
|
! (state & (GDK_BUTTON1_MASK |
|
|
|
|
GDK_BUTTON2_MASK |
|
|
|
|
GDK_BUTTON3_MASK)))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
tool_manager_cursor_update_active (gimp,
|
|
|
|
image_coords, state,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
else if (gimp_image_is_empty (image) &&
|
|
|
|
! gimp_tool_control_get_handle_empty_image (active_tool->control))
|
|
|
|
{
|
|
|
|
gimp_display_shell_set_cursor (shell,
|
|
|
|
GIMP_CURSOR_MOUSE,
|
|
|
|
gimp_tool_control_get_tool_cursor (active_tool->control),
|
|
|
|
GIMP_CURSOR_MODIFIER_BAD);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
2011-02-23 13:22:24 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_display_shell_set_cursor (shell,
|
|
|
|
GIMP_CURSOR_MOUSE,
|
|
|
|
GIMP_TOOL_CURSOR_NONE,
|
|
|
|
GIMP_CURSOR_MODIFIER_BAD);
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (update_software_cursor)
|
|
|
|
{
|
|
|
|
GimpCursorPrecision precision = GIMP_CURSOR_PRECISION_PIXEL_CENTER;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
if (active_tool)
|
2011-02-23 13:22:24 +08:00
|
|
|
precision = gimp_tool_control_get_precision (active_tool->control);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
gimp_display_shell_update_software_cursor (shell,
|
|
|
|
precision,
|
|
|
|
(gint) display_coords->x,
|
|
|
|
(gint) display_coords->y,
|
|
|
|
image_coords->x,
|
|
|
|
image_coords->y);
|
|
|
|
}
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-04-04 00:27:03 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_display_shell_initialize_tool (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *image_coords,
|
|
|
|
GdkModifierType state)
|
|
|
|
{
|
|
|
|
GimpDisplay *display = shell->display;
|
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
|
|
|
Gimp *gimp = gimp_display_get_gimp (display);
|
|
|
|
gboolean initialized = FALSE;
|
|
|
|
GimpTool *active_tool;
|
|
|
|
|
|
|
|
active_tool = tool_manager_get_active (gimp);
|
|
|
|
|
|
|
|
if (active_tool &&
|
|
|
|
(! gimp_image_is_empty (image) ||
|
|
|
|
gimp_tool_control_get_handle_empty_image (active_tool->control)))
|
|
|
|
{
|
|
|
|
initialized = TRUE;
|
|
|
|
|
|
|
|
/* initialize the current tool if it has no drawable */
|
|
|
|
if (! active_tool->drawable)
|
|
|
|
{
|
|
|
|
initialized = tool_manager_initialize_active (gimp, display);
|
|
|
|
}
|
|
|
|
else if ((active_tool->drawable !=
|
|
|
|
gimp_image_get_active_drawable (image)) &&
|
2012-09-07 05:55:35 +08:00
|
|
|
(! gimp_tool_control_get_preserve (active_tool->control) &&
|
|
|
|
(gimp_tool_control_get_dirty_mask (active_tool->control) &
|
|
|
|
GIMP_DIRTY_ACTIVE_DRAWABLE)))
|
2011-04-04 00:27:03 +08:00
|
|
|
{
|
2017-01-23 07:00:03 +08:00
|
|
|
GimpProcedure *procedure = g_object_get_data (G_OBJECT (active_tool),
|
|
|
|
"gimp-gegl-procedure");
|
|
|
|
|
|
|
|
if (image == gimp_item_get_image (GIMP_ITEM (active_tool->drawable)))
|
|
|
|
{
|
|
|
|
/* When changing between drawables if the *same* image,
|
|
|
|
* halt the tool so it doesn't get committed on tool
|
|
|
|
* change. This is a pure "probably better this way"
|
|
|
|
* decision because the user is likely changing their
|
|
|
|
* mind or was simply on the wrong layer. See bug
|
|
|
|
* #776370.
|
|
|
|
*/
|
|
|
|
tool_manager_control_active (gimp, GIMP_TOOL_ACTION_HALT,
|
|
|
|
active_tool->display);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (procedure)
|
|
|
|
{
|
|
|
|
/* We can't just recreate an operation tool, we must
|
|
|
|
* make sure the right stuff gets set on it, so
|
|
|
|
* re-activate the procedure that created it instead of
|
|
|
|
* just calling gimp_context_tool_changed(). See
|
|
|
|
* GimpGeglProcedure and bug #776370.
|
|
|
|
*/
|
|
|
|
GimpImageWindow *window;
|
|
|
|
GimpUIManager *manager;
|
|
|
|
|
|
|
|
window = gimp_display_shell_get_window (shell);
|
|
|
|
manager = gimp_image_window_get_ui_manager (window);
|
|
|
|
|
|
|
|
gimp_filter_history_add (gimp, procedure);
|
|
|
|
gimp_ui_manager_activate_action (manager, "filters",
|
|
|
|
"filters-reshow");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* create a new one, deleting the current */
|
|
|
|
gimp_context_tool_changed (gimp_get_user_context (gimp));
|
|
|
|
}
|
2011-04-04 00:27:03 +08:00
|
|
|
|
|
|
|
/* make sure the newly created tool has the right state */
|
2011-04-04 01:01:13 +08:00
|
|
|
gimp_display_shell_update_focus (shell, TRUE, image_coords, state);
|
2011-04-04 00:27:03 +08:00
|
|
|
|
|
|
|
initialized = tool_manager_initialize_active (gimp, display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return initialized;
|
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_get_event_coords (GimpDisplayShell *shell,
|
2011-06-01 05:17:29 +08:00
|
|
|
const GdkEvent *event,
|
2011-02-23 13:22:24 +08:00
|
|
|
GimpCoords *display_coords,
|
|
|
|
GdkModifierType *state,
|
|
|
|
guint32 *time)
|
|
|
|
{
|
2011-02-28 21:37:00 +08:00
|
|
|
Gimp *gimp = gimp_display_get_gimp (shell->display);
|
|
|
|
GimpDeviceManager *manager;
|
|
|
|
GimpDeviceInfo *current_device;
|
|
|
|
|
|
|
|
manager = gimp_devices_get_manager (gimp);
|
|
|
|
current_device = gimp_device_manager_get_current_device (manager);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-28 21:37:00 +08:00
|
|
|
gimp_device_info_get_event_coords (current_device,
|
2011-02-23 13:22:24 +08:00
|
|
|
gtk_widget_get_window (shell->canvas),
|
|
|
|
event,
|
|
|
|
display_coords);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-28 21:37:00 +08:00
|
|
|
gimp_device_info_get_event_state (current_device,
|
2011-02-23 13:22:24 +08:00
|
|
|
gtk_widget_get_window (shell->canvas),
|
|
|
|
event,
|
|
|
|
state);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
*time = gdk_event_get_time (event);
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
static void
|
|
|
|
gimp_display_shell_untransform_event_coords (GimpDisplayShell *shell,
|
|
|
|
const GimpCoords *display_coords,
|
|
|
|
GimpCoords *image_coords,
|
|
|
|
gboolean *update_software_cursor)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2011-02-23 13:22:24 +08:00
|
|
|
Gimp *gimp = gimp_display_get_gimp (shell->display);
|
|
|
|
GimpTool *active_tool;
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
/* GimpCoords passed to tools are ALWAYS in image coordinates */
|
|
|
|
gimp_display_shell_untransform_coords (shell,
|
|
|
|
display_coords,
|
|
|
|
image_coords);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
active_tool = tool_manager_get_active (gimp);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
2011-02-23 13:22:24 +08:00
|
|
|
if (active_tool && gimp_tool_control_get_snap_to (active_tool->control))
|
|
|
|
{
|
|
|
|
gint x, y, width, height;
|
|
|
|
|
|
|
|
gimp_tool_control_get_snap_offsets (active_tool->control,
|
|
|
|
&x, &y, &width, &height);
|
|
|
|
|
|
|
|
if (gimp_display_shell_snap_coords (shell,
|
|
|
|
image_coords,
|
|
|
|
x, y, width, height))
|
|
|
|
{
|
|
|
|
if (update_software_cursor)
|
|
|
|
*update_software_cursor = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
/* gimp_display_shell_compress_motion:
|
|
|
|
*
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
* This function walks the GDK event queue, seeking motion events at the
|
|
|
|
* front of the queue corresponding to the same widget as, and having
|
|
|
|
* similar characteristics to, `initial_event`. If it finds any it will
|
2011-02-23 12:21:06 +08:00
|
|
|
* remove them from the queue, and return the most recent motion event.
|
|
|
|
* Otherwise it will return NULL.
|
|
|
|
*
|
2018-01-04 21:45:18 +08:00
|
|
|
* If `*next_event` is non-NULL upon return, the caller must dispatch and
|
2018-01-04 19:02:53 +08:00
|
|
|
* free this event after handling the motion event.
|
|
|
|
*
|
2011-02-23 12:21:06 +08:00
|
|
|
* The gimp_display_shell_compress_motion function source may be re-used under
|
|
|
|
* the XFree86-style license. <adam@gimp.org>
|
|
|
|
*/
|
|
|
|
static GdkEvent *
|
2018-01-04 19:02:53 +08:00
|
|
|
gimp_display_shell_compress_motion (GdkEvent *initial_event,
|
|
|
|
GdkEvent **next_event)
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
GdkEvent *last_motion = NULL;
|
|
|
|
GtkWidget *widget;
|
|
|
|
|
2018-01-04 19:02:53 +08:00
|
|
|
*next_event = NULL;
|
|
|
|
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
if (initial_event->any.type != GDK_MOTION_NOTIFY)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
widget = gtk_get_event_widget (initial_event);
|
2011-02-23 12:21:06 +08:00
|
|
|
|
|
|
|
while (gdk_events_pending ())
|
|
|
|
{
|
|
|
|
GdkEvent *event = gdk_event_get ();
|
|
|
|
|
|
|
|
if (!event)
|
|
|
|
{
|
|
|
|
/* Do nothing */
|
|
|
|
}
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
else if ((gtk_get_event_widget (event) == widget) &&
|
|
|
|
(event->any.type == GDK_MOTION_NOTIFY) &&
|
2018-01-04 19:02:53 +08:00
|
|
|
(event->any.window == initial_event->any.window) &&
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
(event->motion.state == initial_event->motion.state) &&
|
|
|
|
(event->motion.device == initial_event->motion.device))
|
2011-02-23 12:21:06 +08:00
|
|
|
{
|
2018-01-04 19:02:53 +08:00
|
|
|
/* Discard previous motion event */
|
2011-02-23 12:21:06 +08:00
|
|
|
if (last_motion)
|
|
|
|
gdk_event_free (last_motion);
|
|
|
|
|
|
|
|
last_motion = event;
|
|
|
|
}
|
app: compress tool motion evnets more conservatively
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
2017-06-12 02:45:36 +08:00
|
|
|
else
|
2012-06-24 19:23:11 +08:00
|
|
|
{
|
2018-01-04 19:02:53 +08:00
|
|
|
/* Let the caller dispatch the event */
|
|
|
|
*next_event = event;
|
2012-06-24 19:23:11 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2011-02-23 12:21:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return last_motion;
|
|
|
|
}
|