tool_manager.c 15.4 KB
Newer Older
Nate Summers's avatar
Nate Summers committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <gtk/gtk.h>

23 24
#include "libgimpwidgets/gimpwidgets.h"

25
#include "tools-types.h"
Nate Summers's avatar
Nate Summers committed
26

27
#include "core/gimp.h"
28 29
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
30
#include "core/gimplist.h"
31
#include "core/gimpimage.h"
32
#include "core/gimptoolinfo.h"
33

34 35
#include "config/gimpcoreconfig.h"

36 37
#include "display/gimpdisplay.h"

38
#include "gimptool.h"
39 40
#include "gimptoolcontrol.h"
#include "tool_manager.h"
41

Nate Summers's avatar
Nate Summers committed
42

43
typedef struct _GimpToolManager GimpToolManager;
Nate Summers's avatar
Nate Summers committed
44

45 46
struct _GimpToolManager
{
47 48
  GimpTool *active_tool;
  GSList   *tool_stack;
Nate Summers's avatar
Nate Summers committed
49

50 51
  GQuark    image_clean_handler_id;
  GQuark    image_dirty_handler_id;
52
};
53 54


55
/*  local function prototypes  */
Nate Summers's avatar
Nate Summers committed
56

57 58 59 60 61 62
static GimpToolManager * tool_manager_get    (Gimp            *gimp);
static void              tool_manager_set    (Gimp            *gimp,
                                              GimpToolManager *tool_manager);
static void   tool_manager_tool_changed      (GimpContext     *user_context,
                                              GimpToolInfo    *tool_info,
                                              gpointer         data);
63
static void   tool_manager_image_clean_dirty (GimpImage       *image,
64 65
                                              GimpDirtyMask    dirty_mask,
                                              GimpToolManager *tool_manager);
66 67 68 69 70 71


/*  public functions  */

void
tool_manager_init (Gimp *gimp)
Nate Summers's avatar
Nate Summers committed
72
{
73 74 75
  GimpToolManager *tool_manager;
  GimpContext     *user_context;

76 77
  g_return_if_fail (GIMP_IS_GIMP (gimp));

78 79
  tool_manager = g_new0 (GimpToolManager, 1);

80 81 82 83
  tool_manager->active_tool            = NULL;
  tool_manager->tool_stack             = NULL;
  tool_manager->image_clean_handler_id = 0;
  tool_manager->image_dirty_handler_id = 0;
84 85

  tool_manager_set (gimp, tool_manager);
86

87 88
  tool_manager->image_clean_handler_id =
    gimp_container_add_handler (gimp->images, "clean",
89 90
                                G_CALLBACK (tool_manager_image_clean_dirty),
                                tool_manager);
91

92 93
  tool_manager->image_dirty_handler_id =
    gimp_container_add_handler (gimp->images, "dirty",
94 95
                                G_CALLBACK (tool_manager_image_clean_dirty),
                                tool_manager);
96

97 98
  user_context = gimp_get_user_context (gimp);

99
  g_signal_connect (user_context, "tool-changed",
100 101
                    G_CALLBACK (tool_manager_tool_changed),
                    tool_manager);
102 103
}

104 105 106 107 108 109 110 111 112 113 114
void
tool_manager_exit (Gimp *gimp)
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);
  tool_manager_set (gimp, NULL);

  gimp_container_remove_handler (gimp->images,
115
                                 tool_manager->image_clean_handler_id);
116
  gimp_container_remove_handler (gimp->images,
117
                                 tool_manager->image_dirty_handler_id);
118 119 120 121 122 123 124

  if (tool_manager->active_tool)
    g_object_unref (tool_manager->active_tool);

  g_free (tool_manager);
}

125 126 127 128 129
GimpTool *
tool_manager_get_active (Gimp *gimp)
{
  GimpToolManager *tool_manager;

130 131
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);

132 133 134 135 136
  tool_manager = tool_manager_get (gimp);

  return tool_manager->active_tool;
}

Nate Summers's avatar
Nate Summers committed
137
void
138
tool_manager_select_tool (Gimp     *gimp,
139
                          GimpTool *tool)
