gimpdisplayshell-callbacks.c 51.7 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* The GIMP -- an 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 2 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, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

19
#include "config.h"
20

Elliot Lee's avatar
Elliot Lee committed
21
#include <stdlib.h>
22

23
#include <gtk/gtk.h>
24
25
#include <gdk/gdkkeysyms.h>

Michael Natterer's avatar
Michael Natterer committed
26
27
28
#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h"

29
#include "display-types.h"
30
#include "tools/tools-types.h"
31

32
33
#include "config/gimpdisplayconfig.h"

Michael Natterer's avatar
Michael Natterer committed
34
#include "core/gimp.h"
35
#include "core/gimpcontainer.h"
36
37
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
38
#include "core/gimpimage-guides.h"
39
#include "core/gimpimage-qmask.h"
40
#include "core/gimplayer.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "core/gimptoolinfo.h"
42

43
#include "tools/gimpmovetool.h"
44
#include "tools/gimptoolcontrol.h"
45
46
#include "tools/tool_manager.h"

47
#include "widgets/gimpactiongroup.h"
48
#include "widgets/gimpcontrollers.h"
49
#include "widgets/gimpcontrollerkeyboard.h"
50
#include "widgets/gimpcontrollerwheel.h"
51
#include "widgets/gimpcursor.h"
52
#include "widgets/gimpdevices.h"
53
54
#include "widgets/gimpdialogfactory.h"
#include "widgets/gimpuimanager.h"
55
#include "widgets/gimpwidgets-utils.h"
Michael Natterer's avatar
Michael Natterer committed
56

57
#include "gimpcanvas.h"
58
#include "gimpdisplay.h"
59
#include "gimpdisplayoptions.h"
Michael Natterer's avatar
Michael Natterer committed
60
#include "gimpdisplayshell.h"
61
#include "gimpdisplayshell-appearance.h"
62
#include "gimpdisplayshell-autoscroll.h"
63
#include "gimpdisplayshell-callbacks.h"
64
#include "gimpdisplayshell-coords.h"
65
#include "gimpdisplayshell-cursor.h"
66
#include "gimpdisplayshell-draw.h"
67
#include "gimpdisplayshell-layer-select.h"
68
#include "gimpdisplayshell-preview.h"
69
70
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
71
#include "gimpdisplayshell-selection.h"
72
73
#include "gimpdisplayshell-title.h"
#include "gimpdisplayshell-transform.h"
74
#include "gimpnavigationeditor.h"
75

76
#include "gimp-intl.h"
77

78

79
80
81
/* #define DEBUG_MOVE_PUSH 1 */


Michael Natterer's avatar
Michael Natterer committed
82
83
84
85
86
87
88
/*  local function prototypes  */

static void     gimp_display_shell_vscrollbar_update (GtkAdjustment    *adjustment,
                                                      GimpDisplayShell *shell);
static void     gimp_display_shell_hscrollbar_update (GtkAdjustment    *adjustment,
                                                      GimpDisplayShell *shell);

89
static GdkModifierType
Michael Natterer's avatar
Michael Natterer committed
90
                gimp_display_shell_key_to_state      (gint              key);
91

92
93
94
GdkEvent *      gimp_display_shell_compress_motion   (GimpDisplayShell *shell);


Michael Natterer's avatar
Michael Natterer committed
95
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
96

97
gboolean
98
99
100
gimp_display_shell_events (GtkWidget        *widget,
                           GdkEvent         *event,
                           GimpDisplayShell *shell)
