~ubuntu-branches/ubuntu/utopic/inkscape/utopic-proposed

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/ige-mac-menu.c

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GTK+ Integration for the Mac OS X Menubar.
 
2
 *
 
3
 * Copyright (C) 2007 Pioneer Research Center USA, Inc.
 
4
 *
 
5
 * For further information, see:
 
6
 * http://developer.imendio.com/projects/gtk-macosx/menubar
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library; if not, write to the
 
20
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
21
 * Boston, MA 02111-1307, USA.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
# include "config.h"
 
26
#endif
 
27
 
 
28
#include <gtk/gtk.h>
 
29
 
 
30
#ifdef GDK_WINDOWING_QUARTZ
 
31
 
 
32
#include <gdk/gdkkeysyms.h>
 
33
 
 
34
#include <Carbon/Carbon.h>
 
35
 
 
36
#include "ige-mac-menu.h"
 
37
 
 
38
 
 
39
/* TODO
 
40
 *
 
41
 * - Sync adding/removing/reordering items
 
42
 * - Create on demand? (can this be done with gtk+? ie fill in menu
 
43
     items when the menu is opened)
 
44
 * - Figure out what to do per app/window...
 
45
 *
 
46
 */
 
47
 
 
48
#define IGE_QUARTZ_MENU_CREATOR 'IGEC'
 
49
#define IGE_QUARTZ_ITEM_WIDGET  'IWID'
 
50
 
 
51
 
 
52
static void   sync_menu_shell (GtkMenuShell *menu_shell,
 
53
                               MenuRef       carbon_menu,
 
54
                               gboolean      toplevel,
 
55
                               gboolean      debug);
 
56
 
 
57
 
 
58
/*
 
59
 * utility functions
 
60
 */
 
61
 
 
62
static GtkWidget *
 
63
find_menu_label (GtkWidget *widget)
 
64
{
 
65
  GtkWidget *label = NULL;
 
66
 
 
67
  if (GTK_IS_LABEL (widget))
 
68
    return widget;
 
69
 
 
70
  if (GTK_IS_CONTAINER (widget))
 
71
    {
 
72
      GList *children;
 
73
      GList *l;
 
74
 
 
75
      children = gtk_container_get_children (GTK_CONTAINER (widget));
 
76
 
 
77
      for (l = children; l; l = l->next)
 
78
        {
 
79
          label = find_menu_label (l->data);
 
80
          if (label)
 
81
            break;
 
82
        }
 
83
 
 
84
      g_list_free (children);
 
85
    }
 
86
 
 
87
  return label;
 
88
}
 
89
 
 
90
static const gchar *
 
91
get_menu_label_text (GtkWidget  *menu_item,
 
92
                     GtkWidget **label)
 
93
{
 
94
  GtkWidget *my_label;
 
95
 
 
96
  my_label = find_menu_label (menu_item);
 
97
  if (label)
 
98
    *label = my_label;
 
99
 
 
100
  if (my_label)
 
101
    return gtk_label_get_text (GTK_LABEL (my_label));
 
102
 
 
103
  return NULL;
 
104
}
 
105
 
 
106
static gboolean
 
107
accel_find_func (GtkAccelKey *key,
 
108
                 GClosure    *closure,
 
109
                 gpointer     data)
 
110
{
 
111
  return (GClosure *) data == closure;
 
112
}
 
113
 
 
114
 
 
115
/*
 
116
 * CarbonMenu functions
 
117
 */
 
118
 
 
119
typedef struct
 
120
{
 
121
  MenuRef menu;
 
122
} CarbonMenu;
 
123
 
 
124
static GQuark carbon_menu_quark = 0;
 
125
 
 
126
static CarbonMenu *
 
127
carbon_menu_new (void)
 
128
{
 
129
  return g_slice_new0 (CarbonMenu);
 
130
}
 
131
 
 
132
static void
 
133
carbon_menu_free (CarbonMenu *menu)
 
134
{
 
135
  g_slice_free (CarbonMenu, menu);
 
136
}
 
137
 
 
138
static CarbonMenu *
 