Nate Summers's avatar
Nate Summers committed
140
{
141 142
  GimpToolManager *tool_manager;

Michael Natterer's avatar
Michael Natterer committed
143
  g_return_if_fail (GIMP_IS_GIMP (gimp));
144 145
  g_return_if_fail (GIMP_IS_TOOL (tool));

146 147 148
  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
149
    {
150
      GimpTool    *active_tool = tool_manager->active_tool;
151
      GimpDisplay *display;
152

153 154
      /*  NULL image returns any display (if there is any)  */
      display = gimp_tool_has_image (active_tool, NULL);
155

156
      tool_manager_control_active (gimp, GIMP_TOOL_ACTION_HALT, display);
157 158
      tool_manager_focus_display_active (gimp, NULL);

159
      g_object_unref (tool_manager->active_tool);
160
    }
Nate Summers's avatar
Nate Summers committed
161

162
  tool_manager->active_tool = g_object_ref (tool);
Nate Summers's avatar
Nate Summers committed
163 164
}

165
void
166
tool_manager_push_tool (Gimp     *gimp,
167
                        GimpTool *tool)
168
{
169 170
  GimpToolManager *tool_manager;

Michael Natterer's avatar
Michael Natterer committed
171
  g_return_if_fail (GIMP_IS_GIMP (gimp));
172 173
  g_return_if_fail (GIMP_IS_TOOL (tool));

174 175 176
  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
177
    {
178
      tool_manager->tool_stack = g_slist_prepend (tool_manager->tool_stack,
179
                                                  tool_manager->active_tool);
180

181
      g_object_ref (tool_manager->tool_stack->data);
182 183
    }

184
  tool_manager_select_tool (gimp, tool);
185 186 187
}

void
188
tool_manager_pop_tool (Gimp *gimp)
189
{
190 191
  GimpToolManager *tool_manager;

192 193
  g_return_if_fail (GIMP_IS_GIMP (gimp));

194 195 196
  tool_manager = tool_manager_get (gimp);

  if (tool_manager->tool_stack)
197
    {
198
      GimpTool *tool = tool_manager->tool_stack->data;
199

200
      tool_manager->tool_stack = g_slist_remove (tool_manager->tool_stack,
201 202 203 204 205
                                                 tool);

      tool_manager_select_tool (gimp, tool);

      g_object_unref (tool);
206 207 208
    }
}

209
gboolean
210
tool_manager_initialize_active (Gimp        *gimp,
211
                                GimpDisplay *display)
212
{
213 214
  GimpToolManager *tool_manager;

215
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
216
  g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
217

218
  tool_manager = tool_manager_get (gimp);
219

220
  if (tool_manager->active_tool)
221
    {
222
      GimpTool *tool = tool_manager->active_tool;
223

224
      if (gimp_tool_initialize (tool, display))
225
        {
226
          tool->drawable = gimp_image_active_drawable (display->image);
227

228 229
          return TRUE;
        }
230
    }
231 232

  return FALSE;
233 234
}

Nate Summers's avatar
Nate Summers committed
235
void
236
tool_manager_control_active (Gimp           *gimp,
237 238
                             GimpToolAction  action,
                             GimpDisplay    *display)
Nate Summers's avatar
Nate Summers committed
239
{
240 241
  GimpToolManager *tool_manager;

242 243
  g_return_if_fail (GIMP_IS_GIMP (gimp));

244 245
  tool_manager = tool_manager_get (gimp);

246
  if (tool_manager->active_tool)
247
    {
248 249
      GimpTool *tool = tool_manager->active_tool;

250
      if (display && gimp_tool_has_display (tool, display))
251 252 253
        {
          gimp_tool_control (tool, action, display);
        }
254
      else if (action == GIMP_TOOL_ACTION_HALT)
255 256 257 258
        {
          if (gimp_tool_control_is_active (tool->control))
            gimp_tool_control_halt (tool->control);
        }
259
    }
Nate Summers's avatar
Nate Summers committed
260 261
}

262 263 264 265 266
void
tool_manager_button_press_active (Gimp            *gimp,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
267
                                  GimpDisplay     *display)
