gimpitemfactory.c 28.2 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
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

21
#include "string.h"
22

Sven Neumann's avatar
Sven Neumann committed
23
#include <gtk/gtk.h>
24
#include <gdk/gdkkeysyms.h>
25

26
#include "libgimpbase/gimpbase.h"
27 28
#include "libgimpwidgets/gimpwidgets.h"

29 30
#include "widgets-types.h"

31 32
#include "config/gimpguiconfig.h"

33 34
#include "core/gimp.h"

35
#include "gimpitemfactory.h"
36
#include "gimpwidgets-utils.h"
37

38
#include "gimphelp.h"
39

40
#include "gimp-intl.h"
41 42


43 44 45 46
#define COLOR_BOX_WIDTH  16
#define COLOR_BOX_HEIGHT 16


47 48
/*  local function prototypes  */

49 50 51
static void     gimp_item_factory_class_init      (GimpItemFactoryClass *klass);
static void     gimp_item_factory_init            (GimpItemFactory      *factory);

52
static void     gimp_item_factory_destroy         (GtkObject            *object);
53 54

static void     gimp_item_factory_create_branches (GimpItemFactory      *factory,
55 56
                                                   GimpItemFactoryEntry *entry,
                                                   const gchar          *textdomain);
57 58 59 60 61 62 63
static void     gimp_item_factory_item_realize    (GtkWidget            *widget,
                                                   gpointer              data);
static gboolean gimp_item_factory_item_key_press  (GtkWidget            *widget,
                                                   GdkEventKey          *kevent,
                                                   gpointer              data);
static gchar *  gimp_item_factory_translate_func  (const gchar          *path,
                                                   gpointer              data);
64

65

66
static GtkItemFactoryClass *parent_class = NULL;
67

68

69 70 71 72
GType
gimp_item_factory_get_type (void)
{
  static GType factory_type = 0;
73

74
  if (! factory_type)
75
    {
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
      static const GTypeInfo factory_info =
      {
        sizeof (GimpItemFactoryClass),
        NULL,           /* base_init */
        NULL,           /* base_finalize */
        (GClassInitFunc) gimp_item_factory_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GimpItemFactory),
        0,              /* n_preallocs */
        (GInstanceInitFunc) gimp_item_factory_init,
      };

      factory_type = g_type_register_static (GTK_TYPE_ITEM_FACTORY,
					     "GimpItemFactory",
					     &factory_info, 0);
92
    }
93

94
  return factory_type;
95
}
96

97 98
static void
gimp_item_factory_class_init (GimpItemFactoryClass *klass)
99
{
100
  GtkObjectClass *object_class;
101

102
  object_class = GTK_OBJECT_CLASS (klass);
103

104
  parent_class = g_type_class_peek_parent (klass);
105

106
  object_class->destroy = gimp_item_factory_destroy;
107

108 109
  klass->factories = g_hash_table_new_full (g_str_hash, g_str_equal,
                                            g_free, NULL);
Elliot Lee's avatar
Elliot Lee committed
110 111
}

112 113
static void
gimp_item_factory_init (GimpItemFactory *factory)
Elliot Lee's avatar
Elliot Lee committed
114
{
115 116 117
  factory->gimp            = NULL;
  factory->update_func     = NULL;
  factory->update_on_popup = FALSE;
118 119
}

120
static void
121
gimp_item_factory_destroy (GtkObject *object)
122
{
123
  GimpItemFactory *factory;
124
  gchar           *factory_path;
Elliot Lee's avatar
Elliot Lee committed
125

126
  factory = GIMP_ITEM_FACTORY (object);
127

128 129 130
  factory_path = GTK_ITEM_FACTORY (object)->path;

  if (factory_path)
131
    {
132 133 134 135 136 137
      GimpItemFactoryClass *factory_class;
      GList                *list;

      factory_class = GIMP_ITEM_FACTORY_GET_CLASS (factory);

      list = g_hash_table_lookup (factory_class->factories, factory_path);
138

139 140 141 142 143 144 145 146 147 148 149
      if (list)
        {
          list = g_list_remove (list, factory);

          if (list)
            g_hash_table_replace (factory_class->factories,
                                  g_strdup (factory_path),
                                  list);
          else
            g_hash_table_remove (factory_class->factories, factory_path);
        }
150
    }
151

152
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
153 154 155
}