139
carbon_menu_get (GtkWidget *widget)
 
140
{
 
141
  return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark);
 
142
}
 
143
 
 
144
static void
 
145
carbon_menu_connect (GtkWidget *menu,
 
146
                     MenuRef    menuRef)
 
147
{
 
148
  CarbonMenu *carbon_menu = carbon_menu_get (menu);
 
149
 
 
150
  if (!carbon_menu)
 
151
    {
 
152
      carbon_menu = carbon_menu_new ();
 
153
 
 
154
      g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark,
 
155
                               carbon_menu,
 
156
                               (GDestroyNotify) carbon_menu_free);
 
157
    }
 
158
 
 
159
  carbon_menu->menu = menuRef;
 
160
}
 
161
 
 
162
 
 
163
/*
 
164
 * CarbonMenuItem functions
 
165
 */
 
166
 
 
167
typedef struct
 
168
{
 
169
  MenuRef        menu;
 
170
  MenuItemIndex  index;
 
171
  MenuRef        submenu;
 
172
  GClosure      *accel_closure;
 
173
} CarbonMenuItem;
 
174
 
 
175
static GQuark carbon_menu_item_quark = 0;
 
176
 
 
177
static CarbonMenuItem *
 
178
carbon_menu_item_new (void)
 
179
{
 
180
  return g_slice_new0 (CarbonMenuItem);
 
181
}
 
182
 
 
183
static void
 
184
carbon_menu_item_free (CarbonMenuItem *menu_item)
 
185
{
 
186
  if (menu_item->accel_closure)
 
187
    g_closure_unref (menu_item->accel_closure);
 
188
 
 
189
  g_slice_free (CarbonMenuItem, menu_item);
 
190
}
 
191
 
 
192
static CarbonMenuItem *
 
193
carbon_menu_item_get (GtkWidget *widget)
 
194
{
 
195
  return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark);
 
196
}
 
197
 
 
198
static void
 
199
carbon_menu_item_update_state (CarbonMenuItem *carbon_item,
 
200
                               GtkWidget      *widget)
 
201
{
 
202
  gboolean sensitive;
 
203
  gboolean visible;
 
204
  UInt32   set_attrs = 0;
 
205
  UInt32   clear_attrs = 0;
 
206
 
 
207
  g_object_get (widget,
 
208
                "sensitive", &sensitive,
 
209
                "visible",   &visible,
 
210
                NULL);
 
211
 
 
212
  if (!sensitive)
 
213
    set_attrs |= kMenuItemAttrDisabled;
 
214
  else
 
215
    clear_attrs |= kMenuItemAttrDisabled;
 
216
 
 
217
  if (!visible)
 
218
    set_attrs |= kMenuItemAttrHidden;
 
219
  else
 
220
    clear_attrs |= kMenuItemAttrHidden;
 
221
 
 
222
  ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
 
223
                            set_attrs, clear_attrs);
 
224
}
 
225
 
 
226
static void
 
227
carbon_menu_item_update_active (CarbonMenuItem *carbon_item,
 
228
                                GtkWidget      *widget)
 
229
{
 
230
  gboolean active;
 
231
 
 
232
  g_object_get (widget,
 
233
                "active", &active,
 
234
                NULL);
 
235
 
 
236
  CheckMenuItem (carbon_item->menu, carbon_item->index,
 
237
                 active);
 
238
}
 
239
 
 
240
static void
 
241
carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item,
 
242
                                 GtkWidget      *widget)
 
243
{
 
244
  GtkWidget *submenu;
 
245
 
 
246
  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
 
247
 
 
248
  if (submenu)
 
249
    {
 
250
      const gchar *label_text;
 
251
      CFStringRef  cfstr = NULL;
 
252
 
 
253
      label_text = get_menu_label_text (widget, NULL);
 
254
      if (label_text)
 
255
        cfstr = CFStringCreateWithCString (NULL, label_text,
 
256
                                           kCFStringEncodingUTF8);
 
257
 
 
258
      CreateNewMenu (0, 0, &carbon_item->submenu);
 
259
      SetMenuTitleWithCFString (carbon_item->submenu, cfstr);
 
260
      SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
 
261
                                   carbon_item->submenu);
 
262
 
 
263
      sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE, FALSE);
 