101
{
102
103
104
105
106
107
108
109
  Gimp        *gimp;
  gboolean     set_display = FALSE;

  /*  are we in destruction?  */
  if (! shell->gdisp || ! shell->gdisp->shell)
    return TRUE;

  gimp = shell->gdisp->gimage->gimp;
110

111
112
113
  switch (event->type)
    {
    case GDK_KEY_PRESS:
114
    case GDK_KEY_RELEASE:
115
116
      {
        GdkEventKey *kevent = (GdkEventKey *) event;
117

118
119
        if (gimp->busy)
          return TRUE;
120

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
        /*  do not process any key events while BUTTON1 is down. We do this
         *  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 (event->type == GDK_KEY_PRESS)
              {
                if (kevent->keyval == GDK_space && shell->space_release_pending)
                  {
                    shell->space_pressed         = TRUE;
                    shell->space_release_pending = FALSE;
                  }
              }
            else
              {
                if (kevent->keyval == GDK_space && shell->space_pressed)
                  {
                    shell->space_pressed         = FALSE;
                    shell->space_release_pending = TRUE;
                  }
              }
143

144
145
            return TRUE;
          }
146

147
148
149
150
151
152
153
154
155
156
        switch (kevent->keyval)
          {
          case GDK_Left:      case GDK_Right:
          case GDK_Up:        case GDK_Down:
          case GDK_space:
          case GDK_Tab:
          case GDK_ISO_Left_Tab:
          case GDK_Alt_L:     case GDK_Alt_R:
          case GDK_Shift_L:   case GDK_Shift_R:
          case GDK_Control_L: case GDK_Control_R:
157
158
          case GDK_Return:    case GDK_KP_Enter:
          case GDK_BackSpace: case GDK_Delete:
159
            break;
160

161
          case GDK_Escape:
162
163
            if (event->type == GDK_KEY_PRESS)
              gimp_display_shell_set_fullscreen (shell, FALSE);
164
            break;
165

166
167
168
169
170
          default:
            if (shell->space_pressed)
              return TRUE;
            break;
          }
171

172
173
174
        set_display = TRUE;
        break;
      }
175

Michael Natterer's avatar
Michael Natterer committed
176
    case GDK_BUTTON_PRESS:
177
    case GDK_SCROLL:
178
      set_display = TRUE;
179
      break;
180

181
182
183
184
185
186
187
188
189
    case GDK_FOCUS_CHANGE:
      {
        GdkEventFocus *fevent = (GdkEventFocus *) event;

        if (fevent->in && GIMP_DISPLAY_CONFIG (gimp->config)->activate_on_focus)
          set_display = TRUE;
      }
      break;

190
191
    case GDK_WINDOW_STATE:
      {
192
        GdkEventWindowState *sevent = (GdkEventWindowState *) event;
193
194
        GimpDisplayOptions  *options;
        gboolean             fullscreen;
195
        GimpActionGroup     *group;
196

197
        shell->window_state = sevent->new_window_state;
198

199
200
        if (! (sevent->changed_mask & GDK_WINDOW_STATE_FULLSCREEN))
          break;
201

202
203
        fullscreen = gimp_display_shell_get_fullscreen (shell);

204
205
206
207
208
209
210
211
212
213
214
215
216
        options = fullscreen ? shell->fullscreen_options : shell->options;

        gimp_display_shell_set_show_menubar    (shell,
                                                options->show_menubar);
        gimp_display_shell_set_show_rulers     (shell,
                                                options->show_rulers);
        gimp_display_shell_set_show_scrollbars (shell,
                                                options->show_scrollbars);
        gimp_display_shell_set_show_statusbar  (shell,
                                                options->show_statusbar);
        gimp_display_shell_set_show_selection  (shell,
                                                options->show_selection);
        gimp_display_shell_set_show_layer      (shell,
217
                                                options->show_layer_boundary);
218
219
220
221
222
223
224
        gimp_display_shell_set_show_guides     (shell,
                                                options->show_guides);
        gimp_display_shell_set_show_grid       (shell,
                                                options->show_grid);
        gimp_display_shell_set_padding         (shell,
                                                options->padding_mode,
                                                &options->padding_color);
225

226
227
228
229
        group = gimp_ui_manager_get_action_group (shell->menubar_manager,
                                                  "view");
        gimp_action_group_set_action_active (group, "view-fullscreen",
                                             fullscreen);
230
231
232

        if (shell->gdisp ==
            gimp_context_get_display (gimp_get_user_context (gimp)))
233
234
235
236
237
238
          {
            group = gimp_ui_manager_get_action_group (shell->popup_manager,
                                                      "view");
            gimp_action_group_set_action_active (group, "view-fullscreen",
                                                 fullscreen);
          }
239
240
241
      }
      break;

242
243
    default:
      break;
244
245
    }

246
247
  if (set_display)
    {
Sven Neumann's avatar
Sven Neumann committed
248
249
      Gimp *gimp = shell->gdisp->gimage->gimp;

250
      /*  Setting the context's display automatically sets the image, too  */
Sven Neumann's avatar
Sven Neumann committed
251
      gimp_context_set_display (gimp_get_user_context (gimp), shell->gdisp);
252
253
    }

254
255
256
  return FALSE;
}

257
258
259
260
void
gimp_display_shell_canvas_realize (GtkWidget        *canvas,
                                   GimpDisplayShell *shell)
{
261
262
263
264
  GimpDisplayConfig     *config;
  GimpDisplay           *gdisp;
  GimpCanvasPaddingMode  padding_mode;
  GimpRGB                padding_color;
265

266
267
  gdisp  = shell->gdisp;
  config = GIMP_DISPLAY_CONFIG (gdisp->gimage->gimp->config);
268

269
270
  gtk_widget_grab_focus (shell->canvas);

271
272
  gimp_display_shell_get_padding (shell, &padding_mode, &padding_color);
  gimp_display_shell_set_padding (shell, padding_mode, &padding_color);
Michael Natterer's avatar
Michael Natterer committed
273

274
  gimp_display_shell_title_update (shell);
275

276
277
278
279
  shell->disp_width  = canvas->allocation.width;
  shell->disp_height = canvas->allocation.height;

  /*  set up the scrollbar observers  */
280
  g_signal_connect (shell->hsbdata, "value_changed",
281
282
                    G_CALLBACK (gimp_display_shell_hscrollbar_update),
                    shell);
283
  g_signal_connect (shell->vsbdata, "value_changed",
284
285
286
                    G_CALLBACK (gimp_display_shell_vscrollbar_update),
                    shell);

287
  /*  set the initial cursor  */
288
289
290
291
  gimp_display_shell_set_cursor (shell,
                                 GDK_TOP_LEFT_ARROW,
                                 GIMP_TOOL_CURSOR_NONE,
                                 GIMP_CURSOR_MODIFIER_NONE);
292
293
294

  /*  allow shrinking  */
  gtk_widget_set_size_request (GTK_WIDGET (shell), 0, 0);
295
296

  gimp_display_shell_draw_vectors (shell);
297
298
}

299
300
301
302
void
gimp_display_shell_canvas_size_allocate (GtkWidget        *widget,
                                         GtkAllocation    *allocation,
                                         GimpDisplayShell *shell)
303
{
304
305
  /*  are we in destruction?  */
  if (! shell->gdisp || ! shell->gdisp->shell)
306
    return;
307

308
309
  if ((shell->disp_width  != allocation->width) ||
      (shell->disp_height != allocation->height))
Michael Natterer's avatar
Michael Natterer committed
310
    {
311
312
313
314
315
      if (shell->zoom_on_resize   &&
          shell->disp_width  > 64 &&
          shell->disp_height > 64 &&
          allocation->width  > 64 &&
          allocation->height > 64)
316
        {
317
          gdouble scale = shell->scale;
318
319
320
321
322
323
          gint    offset_x;
          gint    offset_y;

          /*  multiply the zoom_factor with the ratio of the new and
           *  old canvas diagonals
           */
324
325
          scale *= (sqrt (SQR (allocation->width) +
                          SQR (allocation->height)) /
326
327
328
329
330
331
332
333
334
335
336
                    sqrt (SQR (shell->disp_width) +
                          SQR (shell->disp_height)));

          offset_x = UNSCALEX (shell, shell->offset_x);
          offset_y = UNSCALEX (shell, shell->offset_y);

          shell->scale    = scale;
          shell->offset_x = SCALEX (shell, offset_x);
          shell->offset_y = SCALEY (shell, offset_y);
        }

337
338
      shell->disp_width  = allocation->width;
      shell->disp_height = allocation->height;
339

Michael Natterer's avatar
Michael Natterer committed
340
341
      gimp_display_shell_scroll_clamp_offsets (shell);
      gimp_display_shell_scale_setup (shell);
342
      gimp_display_shell_scaled (shell);
Michael Natterer's avatar
Michael Natterer committed
343
    }
344
345
}

Michael Natterer's avatar
Michael Natterer committed
346
347
348
349
gboolean
gimp_display_shell_canvas_expose (GtkWidget        *widget,
                                  GdkEventExpose   *eevent,
                                  GimpDisplayShell *shell)
350
{
351
  GdkRegion    *region = NULL;
352
353
354
  GdkRectangle *rects;
  gint          n_rects;
  gint          i;
355

356
357
358
359
  /*  are we in destruction?  */
  if (! shell->gdisp || ! shell->gdisp->shell)
    return TRUE;

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  /*  If the call to gimp_display_shell_pause() would cause a redraw,
   *  we need to make sure that no XOR drawing happens on areas that
   *  have already been cleared by the windowing system.
   */
  if (shell->paused_count == 0)
    {
      GdkRectangle  area;

      area.x      = 0;
      area.y      = 0;
      area.width  = shell->disp_width;
      area.height = shell->disp_height;

      region = gdk_region_rectangle (&area);

      gdk_region_subtract (region, eevent->region);

      gimp_canvas_set_clip_region (GIMP_CANVAS (shell->canvas),
                                   GIMP_CANVAS_STYLE_XOR, region);
      gimp_canvas_set_clip_region (GIMP_CANVAS (shell->canvas),
                                   GIMP_CANVAS_STYLE_XOR_DASHED, region);
    }

383
  gimp_display_shell_pause (shell);
384

385
386
387
388
389
390
391
392
393
  if (region)
    {
      gimp_canvas_set_clip_region (GIMP_CANVAS (shell->canvas),
                                   GIMP_CANVAS_STYLE_XOR, NULL);
      gimp_canvas_set_clip_region (GIMP_CANVAS (shell->canvas),
                                   GIMP_CANVAS_STYLE_XOR_DASHED, NULL);
      gdk_region_destroy (region);
    }

394
  gdk_region_get_rectangles (eevent->region, &rects, &n_rects);
Michael Natterer's avatar
Michael Natterer committed
395

396
397
398
399
400
401
402
403
404
  for (i = 0; i < n_rects; i++)
    gimp_display_shell_draw_area (shell,
                                  rects[i].x,
                                  rects[i].y,
                                  rects[i].width,
                                  rects[i].height);

  g_free (rects);

405
406
  /* draw the transform tool preview */
  gimp_display_shell_preview_transform (shell);
407

408
409
410
  /* draw the guides */
  gimp_display_shell_draw_guides (shell);

411
  /* draw the grid */
412
  gimp_display_shell_draw_grid (shell, &eevent->area);
413

414
  /* and the cursor (if we have a software cursor) */
415
  gimp_display_shell_draw_cursor (shell);
416
417
418
419

  /* restart (and recalculate) the selection boundaries */
  gimp_display_shell_selection_start (shell->select, TRUE);

420
  gimp_display_shell_resume (shell);
421

Michael Natterer's avatar
Michael Natterer committed
422
423
  return TRUE;
}
424

Michael Natterer's avatar
Michael Natterer committed
425
426
static void
gimp_display_shell_check_device_cursor (GimpDisplayShell *shell)
427
{
428
  GdkDevice *current_device;
429

430
  current_device = gimp_devices_get_current (shell->gdisp->gimage->gimp);
431

432
  shell->draw_cursor = ! current_device->has_cursor;
433
434
}

435
gboolean
Michael Natterer's avatar
Michael Natterer committed
436
437
438
gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
                                       GdkEvent         *event,
                                       GimpDisplayShell *shell)