156 157 158
/*  public functions  */

GimpItemFactory *
159 160
gimp_item_factory_new (Gimp                      *gimp,
                       GType                      container_type,
161
                       const gchar               *factory_path,
162
                       const gchar               *help_path,
163
                       GimpItemFactoryUpdateFunc  update_func,
164
                       gboolean                   update_on_popup,
165 166 167 168
                       guint                      n_entries,
                       GimpItemFactoryEntry      *entries,
                       gpointer                   callback_data,
                       gboolean                   create_tearoff)
169
{
170 171
  GimpItemFactoryClass *factory_class;
  GimpItemFactory      *factory;
172
  GList                *list;
173

174
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
175
  g_return_val_if_fail (factory_path != NULL, NULL);
176 177 178
  g_return_val_if_fail (help_path != NULL, NULL);
  g_return_val_if_fail (factory_path[0] == '<', NULL);
  g_return_val_if_fail (factory_path[strlen (factory_path) - 1] == '>', NULL);
179

180 181 182 183 184 185
  factory_class = g_type_class_ref (GIMP_TYPE_ITEM_FACTORY);

  factory = g_object_new (GIMP_TYPE_ITEM_FACTORY, NULL);

  gtk_item_factory_construct (GTK_ITEM_FACTORY (factory),
                              container_type,
186
                              factory_path,
187 188 189
                              NULL);

  gtk_item_factory_set_translate_func (GTK_ITEM_FACTORY (factory),
190
				       gimp_item_factory_translate_func,
191
				       factory,
192 193
				       NULL);

194 195 196
  factory->gimp            = gimp;
  factory->update_func     = update_func;
  factory->update_on_popup = update_on_popup;
197 198

  list = g_hash_table_lookup (factory_class->factories, factory_path);
199

200
  list = g_list_append (list, factory);
201

202 203 204
  g_hash_table_replace (factory_class->factories,
                        g_strdup (factory_path),
                        list);
205 206

  /*  this will go away  <mitch>  */
207 208 209
  g_object_set_data_full (G_OBJECT (factory), "help_path",
                          g_strdup (help_path),
                          (GDestroyNotify) g_free);
210 211 212 213 214 215 216 217

  gimp_item_factory_create_items (factory,
                                  n_entries,
                                  entries,
                                  callback_data,
                                  2,
                                  create_tearoff,
                                  TRUE);
218

219 220
  g_type_class_unref (factory_class);

221 222 223
  return factory;
}

224 225
GimpItemFactory *
gimp_item_factory_from_path (const gchar *path)
226 227 228 229 230 231 232 233 234 235 236 237 238
{
  GList *list;

  list = gimp_item_factories_from_path (path);

  if (list)
    return list->data;

  return NULL;
}

GList *
gimp_item_factories_from_path (const gchar *path)
239
{
240
  GimpItemFactoryClass *factory_class;
241
  GList                *list;
242 243
  gchar                *base_path;
  gchar                *p;
244

245
  g_return_val_if_fail (path != NULL, NULL);
246

247
  base_path = g_strdup (path);
248

249
  p = strchr (base_path, '>');
250

251 252
  if (p)
    p[1] = '\0';
253

254 255
  factory_class = g_type_class_ref (GIMP_TYPE_ITEM_FACTORY);

256
  list = g_hash_table_lookup (factory_class->factories, base_path);
257 258 259 260 261

  g_type_class_unref (factory_class);

  g_free (base_path);

262
  return list;
263 264
}