264
 
 
265
      if (cfstr)
 
266
        CFRelease (cfstr);
 
267
    }
 
268
  else
 
269
    {
 
270
      SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
 
271
                                   NULL);
 
272
      carbon_item->submenu = NULL;
 
273
    }
 
274
}
 
275
 
 
276
static void
 
277
carbon_menu_item_update_label (CarbonMenuItem *carbon_item,
 
278
                               GtkWidget      *widget)
 
279
{
 
280
  const gchar *label_text;
 
281
  CFStringRef  cfstr = NULL;
 
282
 
 
283
  label_text = get_menu_label_text (widget, NULL);
 
284
  if (label_text)
 
285
    cfstr = CFStringCreateWithCString (NULL, label_text,
 
286
                                       kCFStringEncodingUTF8);
 
287
 
 
288
  SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index,
 
289
                               cfstr);
 
290
 
 
291
  if (cfstr)
 
292
    CFRelease (cfstr);
 
293
}
 
294
 
 
295
static void
 
296
carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item,
 
297
                                     GtkWidget      *widget)
 
298
{
 
299
  GtkWidget *label;
 
300
 
 
301
  get_menu_label_text (widget, &label);
 
302
 
 
303
  if (GTK_IS_ACCEL_LABEL (label) &&
 
304
      GTK_ACCEL_LABEL (label)->accel_closure)
 
305
    {
 
306
      GtkAccelKey *key;
 
307
 
 
308
      key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
 
309
                                  accel_find_func,
 
310
                                  GTK_ACCEL_LABEL (label)->accel_closure);
 
311
 
 
312
      if (key            &&
 
313
          key->accel_key &&
 
314
          key->accel_flags & GTK_ACCEL_VISIBLE)
 
315
        {
 
316
          GdkDisplay      *display = gtk_widget_get_display (widget);
 
317
          GdkKeymap       *keymap  = gdk_keymap_get_for_display (display);
 
318
          GdkKeymapKey    *keys;
 
319
          gint             n_keys;
 
320
 
 
321
          if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key,
 
322
                                                 &keys, &n_keys))
 
323
            {
 
324
              UInt8 modifiers = 0;
 
325
 
 
326
              SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
 
327
                                     true, keys[0].keycode);
 
328
 
 
329
              g_free (keys);
 
330
 
 
331
              if (key->accel_mods)
 
332
                {
 
333
                  if (key->accel_mods & GDK_SHIFT_MASK)
 
334
                    modifiers |= kMenuShiftModifier;
 
335
 
 
336
                  if (key->accel_mods & GDK_MOD1_MASK)
 
337
                    modifiers |= kMenuOptionModifier;
 
338
                }
 
339
 
 
340
              if (!(key->accel_mods & GDK_CONTROL_MASK))
 
341
                {
 
342
                  modifiers |= kMenuNoCommandModifier;
 
343
                }
 
344
 
 
345
              SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
 
346
                                    modifiers);
 
347
 
 
348
              return;
 
349
            }
 
350
        }
 
351
    }
 
352
 
 
353
  /*  otherwise, clear the menu shortcut  */
 
354
  SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
 
355
                        kMenuNoModifiers | kMenuNoCommandModifier);
 
356
  ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
 
357
                            0, kMenuItemAttrUseVirtualKey);
 
358
  SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
 
359
                         false, 0);
 
360
}
 
361
 
 
362
static void
 
363
carbon_menu_item_accel_changed (GtkAccelGroup   *accel_group,
 
364
                                guint            keyval,
 
365
                                GdkModifierType  modifier,
 
366
                                GClosure        *accel_closure,
 
367
                                GtkWidget       *widget)
 
368
{
 
369
  CarbonMenuItem *carbon_item = carbon_menu_item_get (widget);
 
370
  GtkWidget      *label;
 
371
 
 
372
  get_menu_label_text (widget, &label);
 
373
 
 
374
  if (GTK_IS_ACCEL_LABEL (label) &&
 
375
      GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
 
376
    carbon_menu_item_update_accelerator (carbon_item, widget);
 
377
}
 
378
 
 
379
static void
 
380
carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item,
 
381
                                       GtkWidget      *widget)
 