268 269 270 271 272 273 274 275 276 277 278
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_button_press (tool_manager->active_tool,
                              coords, time, state,
279
                              display);
280 281 282 283 284 285 286 287
    }
}

void
tool_manager_button_release_active (Gimp            *gimp,
                                    GimpCoords      *coords,
                                    guint32          time,
                                    GdkModifierType  state,
288
                                    GimpDisplay     *display)
289 290 291 292 293 294 295 296 297 298 299
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_button_release (tool_manager->active_tool,
                                coords, time, state,
300
                                display);
301 302 303 304 305 306 307 308
    }
}

void
tool_manager_motion_active (Gimp            *gimp,
                            GimpCoords      *coords,
                            guint32          time,
                            GdkModifierType  state,
309
                            GimpDisplay     *display)
310 311 312 313 314 315 316 317 318 319 320
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_motion (tool_manager->active_tool,
                        coords, time, state,
321
                        display);
322 323 324
    }
}

325
gboolean
326
tool_manager_key_press_active (Gimp        *gimp,
327
                               GdkEventKey *kevent,
328
                               GimpDisplay *display)
329 330 331
{
  GimpToolManager *tool_manager;

332
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
333 334 335 336 337

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
338 339
      return gimp_tool_key_press (tool_manager->active_tool,
                                  kevent,
340
                                  display);
341
    }
342 343

  return FALSE;
344 345 346
}

void
347
tool_manager_focus_display_active (Gimp        *gimp,
348
                                   GimpDisplay *display)
349 350 351 352 353 354 355 356 357
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
358
      gimp_tool_set_focus_display (tool_manager->active_tool,
359
                                   display);
360 361 362 363 364 365
    }
}

void
tool_manager_modifier_state_active (Gimp            *gimp,
                                    GdkModifierType  state,
366
                                    GimpDisplay     *display)
367 368 369 370 371 372 373 374 375 376 377
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_set_modifier_state (tool_manager->active_tool,
                                    state,
378
                                    display);
379 380 381 382 383 384 385
    }
}

void
tool_manager_oper_update_active (Gimp            *gimp,
                                 GimpCoords      *coords,
                                 GdkModifierType  state,
386
                                 gboolean         proximity,
387
                                 GimpDisplay     *display)
388 389 390 391 392 393 394 395 396 397
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_oper_update (tool_manager->active_tool,
398
                             coords, state, proximity,
399
                             display);
400 401 402 403 404 405 406
    }
}

void
tool_manager_cursor_update_active (Gimp            *gimp,
                                   GimpCoords      *coords,
                                   GdkModifierType  state,
407
                                   GimpDisplay     *display)
408 409 410 411 412 413 414 415 416 417 418
{
  GimpToolManager *tool_manager;

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  tool_manager = tool_manager_get (gimp);

  if (tool_manager->active_tool)
    {
      gimp_tool_cursor_update (tool_manager->active_tool,
                               coords, state,
419
                               display);
420 421 422
    }
}

423 424 425

/*  private functions  */

426 427
static GQuark tool_manager_quark = 0;

428 429 430
static GimpToolManager *
tool_manager_get (Gimp *gimp)
{
431 432 433 434
  if (! tool_manager_quark)
    tool_manager_quark = g_quark_from_static_string ("gimp-tool-manager");

  return g_object_get_qdata (G_OBJECT (gimp), tool_manager_quark);
435
}
436

437 438
static void
tool_manager_set (Gimp            *gimp,
439
                  GimpToolManager *tool_manager)
440
{
441 442 443 444
  if (! tool_manager_quark)
    tool_manager_quark = g_quark_from_static_string ("gimp-tool-manager");

  g_object_set_qdata (G_OBJECT (gimp), tool_manager_quark, tool_manager);
445 446 447 448
}

static void
tool_manager_tool_changed (GimpContext  *user_context,
449 450
                           GimpToolInfo *tool_info,
                           gpointer      data)