265
void
266
gimp_item_factory_create_item (GimpItemFactory       *item_factory,
267
                               GimpItemFactoryEntry  *entry,
268
                               const gchar           *textdomain,
269 270 271 272 273 274
                               gpointer               callback_data,
                               guint                  callback_type,
                               gboolean               create_tearoff,
                               gboolean               static_entry)
{
  GtkWidget *menu_item;
275
  gboolean   tearoffs;
276

277
  g_return_if_fail (GIMP_IS_ITEM_FACTORY (item_factory));
278 279
  g_return_if_fail (entry != NULL);

280 281
  tearoffs = GIMP_GUI_CONFIG (item_factory->gimp->config)->tearoff_menus;

282
  if (! (strstr (entry->entry.path, "tearoff")))
283
    {
284
      if (tearoffs && create_tearoff)
285
	{
286
	  gimp_item_factory_create_branches (item_factory, entry, textdomain);
287
	}
288
    }
289
  else if (! tearoffs || ! create_tearoff)
290
    {
291
      return;
292
    }
293

294
  if (entry->quark_string)
295
    {
296 297 298 299 300 301 302 303
      GQuark quark;

      if (static_entry)
	quark = g_quark_from_static_string (entry->quark_string);
      else
	quark = g_quark_from_string (entry->quark_string);

      entry->entry.callback_action = (guint) quark;
304 305
    }

306 307 308 309
  if (textdomain)
    g_object_set_data (G_OBJECT (item_factory), "textdomain",
                       (gpointer) textdomain);

310
  gtk_item_factory_create_item (GTK_ITEM_FACTORY (item_factory),
311 312 313 314
				(GtkItemFactoryEntry *) entry,
				callback_data,
				callback_type);

315 316 317
  if (textdomain)
    g_object_set_data (G_OBJECT (item_factory), "textdomain", NULL);

318
  menu_item = gtk_item_factory_get_item (GTK_ITEM_FACTORY (item_factory),
319 320 321
					 ((GtkItemFactoryEntry *) entry)->path);

  if (menu_item)
322
    {
323
      g_signal_connect_after (menu_item, "realize",
324 325 326
			      G_CALLBACK (gimp_item_factory_item_realize),
			      item_factory);

327 328 329 330 331 332 333 334 335 336
      if (entry->help_page)
        {
          if (static_entry)
            g_object_set_data (G_OBJECT (menu_item), "help_page",
                               (gpointer) entry->help_page);
          else
            g_object_set_data_full (G_OBJECT (menu_item), "help_page",
                                    g_strdup (entry->help_page),
                                    g_free);
        }
337
    }
338
}
339

340
void
341
gimp_item_factory_create_items (GimpItemFactory      *item_factory,
342 343 344 345 346 347 348 349 350 351
                                guint                 n_entries,
                                GimpItemFactoryEntry *entries,
                                gpointer              callback_data,
                                guint                 callback_type,
                                gboolean              create_tearoff,
                                gboolean              static_entries)
{
  gint i;

  for (i = 0; i < n_entries; i++)
352
    {
353 354
      gimp_item_factory_create_item (item_factory,
                                     entries + i,
355
                                     NULL,
356 357 358 359
                                     callback_data,
                                     callback_type,
                                     create_tearoff,
                                     static_entries);
360
    }
361
}
362

363 364 365 366 367 368 369 370 371 372
void
gimp_item_factory_update (GimpItemFactory *item_factory,
                          gpointer         popup_data)
{
  g_return_if_fail (GIMP_IS_ITEM_FACTORY (item_factory));

  if (item_factory->update_func)
    item_factory->update_func (GTK_ITEM_FACTORY (item_factory), popup_data);
}

373 374 375 376 377 378 379 380 381 382 383
void
gimp_item_factory_popup_with_data (GimpItemFactory  *item_factory,
				   gpointer          data,
                                   GtkDestroyNotify  popdown_func)
{
  gint    x, y;
  guint   button;
  guint32 activate_time;

  g_return_if_fail (GIMP_IS_ITEM_FACTORY (item_factory));

384 385
  if (item_factory->update_on_popup)
    gimp_item_factory_update (item_factory, data);
386 387 388 389 390 391 392 393 394 395 396 397 398 399

  gimp_menu_position (GTK_MENU (GTK_ITEM_FACTORY (item_factory)->widget),
		      &x, &y,
		      &button,
		      &activate_time);

  gtk_item_factory_popup_with_data (GTK_ITEM_FACTORY (item_factory),
				    data,
				    popdown_func,
				    x, y,
				    button,
				    activate_time);
}