382
{
 
383
  GtkAccelGroup *group;
 
384
  GtkWidget     *label;
 
385
 
 
386
  get_menu_label_text (widget, &label);
 
387
 
 
388
  if (carbon_item->accel_closure)
 
389
    {
 
390
      group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
 
391
 
 
392
      g_signal_handlers_disconnect_by_func (group,
 
393
                                            carbon_menu_item_accel_changed,
 
394
                                            widget);
 
395
 
 
396
      g_closure_unref (carbon_item->accel_closure);
 
397
      carbon_item->accel_closure = NULL;
 
398
    }
 
399
 
 
400
  if (GTK_IS_ACCEL_LABEL (label))
 
401
    carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
 
402
 
 
403
  if (carbon_item->accel_closure)
 
404
    {
 
405
      g_closure_ref (carbon_item->accel_closure);
 
406
 
 
407
      group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
 
408
 
 
409
      g_signal_connect_object (group, "accel-changed",
 
410
                               G_CALLBACK (carbon_menu_item_accel_changed),
 
411
                               widget, 0);
 
412
    }
 
413
 
 
414
  carbon_menu_item_update_accelerator (carbon_item, widget);
 
415
}
 
416
 
 
417
static void
 
418
carbon_menu_item_notify (GObject        *object,
 
419
                         GParamSpec     *pspec,
 
420
                         CarbonMenuItem *carbon_item)
 
421
{
 
422
  if (!strcmp (pspec->name, "sensitive") ||
 
423
      !strcmp (pspec->name, "visible"))
 
424
    {
 
425
      carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object));
 
426
    }
 
427
  else if (!strcmp (pspec->name, "active"))
 
428
    {
 
429
      carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object));
 
430
    }
 
431
  else if (!strcmp (pspec->name, "submenu"))
 
432
    {
 
433
      carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object));
 
434
    }
 
435
}
 
436
 
 
437
static void
 
438
carbon_menu_item_notify_label (GObject    *object,
 
439
                               GParamSpec *pspec,
 
440
                               gpointer    data)
 
441
{
 
442
  CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object));
 
443
 
 
444
  if (!strcmp (pspec->name, "label"))
 
445
    {
 
446
      carbon_menu_item_update_label (carbon_item,
 
447
                                     GTK_WIDGET (object));
 
448
    }
 
449
  else if (!strcmp (pspec->name, "accel-closure"))
 
450
    {
 
451
      carbon_menu_item_update_accel_closure (carbon_item,
 
452
                                             GTK_WIDGET (object));
 
453
    }
 
454
}
 
455
 
 
456
static CarbonMenuItem *
 
457
carbon_menu_item_connect (GtkWidget     *menu_item,
 
458
                          GtkWidget     *label,
 
459
                          MenuRef        menu,
 
460
                          MenuItemIndex  index)
 
461
{
 
462
  CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item);
 
463
 
 
464
  if (!carbon_item)
 
465
    {
 
466
      carbon_item = carbon_menu_item_new ();
 
467
 
 
468
      g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark,
 
469
                               carbon_item,
 
470
                               (GDestroyNotify) carbon_menu_item_free);
 
471
 
 
472
      g_signal_connect (menu_item, "notify",
 
473
                        G_CALLBACK (carbon_menu_item_notify),
 
474
                        carbon_item);
 
475
 
 
476
      if (label)
 
477
        g_signal_connect_swapped (label, "notify::label",
 
478
                                  G_CALLBACK (carbon_menu_item_notify_label),
 
479
                                  menu_item);
 
480
    }
 
481
 
 
482
  carbon_item->menu  = menu;
 
483
  carbon_item->index = index;
 
484
 
 
485
  return carbon_item;
 
486
}
 
487
 
 
488
 
 
489
/*
 
490
 * carbon event handler
 
491
 */
 
492
 
 
493
static OSStatus
 