Elliot Lee's avatar
Elliot Lee committed
439
{
440
441
442
443
444
445
446
447
448
449
450
  GimpDisplay         *gdisp;
  GimpImage           *gimage;
  Gimp                *gimp;
  GdkDisplay          *gdk_display;
  GimpTool            *active_tool;
  GimpCoords           display_coords;
  GimpCoords           image_coords;
  GdkModifierType      state;
  guint32              time;
  gboolean             return_val        = FALSE;
  gboolean             update_cursor     = FALSE;
451

452
  static GimpToolInfo *space_shaded_tool = NULL;
Michael Natterer's avatar
Michael Natterer committed
453

454
  if (! canvas->window)
455
    {
456
      g_warning ("%s: called unrealized", G_STRFUNC);
457
458
      return FALSE;
    }
scott's avatar
scott committed
459

460
461
462
463
  /*  are we in destruction?  */
  if (! shell->gdisp || ! shell->gdisp->shell)
    return TRUE;

464
465
466
467
  /*  set the active display before doing any other canvas event processing  */
  if (gimp_display_shell_events (canvas, event, shell))
    return TRUE;

Michael Natterer's avatar
Michael Natterer committed
468
  gdisp  = shell->gdisp;
469
  gimage = gdisp->gimage;
470
  gimp   = gimage->gimp;
471

472
473
  gdk_display = gtk_widget_get_display (canvas);

Michael Natterer's avatar
Michael Natterer committed
474
  /*  Find out what device the event occurred upon  */
475
  if (! gimp->busy && gimp_devices_check_change (gimp, event))
476
477
478
    {
      gimp_display_shell_check_device_cursor (shell);
    }
Michael Natterer's avatar
Michael Natterer committed
479

480
481
482
483
484
485
  gimp_display_shell_get_event_coords (shell, event,
                                       gimp_devices_get_current (gimp),
                                       &display_coords);
  gimp_display_shell_get_event_state (shell, event,
                                      gimp_devices_get_current (gimp),
                                      &state);
486
487
488
  time = gdk_event_get_time (event);

  /*  GimpCoords passed to tools are ALWAYS in image coordinates  */
489
490
491
  gimp_display_shell_untransform_coords (shell,
                                         &display_coords,
                                         &image_coords);
492

493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  active_tool = tool_manager_get_active (gimp);

  if (active_tool && gimp_tool_control_auto_snap_to (active_tool->control))
    {
      gint x, y, width, height;

      gimp_tool_control_snap_offsets (active_tool->control,
                                      &x, &y, &width, &height);

      if (gimp_display_shell_snap_coords (shell,
                                          &image_coords,
                                          &image_coords,
                                          x, y, width, height))
        {
          update_cursor = TRUE;
        }
    }
510

Elliot Lee's avatar
Elliot Lee committed
511
512
  switch (event->type)
    {
513
    case GDK_ENTER_NOTIFY:
514
      {
515
        GdkEventCrossing *cevent = (GdkEventCrossing *) event;
516
517
518

        if (cevent->mode != GDK_CROSSING_NORMAL)
          return TRUE;
519
520

        update_cursor = TRUE;
521
522
523
524

        tool_manager_oper_update_active (gimp,
                                         &image_coords, state,
                                         gdisp);
525
      }
526
527
      break;

528
    case GDK_LEAVE_NOTIFY:
529
      {
530
        GdkEventCrossing *cevent = (GdkEventCrossing *) event;
531
532
533
534
535

        if (cevent->mode != GDK_CROSSING_NORMAL)
          return TRUE;

        shell->proximity = FALSE;
536
        gimp_display_shell_clear_cursor (shell);
537
538
539
540

        tool_manager_oper_update_active (gimp,
                                         &image_coords, state,
                                         gdisp);
541
      }
542
543
544
      break;

    case GDK_PROXIMITY_IN:
545
546
547
      tool_manager_oper_update_active (gimp,
                                       &image_coords, state,
                                       gdisp);
548
549
550
551
      break;

    case GDK_PROXIMITY_OUT:
      shell->proximity = FALSE;
552
      gimp_display_shell_clear_cursor (shell);
553
554
555
556

      tool_manager_oper_update_active (gimp,
                                       &image_coords, state,
                                       gdisp);
557
558
      break;

Michael Natterer's avatar
Michael Natterer committed
559
560
    case GDK_FOCUS_CHANGE:
      {
561
        GdkEventFocus *fevent = (GdkEventFocus *) event;
Michael Natterer's avatar
Michael Natterer committed
562
563
564
565
566
567
568
569
570
571

        if (fevent->in)
          {
            GTK_WIDGET_SET_FLAGS (canvas, GTK_HAS_FOCUS);

            /*  press modifier keys when the canvas gets the focus
             *
             *  in "click to focus" mode, we did this on BUTTON_PRESS, so
             *  do it here only if button_press_before_focus is FALSE
             */
572
            if (! shell->button_press_before_focus)
Michael Natterer's avatar
Michael Natterer committed
573
              {
574
575
                tool_manager_focus_display_active (gimp, gdisp);
                tool_manager_modifier_state_active (gimp, state, gdisp);
Michael Natterer's avatar
Michael Natterer committed
576

577
                tool_manager_oper_update_active (gimp,
Michael Natterer's avatar
Michael Natterer committed
578
579
580
581
582
583
584
585
586
587
588
                                                 &image_coords, state,
                                                 gdisp);
              }
          }
        else
          {
            GTK_WIDGET_UNSET_FLAGS (canvas, GTK_HAS_FOCUS);

            /*  reset it here to be prepared for the next
             *  FOCUS_IN / BUTTON_PRESS confusion
             */
589
            shell->button_press_before_focus = FALSE;
Michael Natterer's avatar
Michael Natterer committed
590
591

            /*  release modifier keys when the canvas loses the focus  */
592
            tool_manager_focus_display_active (gimp, NULL);
Michael Natterer's avatar
Michael Natterer committed
593

594
595
596
            tool_manager_oper_update_active (gimp,
                                             &image_coords, 0,
                                             gdisp);
Michael Natterer's avatar
Michael Natterer committed
597
598
599
600
601
602
603
604
605
          }

        /*  stop the signal because otherwise gtk+ exposes the whole
         *  canvas to get the non-existant focus indicator drawn
         */
        return_val = TRUE;
      }
      break;

Elliot Lee's avatar
Elliot Lee committed
606
    case GDK_BUTTON_PRESS:
607
      {
608
        GdkEventButton *bevent = (GdkEventButton *) event;
609
        GdkEventMask    event_mask;
610

611
        if (! GTK_WIDGET_HAS_FOCUS (canvas))
Michael Natterer's avatar
Michael Natterer committed
612
          {
613
614
615
            /*  in "click to focus" mode, the BUTTON_PRESS arrives before
             *  FOCUS_IN, so we have to update the tool's modifier state here
             */
616
617
            tool_manager_focus_display_active (gimp, gdisp);
            tool_manager_modifier_state_active (gimp, state, gdisp);
Michael Natterer's avatar
Michael Natterer committed
618

619
620
621
            tool_manager_oper_update_active (gimp,
                                             &image_coords, state,
                                             gdisp);
Michael Natterer's avatar
Michael Natterer committed
622

623
624
625
626
627
628
629
630
631
632
633
634
635
636
            active_tool = tool_manager_get_active (gimp);

            if (active_tool)
              {
                if ((! gimp_image_is_empty (gimage) ||
                     gimp_tool_control_handles_empty_image (active_tool->control)) &&
                    (bevent->button == 1 ||
                     bevent->button == 2 ||
                     bevent->button == 3))
                  {
                    tool_manager_cursor_update_active (gimp,
                                                       &image_coords, state,
                                                       gdisp);
                  }
637
638
                else if (gimp_image_is_empty (gimage) &&
                         ! gimp_tool_control_handles_empty_image (active_tool->control))
639
640
                  {
                    gimp_display_shell_set_cursor (shell,
641
                                                   GIMP_CURSOR_BAD,
642
643
644
645
646
647
648
                                                   gimp_tool_control_get_tool_cursor (active_tool->control),
                                                   GIMP_CURSOR_MODIFIER_NONE);
                  }
              }
            else
              {
                gimp_display_shell_set_cursor (shell,
649
                                               GIMP_CURSOR_BAD,
650
651
652
                                               GIMP_TOOL_CURSOR_NONE,
                                               GIMP_CURSOR_MODIFIER_NONE);
              }
653

654
            shell->button_press_before_focus = TRUE;
655
656
657
658
659

            /*  we expect a FOCUS_IN event to follow, but can't rely
             *  on it, so force one
             */
            gdk_window_focus (canvas->window, time);
Michael Natterer's avatar
Michael Natterer committed
660
661
          }

662
        /*  ignore new mouse events  */
663
        if (gimp->busy)
664
665
          return TRUE;

666
        active_tool = tool_manager_get_active (gimp);
667
668
669
670
671
672

        switch (bevent->button)
          {
          case 1:
            state |= GDK_BUTTON1_MASK;

673
            event_mask = (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK);
674

675
            if (active_tool &&
676
                (! GIMP_DISPLAY_CONFIG (gimp->config)->perfect_mouse ||
677
678
                 (gimp_tool_control_motion_mode (active_tool->control) !=
                  GIMP_MOTION_MODE_EXACT)))
679
              {
680
681
682
683
                /*  don't request motion hins for XInput devices because
                 *  the wacom driver is known to report crappy hints
                 *  (#6901) --mitch
                 */
684
685
686
687
688
                if (gimp_devices_get_current (gimp) ==
                    gdk_display_get_core_pointer (gdk_display))
                  {
                    event_mask |= (GDK_POINTER_MOTION_HINT_MASK);
                  }
689
              }
690

691
692
693
            gdk_pointer_grab (canvas->window,
                              FALSE, event_mask, NULL, NULL, time);

694
695
            if (! shell->space_pressed && ! shell->space_release_pending)
              gdk_keyboard_grab (canvas->window, FALSE, time);
696

697
698
699
            if (active_tool &&
                (! gimp_image_is_empty (gimage) ||
                 gimp_tool_control_handles_empty_image (active_tool->control)))
700
              {
701
702
                gboolean initialized = TRUE;

703
704
705
706
                /*  initialize the current tool if it has no drawable
                 */
                if (! active_tool->drawable)
                  {
707
                    initialized = tool_manager_initialize_active (gimp, gdisp);
708
                  }
709
                else if ((active_tool->drawable !=
710
                          gimp_image_active_drawable (gimage)) &&
711
                         ! gimp_tool_control_preserve (active_tool->control))
712
713
714
                  {
                    /*  create a new one, deleting the current
                     */
715
                    gimp_context_tool_changed (gimp_get_user_context (gimp));
716

717
                    initialized = tool_manager_initialize_active (gimp, gdisp);
718
719
                  }

720
                if (initialized)
721
722
723
724
725
726
727
                  {
                    tool_manager_button_press_active (gimp,
                                                      &image_coords, time, state,
                                                      gdisp);

                    shell->last_motion_time = bevent->time;
                  }
728
729
730
731
732
733
              }
            break;

          case 2:
            state |= GDK_BUTTON2_MASK;

734
735
736
            shell->scrolling      = TRUE;
            shell->scroll_start_x = bevent->x + shell->offset_x;
            shell->scroll_start_y = bevent->y + shell->offset_y;
737
738
739

            gtk_grab_add (canvas);

740
            gimp_display_shell_set_override_cursor (shell, GDK_FLEUR);
741
742
743
744
            break;

          case 3:
            state |= GDK_BUTTON3_MASK;
745
746
            gimp_ui_manager_ui_popup (shell->popup_manager,
                                      "/dummy-menubar/image-popup",
747
                                      GTK_WIDGET (shell),
748
                                      NULL, NULL, NULL, NULL);
749
750
751
752
753
754
755
            return_val = TRUE;
            break;

          default:
            break;
          }
      }
Elliot Lee's avatar
Elliot Lee committed
756
757
758
      break;

    case GDK_BUTTON_RELEASE:
759
      {
760
        GdkEventButton *bevent = (GdkEventButton *) event;
761

762
	gimp_display_shell_autoscroll_stop (shell);
763

764
        if (gimp->busy)
765
766
          return TRUE;

767
768
        active_tool = tool_manager_get_active (gimp);

769
770
771
772
773
        switch (bevent->button)
          {
          case 1:
            state &= ~GDK_BUTTON1_MASK;

774
775
776
777
778
            if (! shell->space_pressed && ! shell->space_release_pending)
              gdk_display_keyboard_ungrab (gdk_display, time);

            gdk_display_pointer_ungrab (gdk_display, time);

779
780
            gtk_grab_add (GTK_WIDGET (canvas));

781
782
783
            if (active_tool &&
                (! gimp_image_is_empty (gimage) ||
                 gimp_tool_control_handles_empty_image (active_tool->control)))
784
              {
785
                if (gimp_tool_control_is_active (active_tool->control))
786
                  {
787
                    tool_manager_button_release_active (gimp,
Sven Neumann's avatar
Sven Neumann committed
788
789
                                                        &image_coords,
                                                        time, state,
790
791
792
                                                        gdisp);
                  }
              }
793

794
795
796
797
798
799
800
801
802
803
804
805
            /*  update the tool's modifier state because it didn't get
             *  key events while BUTTON1 was down
             */
            tool_manager_focus_display_active (gimp, gdisp);
            tool_manager_modifier_state_active (gimp, state, gdisp);

            tool_manager_oper_update_active (gimp,
                                             &image_coords, state,
                                             gdisp);

            gtk_grab_remove (GTK_WIDGET (canvas));

806
807
            if (shell->space_release_pending)
              {
808
#ifdef DEBUG_MOVE_PUSH
809
                g_printerr ("%s: popping move tool\n", G_STRFUNC);
810
#endif
811

812
                gimp_context_set_tool (gimp_get_user_context (gimp),
813
814
815
                                       space_shaded_tool);
                space_shaded_tool = NULL;

816
817
                tool_manager_focus_display_active (gimp, gdisp);
                tool_manager_modifier_state_active (gimp, state, gdisp);
818

819
                tool_manager_oper_update_active (gimp,
820
821
822
823
                                                 &image_coords, state,
                                                 gdisp);

                shell->space_release_pending = FALSE;
824

825
                gdk_display_keyboard_ungrab (gdk_display, time);
826
              }
827
828
829
830
831
            break;

          case 2:
            state &= ~GDK_BUTTON2_MASK;

832
833
834
            shell->scrolling      = FALSE;
            shell->scroll_start_x = 0;
            shell->scroll_start_y = 0;
835
836
837

            gtk_grab_remove (canvas);

838
            gimp_display_shell_unset_override_cursor (shell);
839
840
841
842
843
844
845
846
847
848
            break;

          case 3:
            state &= ~GDK_BUTTON3_MASK;
            break;

          default:
            break;
          }
      }
Michael Natterer's avatar
Michael Natterer committed
849
      break;
850

Michael Natterer's avatar
Michael Natterer committed
851
    case GDK_SCROLL:
852
      {
853
        GdkEventScroll     *sevent = (GdkEventScroll *) event;
854
        GdkScrollDirection  direction;
855
856
857
858
859
        GimpController     *wheel;

        wheel = gimp_controllers_get_wheel (gimp);

        if (wheel &&
860
861
            gimp_controller_wheel_scroll (GIMP_CONTROLLER_WHEEL (wheel),
                                          sevent))
862
          return TRUE;
863

864
865
        direction = sevent->direction;

866
        if (state & GDK_CONTROL_MASK)
867
          {
868
869
870
            switch (direction)
              {
              case GDK_SCROLL_UP:
871
                gimp_display_shell_scale (shell, GIMP_ZOOM_IN, 0.0);
872
873
874
                break;

              case GDK_SCROLL_DOWN:
875
                gimp_display_shell_scale (shell, GIMP_ZOOM_OUT, 0.0);
876
877
878
879
880
                break;

              default:
                break;
              }
881
882
883
          }
        else
          {
884
            GtkAdjustment *adj = NULL;
885
886
            gdouble        value;

887
            if (state & GDK_SHIFT_MASK)
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
              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;
              }
908

909
910
            value = adj->value + ((direction == GDK_SCROLL_UP ||
                                   direction == GDK_SCROLL_LEFT) ?
911
912
913
914
915
916
917
                                  -adj->page_increment / 2 :
                                  adj->page_increment / 2);
            value = CLAMP (value, adj->lower, adj->upper - adj->page_size);

            gtk_adjustment_set_value (adj, value);
          }

918
        /*  GimpCoords passed to tools are ALWAYS in image coordinates  */
919
920
921
922
        gimp_display_shell_untransform_coords (shell,
                                               &display_coords,
                                               &image_coords);

923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
        active_tool = tool_manager_get_active (gimp);

        if (active_tool &&
            gimp_tool_control_auto_snap_to (active_tool->control))
          {
            gint x, y, width, height;

            gimp_tool_control_snap_offsets (active_tool->control,
                                            &x, &y, &width, &height);

            if (gimp_display_shell_snap_coords (shell,
                                                &image_coords,
                                                &image_coords,
                                                x, y, width, height))
              {
                update_cursor = TRUE;
              }
          }

942
        tool_manager_oper_update_active (gimp,
943
944
                                         &image_coords, state,
                                         gdisp);
945

946
947
        return_val = TRUE;
      }
Elliot Lee's avatar
Elliot Lee committed
948
949
950
      break;

    case GDK_MOTION_NOTIFY:
951
      {
952
        GdkEventMotion *mevent            = (GdkEventMotion *) event;
953
        GdkEvent       *compressed_motion = NULL;
954

955
        if (gimp->busy)
956
957
          return TRUE;

958
        active_tool = tool_manager_get_active (gimp);
959

960
961
962
        if (active_tool &&
            gimp_tool_control_motion_mode (active_tool->control) ==
            GIMP_MOTION_MODE_COMPRESS)
963
964
965
          {
            compressed_motion = gimp_display_shell_compress_motion (shell);
          }
966

967
968
        if (compressed_motion)
          {
Sven Neumann's avatar
Sven Neumann committed
969
            GdkDevice *device = gimp_devices_get_current (gimp);
970

971
            gimp_display_shell_get_event_coords (shell, compressed_motion,
Sven Neumann's avatar
Sven Neumann committed
972
                                                 device, &display_coords);
973
            gimp_display_shell_get_event_state (shell, compressed_motion,
Sven Neumann's avatar
Sven Neumann committed
974
                                                device, &state);
975
976
977
978
979
980
            time = gdk_event_get_time (event);

            /*  GimpCoords passed to tools are ALWAYS in image coordinates  */
            gimp_display_shell_untransform_coords (shell,
                                                   &display_coords,
                                                   &image_coords);
981
982
983
984
985
986
987
988
989
990
991
992
993
994

            if (active_tool &&
                gimp_tool_control_auto_snap_to (active_tool->control))
              {
                gint x, y, width, height;

                gimp_tool_control_snap_offsets (active_tool->control,
                                                &x, &y, &width, &height);

                gimp_display_shell_snap_coords (shell,
                                                &image_coords,
                                                &image_coords,
                                                x, y, width, height);
              }
995
996
          }

997
        /* Ask for the pointer position, but ignore it except for cursor
998
         * handling, so motion events sync with the button press/release events
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
         */
        if (mevent->is_hint)
          {
            gimp_display_shell_get_device_coords (shell,
                                                  mevent->device,
                                                  &display_coords);
          }

        update_cursor = TRUE;

        if (! shell->proximity)
          {
            shell->proximity = TRUE;
            gimp_display_shell_check_device_cursor (shell);
          }

1015
        if (state & GDK_BUTTON1_MASK)
1016
          {
1017
1018
            if (active_tool                                        &&
                gimp_tool_control_is_active (active_tool->control) &&
1019
                (! gimp_image_is_empty (gimage) ||
1020
                 gimp_tool_control_handles_empty_image (active_tool->control)))
1021
              {
1022
1023
1024
1025
                GdkTimeCoord **history_events;
                gint           n_history_events;

               /*  if the first mouse button is down, check for automatic
1026
1027
1028
1029
1030
1031
                 *  scrolling...
                 */
                if ((mevent->x < 0                 ||
                     mevent->y < 0                 ||
                     mevent->x > shell->disp_width ||
                     mevent->y > shell->disp_height) &&
1032
                    ! gimp_tool_control_scroll_lock (active_tool->control))
1033
                  {
1034
                    gimp_display_shell_autoscroll_start (shell, state, mevent);
1035
1036
                  }

1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
                if (gimp_tool_control_motion_mode (active_tool->control) ==
                    GIMP_MOTION_MODE_EXACT &&
                    gdk_device_get_history (mevent->device, mevent->window,
                                            shell->last_motion_time,
                                            mevent->time,
                                            &history_events,
                                            &n_history_events))
                  {
                    gint i;

                    for (i = 0; i < n_history_events; i++)
                      {
                        gimp_display_shell_get_time_coords (shell,
                                                            mevent->device,
                                                            history_events[i],
                                                            &display_coords);

                        /*  GimpCoords passed to tools are ALWAYS in
                         *  image coordinates
                         */
                        gimp_display_shell_untransform_coords (shell,
                                                               &display_coords,
                                                               &image_coords);

                        if (gimp_tool_control_auto_snap_to (active_tool->control))
                          {
                            gint x, y, width, height;

                            gimp_tool_control_snap_offsets (active_tool->control,
                                                            &x, &y, &width, &height);

                            gimp_display_shell_snap_coords (shell,
                                                            &image_coords,
                                                            &image_coords,
                                                            x, y, width, height);
                          }

                        tool_manager_motion_active (gimp,
                                                    &image_coords,