400 401
void
gimp_item_factory_set_active (GtkItemFactory *factory,
402
                              const gchar    *path,
403 404 405 406 407 408 409 410 411 412
                              gboolean        active)
{
  GtkWidget *widget;

  g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));
  g_return_if_fail (path != NULL);

  widget = gtk_item_factory_get_widget (factory, path);

  if (widget)
413
    {
414 415 416 417 418 419
      if (GTK_IS_CHECK_MENU_ITEM (widget))
        {
          gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), active);
        }
      else
        {
420 421 422 423 424
          g_warning ("%s: Unable to set \"active\" for menu item "
                     "of type \"%s\": %s",
                     G_STRLOC,
                     g_type_name (G_TYPE_FROM_INSTANCE (widget)),
                     path);
425
        }
426
    }
427
  else if (! strstr (path, "Script-Fu"))
428
    {
429
      g_warning ("%s: Unable to set \"active\" for menu item "
430
                 "which doesn't exist: %s",
431
                 G_STRLOC, path);
432
    }
433 434
}

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
void
gimp_item_factories_set_active (const gchar *factory_path,
                                const gchar *path,
                                gboolean     active)
{
  GList *list;

  g_return_if_fail (factory_path != NULL);
  g_return_if_fail (path != NULL);

  for (list = gimp_item_factories_from_path (factory_path);
       list;
       list = g_list_next (list))
    {
      gimp_item_factory_set_active (GTK_ITEM_FACTORY (list->data),
                                    path, active);
    }
}

454
void
455
gimp_item_factory_set_color (GtkItemFactory *factory,
456
                             const gchar    *path,
457 458
                             const GimpRGB  *color,
                             gboolean        set_label)
459
{
460
  GtkWidget *widget;
461 462
  GtkWidget *area  = NULL;
  GtkWidget *label = NULL;
463

464 465 466
  g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));
  g_return_if_fail (path != NULL);
  g_return_if_fail (color != NULL);
467

468
  widget = gtk_item_factory_get_widget (factory, path);
469

470
  if (! widget)
471
    {
472
      g_warning ("%s: Unable to set color of menu item "
473
                 "which doesn't exist: %s",
474 475 476
                 G_STRLOC, path);
      return;
    }
477

478 479
  if (GTK_IS_HBOX (GTK_BIN (widget)->child))
    {
480 481
      area = g_object_get_data (G_OBJECT (GTK_BIN (widget)->child),
                                "color_area");
482 483
      label = g_object_get_data (G_OBJECT (GTK_BIN (widget)->child),
                                 "label");
484
    }
485
  else if (GTK_IS_LABEL (GTK_BIN (widget)->child))
486
    {
487
      GtkWidget *hbox;
488

489
      label = GTK_BIN (widget)->child;
490

491
      g_object_ref (label);
492

493
      gtk_container_remove (GTK_CONTAINER (widget), label);
494

495 496 497 498
      hbox = gtk_hbox_new (FALSE, 4);
      gtk_container_add (GTK_CONTAINER (widget), hbox);
      gtk_widget_show (hbox);

499 500 501 502 503 504
      area = gimp_color_area_new (color, GIMP_COLOR_AREA_FLAT, 0);
      gimp_color_area_set_draw_border (GIMP_COLOR_AREA (area), TRUE);

      gtk_widget_set_size_request (area, COLOR_BOX_WIDTH, COLOR_BOX_HEIGHT);
      gtk_box_pack_start (GTK_BOX (hbox), area, FALSE, FALSE, 0);
      gtk_widget_show (area);
505

506
      gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
507 508
      gtk_widget_show (label);

509
      g_object_unref (label);
510

511 512
      g_object_set_data (G_OBJECT (hbox), "color_area", area);
      g_object_set_data (G_OBJECT (hbox), "label",      label);
513 514
    }