494
menu_event_handler_func (EventHandlerCallRef  event_handler_call_ref,
 
495
                         EventRef             event_ref,
 
496
                         void                *data)
 
497
{
 
498
  UInt32  event_class = GetEventClass (event_ref);
 
499
  UInt32  event_kind = GetEventKind (event_ref);
 
500
  MenuRef menu_ref;
 
501
 
 
502
  switch (event_class)
 
503
    {
 
504
    case kEventClassCommand:
 
505
      /* This is called when activating (is that the right GTK+ term?)
 
506
       * a menu item.
 
507
       */
 
508
      if (event_kind == kEventCommandProcess)
 
509
        {
 
510
          HICommand command;
 
511
          OSStatus  err;
 
512
 
 
513
          /*g_printerr ("Menu: kEventClassCommand/kEventCommandProcess\n");*/
 
514
 
 
515
          err = GetEventParameter (event_ref, kEventParamDirectObject,
 
516
                                   typeHICommand, 0,
 
517
                                   sizeof (command), 0, &command);
 
518
 
 
519
          if (err == noErr)
 
520
            {
 
521
              GtkWidget *widget = NULL;
 
522
 
 
523
              /* Get any GtkWidget associated with the item. */
 
524
              err = GetMenuItemProperty (command.menu.menuRef,
 
525
                                         command.menu.menuItemIndex,
 
526
                                         IGE_QUARTZ_MENU_CREATOR,
 
527
                                         IGE_QUARTZ_ITEM_WIDGET,
 
528
                                         sizeof (widget), 0, &widget);
 
529
              if (err == noErr && GTK_IS_WIDGET (widget))
 
530
                {
 
531
                  gtk_menu_item_activate (GTK_MENU_ITEM (widget));
 
532
                  return noErr;
 
533
                }
 
534
            }
 
535
        }
 
536
      break;
 
537
 
 
538
    case kEventClassMenu:
 
539
      GetEventParameter (event_ref,
 
540
                         kEventParamDirectObject,
 
541
                         typeMenuRef,
 
542
                         NULL,
 
543
                         sizeof (menu_ref),
 
544
                         NULL,
 
545
                         &menu_ref);
 
546
 
 
547
      switch (event_kind)
 
548
        {
 
549
        case kEventMenuTargetItem:
 
550
          /* This is called when an item is selected (what is the
 
551
           * GTK+ term? prelight?)
 
552
           */
 
553
          /*g_printerr ("kEventClassMenu/kEventMenuTargetItem\n");*/
 
554
          break;
 
555
 
 
556
        case kEventMenuOpening:
 
557
          /* Is it possible to dynamically build the menu here? We
 
558
           * can at least set visibility/sensitivity.
 
559
           */
 
560
          /*g_printerr ("kEventClassMenu/kEventMenuOpening\n");*/
 
561
          break;
 
562
 
 
563
        case kEventMenuClosed:
 
564
          /*g_printerr ("kEventClassMenu/kEventMenuClosed\n");*/
 
565
          break;
 
566
 
 
567
        default:
 
568
          break;
 
569
        }
 
570
 
 
571
      break;
 
572
 
 
573
    default:
 
574
      break;
 
575
    }
 
576
 
 
577
  return CallNextEventHandler (event_handler_call_ref, event_ref);
 
578
}
 
579
 
 
580
static void
 
581
setup_menu_event_handler (void)
 
582
{
 
583
  EventHandlerUPP menu_event_handler_upp;
 
584
  EventHandlerRef menu_event_handler_ref;
 
585
  const EventTypeSpec menu_events[] = {
 
586
    { kEventClassCommand, kEventCommandProcess },
 
587
    { kEventClassMenu, kEventMenuTargetItem },
 
588
    { kEventClassMenu, kEventMenuOpening },
 
589
    { kEventClassMenu, kEventMenuClosed }
 
590
  };
 
591
 
 
592
  /* FIXME: We might have to install one per window? */
 
593
 
 
594
  menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func);
 
595
  InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp,
 
596
                       GetEventTypeCount (menu_events), menu_events, 0,
 