451
{
Sven Neumann's avatar
Sven Neumann committed
452 453
  GimpToolManager *tool_manager = data;
  GimpTool        *new_tool     = NULL;
454 455 456 457 458

  if (! tool_info)
    return;

  /* FIXME: gimp_busy HACK */
459
  if (user_context->gimp->busy)
460
    {
461
      /*  there may be contexts waiting for the user_context's "tool-changed"
462 463
       *  signal, so stop emitting it.
       */
464
      g_signal_stop_emission_by_name (user_context, "tool-changed");
465

466
      if (G_TYPE_FROM_INSTANCE (tool_manager->active_tool) !=
467 468 469 470 471 472 473 474
          tool_info->tool_type)
        {
          g_signal_handlers_block_by_func (user_context,
                                           tool_manager_tool_changed,
                                           data);

          /*  explicitly set the current tool  */
          gimp_context_set_tool (user_context,
Michael Natterer's avatar
Michael Natterer committed
475
                                 tool_manager->active_tool->tool_info);
476

477 478 479 480
          g_signal_handlers_unblock_by_func (user_context,
                                             tool_manager_tool_changed,
                                             data);
        }
481 482 483 484

      return;
    }

Michael Natterer's avatar
Michael Natterer committed
485
  if (g_type_is_a (tool_info->tool_type, GIMP_TYPE_TOOL))
486
    {
487 488 489
      new_tool = g_object_new (tool_info->tool_type,
                               "tool-info", tool_info,
                               NULL);
490 491 492
    }
  else
    {
493
      g_warning ("%s: tool_info->tool_type is no GimpTool subclass",
494
                 G_STRFUNC);
495 496 497
      return;
    }

498
  /*  disconnect the old tool's context  */
499 500
  if (tool_manager->active_tool            &&
      tool_manager->active_tool->tool_info &&
501
      tool_manager->active_tool->tool_info->context_props)
502
    {
Sven Neumann's avatar
Sven Neumann committed
503
      GimpToolInfo *old_tool_info = tool_manager->active_tool->tool_info;
504

505 506
      gimp_context_set_parent (GIMP_CONTEXT (old_tool_info->tool_options),
                               NULL);
507
    }
508

509
  /*  connect the new tool's context  */
510
  if (tool_info->context_props)
511
    {
512 513 514
      GimpCoreConfig      *config       = user_context->gimp->config;
      GimpContextPropMask  global_props = 0;

515 516 517 518
      /*  FG and BG are always shared between all tools  */
      global_props |= GIMP_CONTEXT_FOREGROUND_MASK;
      global_props |= GIMP_CONTEXT_BACKGROUND_MASK;

519 520 521 522 523 524 525 526 527 528 529
      if (config->global_brush)
        global_props |= GIMP_CONTEXT_BRUSH_MASK;
      if (config->global_pattern)
        global_props |= GIMP_CONTEXT_PATTERN_MASK;
      if (config->global_palette)
        global_props |= GIMP_CONTEXT_PALETTE_MASK;
      if (config->global_gradient)
        global_props |= GIMP_CONTEXT_GRADIENT_MASK;
      if (config->global_font)
        global_props |= GIMP_CONTEXT_FONT_MASK;

530 531
      gimp_context_copy_properties (GIMP_CONTEXT (tool_info->tool_options),
                                    user_context,
532
                                    tool_info->context_props & ~global_props);
533 534
      gimp_context_set_parent (GIMP_CONTEXT (tool_info->tool_options),
                               user_context);
535 536
    }

537
  tool_manager_select_tool (user_context->gimp, new_tool);
538

539
  g_object_unref (new_tool);
540
}
541 542

static void
543
tool_manager_image_clean_dirty (GimpImage       *image,
544 545
                                GimpDirtyMask    dirty_mask,
                                GimpToolManager *tool_manager)
546
{
547
  GimpTool *tool = tool_manager->active_tool;
548

549 550 551
  if (tool &&
      ! gimp_tool_control_get_preserve (tool->control) &&
      (gimp_tool_control_get_dirty_mask (tool->control) & dirty_mask))
552
    {
553
      GimpDisplay *display = gimp_tool_has_image (tool, image);
554

555
      if (display)
556 557
        tool_manager_control_active (image->gimp, GIMP_TOOL_ACTION_HALT,
                                     display);
558 559
    }
}