515 516
  if (area)
    gimp_color_area_set_color (GIMP_COLOR_AREA (area), color);
517

518
  if (label && set_label)
519
    {
520 521 522 523
      gchar *str;

      str = g_strdup_printf (_("RGBA (%0.3f, %0.3f, %0.3f, %0.3f)"),
                             color->r, color->g, color->b, color->a);
524

525 526 527
      gtk_label_set_text (GTK_LABEL (label), str);

      g_free (str);
528
    }
529 530
}

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
void
gimp_item_factories_set_color (const gchar   *factory_path,
                               const gchar   *path,
                               const GimpRGB *color,
                               gboolean       set_label)
{
  GList *list;

  g_return_if_fail (factory_path != NULL);
  g_return_if_fail (path != NULL);
  g_return_if_fail (color != NULL);

  for (list = gimp_item_factories_from_path (factory_path);
       list;
       list = g_list_next (list))
    {
      gimp_item_factory_set_color (GTK_ITEM_FACTORY (list->data),
                                   path, color, set_label);
    }
}

552 553
void
gimp_item_factory_set_label (GtkItemFactory *factory,
554
                             const gchar    *path,
555 556 557 558 559 560 561 562 563 564 565
                             const gchar    *label)
{
  GtkWidget *widget;

  g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));
  g_return_if_fail (path != NULL);
  g_return_if_fail (label != NULL);

  widget = gtk_item_factory_get_widget (factory, path);

  if (widget)
566
    {
567
      if (GTK_IS_MENU (widget))
568
        widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
569

570
      if (GTK_IS_LABEL (GTK_BIN (widget)->child))
571 572
        gtk_label_set_text_with_mnemonic (GTK_LABEL (GTK_BIN (widget)->child),
                                          label);
573
    }
574
  else
575
    {
576
      g_warning ("%s: Unable to set label of menu item "
577
                 "which doesn't exist: %s",
578 579 580
                 G_STRLOC, path);
    }
}
581

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
void
gimp_item_factories_set_label (const gchar *factory_path,
                               const gchar *path,
                               const gchar *label)
{
  GList *list;

  g_return_if_fail (factory_path != NULL);
  g_return_if_fail (path != NULL);
  g_return_if_fail (label != NULL);

  for (list = gimp_item_factories_from_path (factory_path);
       list;
       list = g_list_next (list))
    {
      gimp_item_factory_set_label (GTK_ITEM_FACTORY (list->data),
                                   path, label);
    }
}

602 603
void
gimp_item_factory_set_sensitive (GtkItemFactory *factory,
604
                                 const gchar    *path,
605 606 607
                                 gboolean        sensitive)
{
  GtkWidget *widget;
608

609 610
  g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));
  g_return_if_fail (path != NULL);
611

612 613 614 615 616 617 618 619
  widget = gtk_item_factory_get_widget (factory, path);

  if (widget)
    {
      gtk_widget_set_sensitive (widget, sensitive);
    }
  else if (! strstr (path, "Script-Fu"))
    {
620
      g_warning ("%s: Unable to set sensitivity of menu item "
621
                 "which doesn't exist: %s",
622
                 G_STRLOC, path);
623
    }
624
}
625

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
void
gimp_item_factories_set_sensitive (const gchar *factory_path,
                                   const gchar *path,
                                   gboolean     sensitive)
{
  GList *list;

  g_return_if_fail (factory_path != NULL);
  g_return_if_fail (path != NULL);

  for (list = gimp_item_factories_from_path (factory_path);
       list;
       list = g_list_next (list))
    {
      gimp_item_factory_set_sensitive (GTK_ITEM_FACTORY (list->data),
                                       path, sensitive);
    }
}

645 646
void
gimp_item_factory_set_visible (GtkItemFactory *factory,
647
                               const gchar    *path,
648 649 650 651 652 653 654 655
                               gboolean        visible)
{
  GtkWidget *widget;

  g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));
  g_return_if_fail (path != NULL);

  widget = gtk_item_factory_get_widget (factory, path);
656

657
  if (widget)