597
                       &menu_event_handler_ref);
 
598
 
 
599
#if 0
 
600
  /* FIXME: Remove the handler with: */
 
601
  RemoveEventHandler(menu_event_handler_ref);
 
602
  DisposeEventHandlerUPP(menu_event_handler_upp);
 
603
#endif
 
604
}
 
605
 
 
606
static void
 
607
sync_menu_shell (GtkMenuShell *menu_shell,
 
608
                 MenuRef       carbon_menu,
 
609
                 gboolean      toplevel,
 
610
                 gboolean      debug)
 
611
{
 
612
  GList         *children;
 
613
  GList         *l;
 
614
  MenuItemIndex  carbon_index = 1;
 
615
 
 
616
  if (debug)
 
617
    g_printerr ("%s: syncing shell %p\n", G_STRFUNC, menu_shell);
 
618
 
 
619
  carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu);
 
620
 
 
621
  children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
 
622
 
 
623
  for (l = children; l; l = l->next)
 
624
    {
 
625
      GtkWidget      *menu_item = l->data;
 
626
      CarbonMenuItem *carbon_item;
 
627
 
 
628
      if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
 
629
        continue;
 
630
 
 
631
      if (toplevel && g_object_get_data (G_OBJECT (menu_item),
 
632
                                         "gtk-empty-menu-item"))
 
633
        continue;
 
634
 
 
635
      carbon_item = carbon_menu_item_get (menu_item);
 
636
 
 
637
      if (debug)
 
638
        g_printerr ("%s: carbon_item %d for menu_item %d (%s, %s)\n",
 
639
                    G_STRFUNC, carbon_item ? carbon_item->index : -1,
 
640
                    carbon_index, get_menu_label_text (menu_item, NULL),
 
641
                    g_type_name (G_TYPE_FROM_INSTANCE (menu_item)));
 
642
 
 
643
      if (carbon_item && carbon_item->index != carbon_index)
 
644
        {
 
645
          if (debug)
 
646
            g_printerr ("%s:   -> not matching, deleting\n", G_STRFUNC);
 
647
 
 
648
          DeleteMenuItem (carbon_item->menu, carbon_index);
 
649
          carbon_item = NULL;
 
650
        }
 
651
 
 
652
      if (!carbon_item)
 
653
        {
 
654
          GtkWidget          *label      = NULL;
 
655
          const gchar        *label_text;
 
656
          CFStringRef         cfstr      = NULL;
 
657
          MenuItemAttributes  attributes = 0;
 
658
 
 
659
          if (debug)
 
660
            g_printerr ("%s:   -> creating new\n", G_STRFUNC);
 
661
 
 
662
          label_text = get_menu_label_text (menu_item, &label);
 
663
          if (label_text)
 
664
            cfstr = CFStringCreateWithCString (NULL, label_text,
 
665
                                               kCFStringEncodingUTF8);
 
666
 
 
667
          if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
 
668
            attributes |= kMenuItemAttrSeparator;
 
669
 
 
670
          if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
 
671
            attributes |= kMenuItemAttrDisabled;
 
672
 
 
673
          if (!GTK_WIDGET_VISIBLE (menu_item))
 
674
            attributes |= kMenuItemAttrHidden;
 
675
 
 
676
          InsertMenuItemTextWithCFString (carbon_menu, cfstr,
 
677
                                          carbon_index - 1,
 
678
                                          attributes, 0);
 
679
          SetMenuItemProperty (carbon_menu, carbon_index,
 
680
                               IGE_QUARTZ_MENU_CREATOR,
 
681
                               IGE_QUARTZ_ITEM_WIDGET,
 
682
                               sizeof (menu_item), &menu_item);
 
683
 
 
684
          if (cfstr)
 
685
            CFRelease (cfstr);
 
686
 
 
687
          carbon_item = carbon_menu_item_connect (menu_item, label,
 
688
                                                  carbon_menu,
 
689
                                                  carbon_index);
 
690
 
 
691
          if (GTK_IS_CHECK_MENU_ITEM (menu_item))
 
692
            carbon_menu_item_update_active (carbon_item, menu_item);
 
693
 
 
694
          carbon_menu_item_update_accel_closure (carbon_item, menu_item);
 
695
 
 
696
          if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
 
697
            carbon_menu_item_update_submenu (carbon_item, menu_item);
 
698
        }
 
699
 
 
700
      carbon_index++;
 
701
    }
 
702
 
 
703
  g_list_free (children);
 
704
}
 
705
 
 
706
 
 
707
static gulong emission_hook_id = 0;
 
708
 
 
709
static gboolean
 
710
parent_set_emission_hook (GSignalInvocationHint *ihint,
 
711
                          guint                  n_param_values,
 
712
                          const GValue          *param_values,
 
713
                          gpointer               data)
 
714
{
 
715
  GtkWidget *instance = g_value_get_object (param_values);
 
716
 
 
717
  if (GTK_IS_MENU_ITEM (instance))
 
718
    {
 
719
      GtkWidget *previous_parent = g_value_get_object (param_values + 1);
 
720
      GtkWidget *menu_shell      = NULL;
 
721
 
 
722
      if (GTK_IS_MENU_SHELL (previous_parent))
 
723
        {
 
724
          menu_shell = previous_parent;
 
725
        }
 
726
      else if (GTK_IS_MENU_SHELL (instance->parent))
 
727
        {
 
728
          menu_shell = instance->parent;
 
729
        }
 
730
 
 
731
      if (menu_shell)
 
732
        {
 
733
          CarbonMenu *carbon_menu = carbon_menu_get (menu_shell);
 
734
 
 
735
          if (carbon_menu)
 
736
            {
 
737
#if 0
 
738
              g_printerr ("%s: item %s %p (%s, %s)\n", G_STRFUNC,
 
739
                          previous_parent ? "removed from" : "added to",
 
740
                          menu_shell,
 
741
                          get_menu_label_text (instance, NULL),
 
742
                          g_type_name (G_TYPE_FROM_INSTANCE (instance)));
 
743
#endif
 
744
 
 
745
              sync_menu_shell (GTK_MENU_SHELL (menu_shell),
 
746
                               carbon_menu->menu,
 
747
                               carbon_menu->menu == (MenuRef) data,
 
748
                               FALSE);
 
749
            }
 
750
        }
 
751
    }
 
752
 
 
753
  return TRUE;
 
754
}
 
755
 
 
756
static void
 
757
parent_set_emission_hook_remove (GtkWidget *widget,
 
758
                                 gpointer   data)
 
759
{
 
760
  g_signal_remove_emission_hook (g_signal_lookup ("parent-set",
 
761
                                                  GTK_TYPE_WIDGET),
 
762
                                 emission_hook_id);
 
763
}
 
764
 
 
765
 
 
766
/*
 
767
 * public functions
 
768
 */
 
769
 
 
770
void
 
771
ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell)
 
772
{
 
773
  MenuRef carbon_menubar;
 
774
  guint   hook_id;
 
775
 
 
776
  g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
 
777
 
 
778
  if (carbon_menu_quark == 0)
 
779
    carbon_menu_quark = g_quark_from_static_string ("CarbonMenu");
 
780
 
 
781
  if (carbon_menu_item_quark == 0)
 
782
    carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem");
 
783
 
 
784
  CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar);
 
785
  SetRootMenu (carbon_menubar);
 
786
 
 
787
  setup_menu_event_handler ();
 
788
 
 
789
  emission_hook_id =
 
790
    g_signal_add_emission_hook (g_signal_lookup ("parent-set",
 
791
                                                 GTK_TYPE_WIDGET),
 
792
                                0,
 
793
                                parent_set_emission_hook,
 
794
                                carbon_menubar, NULL);
 
795
 
 
796
  g_signal_connect (menu_shell, "destroy",
 
797
                    G_CALLBACK (parent_set_emission_hook_remove),
 
798
                    NULL);
 
799
 
 
800
  sync_menu_shell (menu_shell, carbon_menubar, TRUE, FALSE);
 
801
}
 
802
 
 
803
void
 
804
ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item)
 