658
    {
659 660 661
      if (GTK_IS_MENU (widget))
        widget = gtk_menu_get_attach_widget (GTK_MENU (widget));

662 663 664 665 666 667 668
      if (visible)
        gtk_widget_show (widget);
      else
        gtk_widget_hide (widget);
    }
  else
    {
669
      g_warning ("%s: Unable to set visibility of menu item "
670 671 672 673 674
                 "which doesn't exist: %s",
                 G_STRLOC, path);
    }
}

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
void
gimp_item_factories_set_visible (const gchar *factory_path,
                                 const gchar *path,
                                 gboolean     visible)
{
  GList *list;

  g_return_if_fail (factory_path != NULL);
  g_return_if_fail (path != NULL);

  for (list = gimp_item_factories_from_path (factory_path);
       list;
       list = g_list_next (list))
    {
      gimp_item_factory_set_visible (GTK_ITEM_FACTORY (list->data),
                                     path, visible);
    }
}

694 695 696 697 698 699 700 701 702 703
void
gimp_item_factory_tearoff_callback (GtkWidget *widget,
                                    gpointer   data,
                                    guint      action)
{
  if (GTK_IS_TEAROFF_MENU_ITEM (widget))
    {
      GtkTearoffMenuItem *tomi = (GtkTearoffMenuItem *) widget;

      if (tomi->torn_off)
704
	{
705 706 707
	  GtkWidget *toplevel;

	  toplevel = gtk_widget_get_toplevel (widget);
708

709
	  if (! GTK_IS_WINDOW (toplevel))
710
	    {
711 712 713 714 715 716 717 718 719 720
	      g_warning ("%s: tearoff menu not in top level window",
                         G_STRLOC);
	    }
	  else
	    {
#ifdef __GNUC__
#warning FIXME: register tearoffs
#endif
	      g_object_set_data (G_OBJECT (widget), "tearoff-menu-toplevel",
                                 toplevel);
721
	    }
722 723 724 725
	}
      else
	{
	  GtkWidget *toplevel;
726

727 728
	  toplevel = (GtkWidget *) g_object_get_data (G_OBJECT (widget),
                                                      "tearoff-menu-toplevel");
729

730 731 732 733 734 735 736 737 738 739
	  if (! toplevel)
	    {
	      g_warning ("%s: can't unregister tearoff menu top level window",
                         G_STRLOC);
	    }
	  else
	    {
#ifdef __GNUC__
#warning FIXME: unregister tearoffs
#endif
740 741 742 743 744 745
	    }
	}
    }
}


746
/*  private functions  */
747

748
static void
749
gimp_item_factory_create_branches (GimpItemFactory      *factory,
750 751
                                   GimpItemFactoryEntry *entry,
                                   const gchar          *textdomain)
752
{
753 754 755 756 757 758
  GString *tearoff_path;
  gint     factory_length;
  gchar   *p;

  if (! entry->entry.path)
    return;
759

760
  tearoff_path = g_string_new ("");
761

Sven Neumann's avatar
Sven Neumann committed
762
  p = strchr (entry->entry.path, '/');
763
  factory_length = p - entry->entry.path;
764 765 766 767 768 769

  /*  skip the first slash  */
  if (p)
    p = strchr (p + 1, '/');

  while (p)
770
    {
771 772
      g_string_assign (tearoff_path, entry->entry.path + factory_length);
      g_string_truncate (tearoff_path, p - entry->entry.path - factory_length);
773

774 775
      if (! gtk_item_factory_get_widget (GTK_ITEM_FACTORY (factory),
                                         tearoff_path->str))
776
	{
777 778
	  GimpItemFactoryEntry branch_entry =
	  {
779
	    { tearoff_path->str, NULL, NULL, 0, "<Branch>" },
780 781 782 783
	    NULL,
	    NULL
	  };

784
	  g_object_set_data (G_OBJECT (factory), "complete", entry->entry.path);
785 786 787

	  gimp_item_factory_create_item (factory,
                                         &branch_entry,
788
                                         textdomain,
789 790 791
                                         NULL, 2, TRUE, FALSE);

	  g_object_set_data (G_OBJECT (factory), "complete", NULL);
792
	}
793

794
      g_string_append (tearoff_path, "/tearoff");
795

796 797
      if (! gtk_item_factory_get_widget (GTK_ITEM_FACTORY (factory),
                                         tearoff_path->str))
798
	{
799 800
	  GimpItemFactoryEntry tearoff_entry =
	  {
801 802
	    { tearoff_path->str, NULL,
              gimp_item_factory_tearoff_callback, 0, "<Tearoff>" },
803 804 805 806 807 808
	    NULL,
	    NULL, NULL
	  };

	  gimp_item_factory_create_item (factory,
                                         &tearoff_entry,
809
                                         textdomain,
810
                                         NULL, 2, TRUE, FALSE);
811
	}
812 813

      p = strchr (p + 1, '/');
814
    }
815

816 817 818 819 820 821 822 823
  g_string_free (tearoff_path, TRUE);
}