805
{
 
806
  MenuRef       appmenu;
 
807
  MenuItemIndex index;
 
808
 
 
809
  g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
 
810
 
 
811
  if (GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
 
812
                                   &appmenu, &index) == noErr)
 
813
    {
 
814
      SetMenuItemCommandID (appmenu, index, 0);
 
815
      SetMenuItemProperty (appmenu, index,
 
816
                           IGE_QUARTZ_MENU_CREATOR,
 
817
                           IGE_QUARTZ_ITEM_WIDGET,
 
818
                           sizeof (menu_item), &menu_item);
 
819
 
 
820
      gtk_widget_hide (GTK_WIDGET (menu_item));
 
821
    }
 
822
}
 
823
 
 
824
 
 
825
struct _IgeMacMenuGroup
 
826
{
 
827
  GList *items;
 
828
};
 
829
 
 
830
static GList *app_menu_groups = NULL;
 
831
 
 
832
IgeMacMenuGroup *
 
833
ige_mac_menu_add_app_menu_group (void)
 
834
{
 
835
  IgeMacMenuGroup *group = g_slice_new0 (IgeMacMenuGroup);
 
836
 
 
837
  app_menu_groups = g_list_append (app_menu_groups, group);
 
838
 
 
839
  return group;
 
840
}
 
841
 
 
842
void
 
843
ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group,
 
844
                                GtkMenuItem     *menu_item,
 
845
                                const gchar     *label)
 
846
{
 
847
  MenuRef  appmenu;
 
848
  GList   *list;
 
849
  gint     index = 0;
 
850
 
 
851
  g_return_if_fail (group != NULL);
 
852
  g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
 
853
 
 
854
  if (GetIndMenuItemWithCommandID (NULL, kHICommandHide, 1,
 
855
                                   &appmenu, NULL) != noErr)
 
856
    {
 
857
      g_warning ("%s: retrieving app menu failed",
 
858
                 G_STRFUNC);
 
859
      return;
 
860
    }
 
861
 
 
862
  for (list = app_menu_groups; list; list = g_list_next (list))
 
863
    {
 
864
      IgeMacMenuGroup *list_group = list->data;
 
865
 
 
866
      index += g_list_length (list_group->items);
 
867
 
 
868
      /*  adjust index for the separator between groups, but not
 
869
       *  before the first group
 
870
       */
 
871
      if (list_group->items && list->prev)
 
872
        index++;
 
873
 
 
874
      if (group == list_group)
 
875
        {
 
876
          CFStringRef cfstr;
 
877
 
 
878
          /*  add a separator before adding the first item, but not
 
879
           *  for the first group
 
880
           */
 
881
          if (!group->items && list->prev)
 
882
            {
 
883
              InsertMenuItemTextWithCFString (appmenu, NULL, index,
 
884
                                              kMenuItemAttrSeparator, 0);
 
885
              index++;
 
886
            }
 
887
 
 
888
          if (!label)
 
889
            label = get_menu_label_text (GTK_WIDGET (menu_item), NULL);
 
890
 
 
891
          cfstr = CFStringCreateWithCString (NULL, label,
 
892
                                             kCFStringEncodingUTF8);
 
893
 
 
894
          InsertMenuItemTextWithCFString (appmenu, cfstr, index, 0, 0);
 
895
          SetMenuItemProperty (appmenu, index + 1,
 
896
                               IGE_QUARTZ_MENU_CREATOR,
 
897
                               IGE_QUARTZ_ITEM_WIDGET,
 
898
                               sizeof (menu_item), &menu_item);
 
899
 
 
900
          CFRelease (cfstr);
 
901
 
 
902
          gtk_widget_hide (GTK_WIDGET (menu_item));
 
903
 
 
904
          group->items = g_list_append (group->items, menu_item);
 
905
 
 
906
          return;
 
907
        }
 
908
    }
 
909
 
 
910
  if (!list)
 
911
    g_warning ("%s: app menu group %p does not exist",
 
912
               G_STRFUNC, group);
 
913
}
 
914
 
 
915
#endif /* GDK_WINDOWING_QUARTZ */