static void
gimp_item_factory_item_realize (GtkWidget *widget,
                                gpointer   data)
{
  if (GTK_IS_MENU_SHELL (widget->parent))
824
    {
825 826 827 828 829 830 831 832
      static GQuark quark_key_press_connected = 0;

      if (! quark_key_press_connected)
        quark_key_press_connected =
          g_quark_from_static_string ("gimp-menu-item-key-press-connected");

      if (! GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (widget->parent),
                                                 quark_key_press_connected)))
833
	{
834
	  g_signal_connect (widget->parent, "key_press_event",
835 836
                            G_CALLBACK (gimp_item_factory_item_key_press),
                            data);
837

838 839 840
	  g_object_set_qdata (G_OBJECT (widget->parent),
                              quark_key_press_connected,
                              GINT_TO_POINTER (TRUE));
841
	}
842
    }
843 844
}

845 846 847 848
static gboolean
gimp_item_factory_item_key_press (GtkWidget   *widget,
                                  GdkEventKey *kevent,
                                  gpointer     data)
849
{
850 851 852 853 854
  GtkItemFactory *item_factory      = NULL;
  GtkWidget      *active_menu_item  = NULL;
  gchar          *factory_help_path = NULL;
  gchar          *help_path         = NULL;
  gchar          *help_page         = NULL;
855

856 857
  item_factory     = (GtkItemFactory *) data;
  active_menu_item = GTK_MENU_SHELL (widget)->active_menu_item;
858

859 860 861 862 863 864
  /*  first, get the help page from the item
   */
  if (active_menu_item)
    {
      help_page = (gchar *) g_object_get_data (G_OBJECT (active_menu_item),
                                               "help_page");
865 866 867

      if (help_page && ! *help_page)
        help_page = NULL;
868
    }
869

870 871 872
  /*  For any valid accelerator key except F1, continue with the
   *  standard GtkItemFactory callback and assign a new shortcut, but
   *  don't assign a shortcut to the help menu entries ...
873 874 875 876
   */
  if (kevent->keyval != GDK_F1)
    {
      if (help_page &&
877
          gtk_accelerator_valid (kevent->keyval, 0) &&
878 879
	  (item_factory ==
           (GtkItemFactory *) gimp_item_factory_from_path ("<Toolbox>")) &&
880 881 882 883 884 885 886 887 888 889
	  (strcmp (help_page, "help/dialogs/help.html") == 0 ||
	   strcmp (help_page, "help/context_help.html") == 0))
	{
	  return TRUE;
	}
      else
	{
	  return FALSE;
	}
    }
890

891
  /*  ...finally, if F1 was pressed over any menu, show it's help page...  */
892

893 894
  factory_help_path = (gchar *) g_object_get_data (G_OBJECT (item_factory),
                                                   "help_path");
895

896
  if (! help_page)
897
    help_page = "index.html";
Sven Neumann's avatar
Sven Neumann committed
898

899
  if (factory_help_path && help_page)
Michael Natterer's avatar
Michael Natterer committed
900
    {
901 902
      gchar *help_string;
      gchar *at;
903